diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3f7911188413..dc4010d0fd0c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -45,6 +45,10 @@ crates/test_utils/tests/connectors/ @juspay/hyperswitch-connector crates/test_utils/tests/sample_auth.toml @juspay/hyperswitch-connector crates/connector_configs/ @juspay/hyperswitch-connector crates/hyperswitch_connectors/ @juspay/hyperswitch-connector +crates/api_models/src/connector_enums.rs @juspay/hyperswitch-connector +crates/common_enums/src/connector_enums.rs @juspay/hyperswitch-connector +crates/router/src/configs/defaults/payment_connector_required_fields.rs @juspay/hyperswitch-connector +crates/hyperswitch_interfaces/src/configs.rs @juspay/hyperswitch-connector crates/router/src/compatibility/ @juspay/hyperswitch-compatibility diff --git a/.github/workflows/CI-pr.yml b/.github/workflows/CI-pr.yml index 220c4f2577c2..369da734da5a 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/.github/workflows/cypress-tests-runner.yml b/.github/workflows/cypress-tests-runner.yml index a878a9db8e46..055aacdcf4f2 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" @@ -158,7 +159,7 @@ jobs: - name: Build project if: ${{ env.RUN_TESTS == 'true' }} - run: cargo build --package router --bin router --jobs 4 + run: cargo build --package router --bin router --jobs 3 - name: Setup Local Server if: ${{ env.RUN_TESTS == 'true' }} @@ -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/.gitignore b/.gitignore index 1aa3faf2c1d1..1209263db3c8 100644 --- a/.gitignore +++ b/.gitignore @@ -263,4 +263,9 @@ result* node_modules/ # cypress credentials -creds.json \ No newline at end of file +creds.json + +/.direnv + +# Nix services data +/data \ No newline at end of file diff --git a/.typos.toml b/.typos.toml index 79c86a39c6b5..d2ffb8a5b105 100644 --- a/.typos.toml +++ b/.typos.toml @@ -1,5 +1,8 @@ [default] check-filename = true +extend-ignore-identifiers-re = [ + "UE_[0-9]{3,4}", # Unified error codes +] [default.extend-identifiers] ABD = "ABD" # Aberdeenshire, UK ISO 3166-2 code @@ -38,7 +41,6 @@ ws2ipdef = "ws2ipdef" # WinSock Extension ws2tcpip = "ws2tcpip" # WinSock Extension ZAR = "ZAR" # South African Rand currency code JOD = "JOD" # Jordan currency code -UE_000 = "UE_000" #default unified error code [default.extend-words] diff --git a/CHANGELOG.md b/CHANGELOG.md index ee37761719f2..8d5eb5d0517b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,244 @@ All notable changes to HyperSwitch will be documented here. - - - +## 2024.11.06.0 + +### Features + +- **config:** Update vector config ([#6365](https://github.com/juspay/hyperswitch/pull/6365)) ([`2919db8`](https://github.com/juspay/hyperswitch/commit/2919db874bd84372663228f2531ba18338e039c0)) +- **connector:** + - [ELAVON] Template PR ([#6309](https://github.com/juspay/hyperswitch/pull/6309)) ([`b481e5c`](https://github.com/juspay/hyperswitch/commit/b481e5cb8ffe417591a2fb917f37ba72667f2fcd)) + - [Paypal] implement vaulting for paypal wallet and cards while purchasing ([#5323](https://github.com/juspay/hyperswitch/pull/5323)) ([`22ba2db`](https://github.com/juspay/hyperswitch/commit/22ba2dbb2870471315d688147b3b53c432ce15dc)) + - [JP MORGAN] Added Template code for cards integration ([#6467](https://github.com/juspay/hyperswitch/pull/6467)) ([`b048e39`](https://github.com/juspay/hyperswitch/commit/b048e39b5c4213752da7765834915cca6bf776f6)) +- **db:** Implement `MerchantAccountInteraface` for `Mockdb` ([#6283](https://github.com/juspay/hyperswitch/pull/6283)) ([`5f493a5`](https://github.com/juspay/hyperswitch/commit/5f493a5166aa0a0a29f9aed538cad03def657c22)) +- **nix:** Add support for running external services through services-flake ([#6377](https://github.com/juspay/hyperswitch/pull/6377)) ([`95f2e0b`](https://github.com/juspay/hyperswitch/commit/95f2e0b8c51bfe116241fc486069e10e578a5ff8)) +- **users:** Add `force_two_factor_auth` environment variable ([#6466](https://github.com/juspay/hyperswitch/pull/6466)) ([`6b66ccc`](https://github.com/juspay/hyperswitch/commit/6b66cccd02c2589bb2dad38b46f4da7e1455ca0b)) + +### Bug Fixes + +- **connector:** + - Expiration Year Incorrectly Populated as YYYY Format in Paybox Mandates ([#6474](https://github.com/juspay/hyperswitch/pull/6474)) ([`e457ccd`](https://github.com/juspay/hyperswitch/commit/e457ccd91e60d5168e0a3283dfa325097f455076)) + - [Cybersource] remove newline in billing address with space ([#6478](https://github.com/juspay/hyperswitch/pull/6478)) ([`7f1d345`](https://github.com/juspay/hyperswitch/commit/7f1d34571f72f63b8bb52aff995ad093e3b6d856)) +- **refunds:** Remove to schema from refund aggregate response and exclude it from open api documentation ([#6405](https://github.com/juspay/hyperswitch/pull/6405)) ([`449c9cf`](https://github.com/juspay/hyperswitch/commit/449c9cfe557b3540e4ad25e48e012b531eb232fd)) +- Replace deprecated backticks with $(...) for command substitution ([#6337](https://github.com/juspay/hyperswitch/pull/6337)) ([`1c92f58`](https://github.com/juspay/hyperswitch/commit/1c92f5843009db42778f94bc9fd915b411a93f76)) +- Lazy connection pools for dynamic routing service ([#6437](https://github.com/juspay/hyperswitch/pull/6437)) ([`71d9933`](https://github.com/juspay/hyperswitch/commit/71d99332204ddfbb3cf305c7d3bc8840d508bf47)) + +**Full Changelog:** [`2024.11.05.0...2024.11.06.0`](https://github.com/juspay/hyperswitch/compare/2024.11.05.0...2024.11.06.0) + +- - - + +## 2024.11.05.0 + +### Features + +- Add macro to generate ToEncryptable trait ([#6313](https://github.com/juspay/hyperswitch/pull/6313)) ([`19cf0f7`](https://github.com/juspay/hyperswitch/commit/19cf0f7437a8d16ee4da254d2a3e2659879be68c)) + +### Bug Fixes + +- **analytics:** Add dynamic limit by clause in failure reasons metric query ([#6462](https://github.com/juspay/hyperswitch/pull/6462)) ([`8825378`](https://github.com/juspay/hyperswitch/commit/88253780d708bc1c005a87c186c4b0b14325c8a0)) + +### Refactors + +- **connector:** [AIRWALLEX, MULTISAFEPAY, RAZORPAY, SHIFT4, WORLDPAY, ZSL] Move connectors from `router` to `hyperswitch_connectors` crate ([#6369](https://github.com/juspay/hyperswitch/pull/6369)) ([`72ee434`](https://github.com/juspay/hyperswitch/commit/72ee434003eef744d516343a2f803264f226d92a)) + +**Full Changelog:** [`2024.11.04.0...2024.11.05.0`](https://github.com/juspay/hyperswitch/compare/2024.11.04.0...2024.11.05.0) + +- - - + +## 2024.11.04.0 + +### Features + +- **analytics:** Add `customer_id` as filter for payment intents ([#6344](https://github.com/juspay/hyperswitch/pull/6344)) ([`d697def`](https://github.com/juspay/hyperswitch/commit/d697def0b7cad3743db9fd70d09a45921dcbea61)) +- **authz:** Make info APIs support `ParentGroup` ([#6440](https://github.com/juspay/hyperswitch/pull/6440)) ([`7dcffcc`](https://github.com/juspay/hyperswitch/commit/7dcffccf3f16de5e40f61a302beb318035c3e88b)) +- **connector:** [Paybox] Add mandates Flow for Paybox ([#6378](https://github.com/juspay/hyperswitch/pull/6378)) ([`37513e0`](https://github.com/juspay/hyperswitch/commit/37513e0f1e78f99da0accf0fee263c10ca4e03c6)) +- **cypress-test:** Include worldpay's request / response structure for test suite ([#6420](https://github.com/juspay/hyperswitch/pull/6420)) ([`8372389`](https://github.com/juspay/hyperswitch/commit/8372389671c4aefeb625365d198390df5d8f35a5)) +- **router:** Add payments get-intent API for v2 ([#6396](https://github.com/juspay/hyperswitch/pull/6396)) ([`c514608`](https://github.com/juspay/hyperswitch/commit/c514608594ebbe9894de47747b0d9fb573ab2503)) + +### Refactors + +- **connector:** Add amount conversion framework to rapyd ([#6414](https://github.com/juspay/hyperswitch/pull/6414)) ([`33bc83f`](https://github.com/juspay/hyperswitch/commit/33bc83fce47c579457f1b9be0a91bb4fa13585ff)) +- **connnector:** Structure connector enums in separate files for improved team ownership ([#6459](https://github.com/juspay/hyperswitch/pull/6459)) ([`bb246e2`](https://github.com/juspay/hyperswitch/commit/bb246e27b72e9e4168c89b94e8d07d63a544b586)) + +### Documentation + +- **README:** Updated the icon and repositioned the hero image ([#6445](https://github.com/juspay/hyperswitch/pull/6445)) ([`35bf5a9`](https://github.com/juspay/hyperswitch/commit/35bf5a91d9a5b2d5e476c995e679b445242218e0)) + +### Miscellaneous Tasks + +- **users:** Change entity_type column of roles to non-optional ([#6435](https://github.com/juspay/hyperswitch/pull/6435)) ([`62067e4`](https://github.com/juspay/hyperswitch/commit/62067e406a01d3a17ef94a04b0ef0304ebd05a70)) + +**Full Changelog:** [`2024.10.30.0...2024.11.04.0`](https://github.com/juspay/hyperswitch/compare/2024.10.30.0...2024.11.04.0) + +- - - + +## 2024.10.30.0 + +### Refactors + +- **connector:** Add amount conversion framework to payu ([#6199](https://github.com/juspay/hyperswitch/pull/6199)) ([`11ce389`](https://github.com/juspay/hyperswitch/commit/11ce389000bf53c7f740d069f7ad2262bf5b70d6)) + +### Documentation + +- Added desc. for wallets other than AP, GP ([#6452](https://github.com/juspay/hyperswitch/pull/6452)) ([`55a81eb`](https://github.com/juspay/hyperswitch/commit/55a81eb4692979036d0bfd43e445d3e1db6601e7)) + +**Full Changelog:** [`2024.10.29.0...2024.10.30.0`](https://github.com/juspay/hyperswitch/compare/2024.10.29.0...2024.10.30.0) + +- - - + +## 2024.10.29.0 + +### Bug Fixes + +- **multitenancy:** Consistently use tenant nomenclature everywhere ([#6389](https://github.com/juspay/hyperswitch/pull/6389)) ([`aecd5ee`](https://github.com/juspay/hyperswitch/commit/aecd5eea3d2dce3ccdd4784f60d076b641104b67)) + +**Full Changelog:** [`2024.10.28.2...2024.10.29.0`](https://github.com/juspay/hyperswitch/compare/2024.10.28.2...2024.10.29.0) + +- - - + +## 2024.10.28.2 + +### Bug Fixes + +- **connector:** + - [Novalnet] Remove webhook placeholder connector config ([#6451](https://github.com/juspay/hyperswitch/pull/6451)) ([`e33340e`](https://github.com/juspay/hyperswitch/commit/e33340e70b59e9e4f18e92fc27d8c90b3df5768b)) + - [Adyen] Add MYR currency config ([#6442](https://github.com/juspay/hyperswitch/pull/6442)) ([`925e424`](https://github.com/juspay/hyperswitch/commit/925e4240e4ad6da1d243769b184842c0d8251a7d)) + +**Full Changelog:** [`2024.10.28.1...2024.10.28.2`](https://github.com/juspay/hyperswitch/compare/2024.10.28.1...2024.10.28.2) + +- - - + +## 2024.10.28.1 + +### Bug Fixes + +- **core:** Fix setup mandate payments to store connector mandate details ([#6446](https://github.com/juspay/hyperswitch/pull/6446)) ([`cee84cd`](https://github.com/juspay/hyperswitch/commit/cee84cdcfd6c323e8db80163f462d8e286aae600)) + +**Full Changelog:** [`2024.10.28.0...2024.10.28.1`](https://github.com/juspay/hyperswitch/compare/2024.10.28.0...2024.10.28.1) + +- - - + +## 2024.10.28.0 + +### Features + +- **connector:** + - [Rapyd] Use connector_response_reference_id ([#6302](https://github.com/juspay/hyperswitch/pull/6302)) ([`a845d46`](https://github.com/juspay/hyperswitch/commit/a845d46899d87ba7f3ca4386719c1934ce3da90e)) + - [Rapyd] Use connector_request_reference_id ([#6296](https://github.com/juspay/hyperswitch/pull/6296)) ([`4105d98`](https://github.com/juspay/hyperswitch/commit/4105d98d7aca885f9c622d5b56c6dbacb85a688b)) + - [Novalnet] Integrate Applepay wallet token flow ([#6409](https://github.com/juspay/hyperswitch/pull/6409)) ([`1d24b04`](https://github.com/juspay/hyperswitch/commit/1d24b04596e6d2f7c44b93501d56fc4fb950bd3b)) + - [PayU] Use connector_request_reference_id ([#6360](https://github.com/juspay/hyperswitch/pull/6360)) ([`acd1530`](https://github.com/juspay/hyperswitch/commit/acd153042062dd14d5e6e266fdc73d82b78213fe)) + - [Fiuu] Add support for cards recurring payments ([#6361](https://github.com/juspay/hyperswitch/pull/6361)) ([`4647a2f`](https://github.com/juspay/hyperswitch/commit/4647a2f6aece6b9479395fa3622b51b50d3091ee)) +- **euclid:** Add dynamic routing in core flows ([#6333](https://github.com/juspay/hyperswitch/pull/6333)) ([`ce732db`](https://github.com/juspay/hyperswitch/commit/ce732db9b2f98924a2b1d44ea5eb1000b6cbb498)) +- **router:** Move organization_id to request header from request body for v2 ([#6277](https://github.com/juspay/hyperswitch/pull/6277)) ([`aaac9aa`](https://github.com/juspay/hyperswitch/commit/aaac9aa97d1b00d50bec4e02efb0658956463398)) +- **sample_data:** Generate random disputes for sample data ([#6341](https://github.com/juspay/hyperswitch/pull/6341)) ([`e36ea18`](https://github.com/juspay/hyperswitch/commit/e36ea184ae6d1363fb1af55c790162df9f8b451c)) +- Add amount, currency and email to paze session response ([#6412](https://github.com/juspay/hyperswitch/pull/6412)) ([`a3ea62f`](https://github.com/juspay/hyperswitch/commit/a3ea62f88524a360b666cacfbc1cf239f6be8797)) + +### Bug Fixes + +- **analytics:** Fix refund status filter on dashboard ([#6431](https://github.com/juspay/hyperswitch/pull/6431)) ([`d58f706`](https://github.com/juspay/hyperswitch/commit/d58f706dc3fdd5ea277eeef6de9c224fe6097b46)) +- **router:** Update request body for migrate-batch api ([#6429](https://github.com/juspay/hyperswitch/pull/6429)) ([`5307579`](https://github.com/juspay/hyperswitch/commit/53075792b372a7ca574b94058c7d72033c014bc8)) + +### Refactors + +- **connector:** + - Add amount conversion framework to tsys ([#6282](https://github.com/juspay/hyperswitch/pull/6282)) ([`90765be`](https://github.com/juspay/hyperswitch/commit/90765bece1b12b208192e7ae4d54f4c70a301cea)) + - [Paypal] Add support for passing shipping_cost in Payment request ([#6423](https://github.com/juspay/hyperswitch/pull/6423)) ([`b0d5c96`](https://github.com/juspay/hyperswitch/commit/b0d5c96b9918549663125681259a598698ec705c)) + - Added amount conversion framework for klarna and change type of amount to MinorUnit for OrderDetailsWithAmount ([#4979](https://github.com/juspay/hyperswitch/pull/4979)) ([`2807622`](https://github.com/juspay/hyperswitch/commit/2807622ba671f77892a0fde42febbcffcb6c2238)) + +**Full Changelog:** [`2024.10.25.0...2024.10.28.0`](https://github.com/juspay/hyperswitch/compare/2024.10.25.0...2024.10.28.0) + +- - - + +## 2024.10.25.0 + +### Features + +- **authz:** Create a permission generator ([#6394](https://github.com/juspay/hyperswitch/pull/6394)) ([`4a0afb8`](https://github.com/juspay/hyperswitch/commit/4a0afb8213cce47cabe9e3f5d22ad1dccb02c20f)) +- **connector:** + - [Airwallex] Use connector_response_reference_id as reference to merchant ([#2747](https://github.com/juspay/hyperswitch/pull/2747)) ([`4b569c9`](https://github.com/juspay/hyperswitch/commit/4b569c9d5eb9b6403175c958b887d7ace4d9cbbb)) + - [Novalnet] Integrate wallets Paypal and Googlepay ([#6370](https://github.com/juspay/hyperswitch/pull/6370)) ([`673b869`](https://github.com/juspay/hyperswitch/commit/673b8691e092e145ba211050db4f5c7e021a0ce2)) +- **payments_v2:** Add payment_confirm_intent api endpoint ([#6263](https://github.com/juspay/hyperswitch/pull/6263)) ([`c7c1e1a`](https://github.com/juspay/hyperswitch/commit/c7c1e1adabceeb0a03659bf8feb9aa06d85960ea)) + +### Bug Fixes + +- **core:** Populate billing_address for payment with pm_id ([#6411](https://github.com/juspay/hyperswitch/pull/6411)) ([`8e58b56`](https://github.com/juspay/hyperswitch/commit/8e58b56b43ad2f823c51943c34aa8837297c70d6)) +- **payment_methods:** Fix merchant payment method list to retain a mca based on connector_name and mca_id ([#6408](https://github.com/juspay/hyperswitch/pull/6408)) ([`842c4a2`](https://github.com/juspay/hyperswitch/commit/842c4a2f47d4cc7b850a16abbe5431fe575f7a86)) +- **payments:** Filter total count by card-network value ([#6397](https://github.com/juspay/hyperswitch/pull/6397)) ([`ca325e9`](https://github.com/juspay/hyperswitch/commit/ca325e969b24fbbb5aa7edcdf86d5b3022291db1)) + +### Refactors + +- **connector:** + - Add amount conversion framework to Shift4 ([#6250](https://github.com/juspay/hyperswitch/pull/6250)) ([`fbe3951`](https://github.com/juspay/hyperswitch/commit/fbe395198aea7252e9c4e3fad97956a548d07002)) + - Add amount conversion framework to Wellsfargo ([#6298](https://github.com/juspay/hyperswitch/pull/6298)) ([`c3b0f7c`](https://github.com/juspay/hyperswitch/commit/c3b0f7c1d6ad95034535048aa50ff6abe9ed6aa0)) + +### Documentation + +- **cypress:** Refactor cypress documentation for more clarity ([#6415](https://github.com/juspay/hyperswitch/pull/6415)) ([`26e0c32`](https://github.com/juspay/hyperswitch/commit/26e0c32f4da5689a1c01fbb456ac008a0b831710)) +- **openapi:** Improve `rust_locker_open_api_spec` ([#6322](https://github.com/juspay/hyperswitch/pull/6322)) ([`a31d164`](https://github.com/juspay/hyperswitch/commit/a31d1641fb9e1c9efd652c6f191f6b29c75dc69b)) + +### Miscellaneous Tasks + +- Add samsung pay payment method support for cybersource ([#6424](https://github.com/juspay/hyperswitch/pull/6424)) ([`ecaf700`](https://github.com/juspay/hyperswitch/commit/ecaf70099671950287e9a6b7d30ffd02c0c5f51e)) +- Address Rust 1.82.0 clippy lints ([#6401](https://github.com/juspay/hyperswitch/pull/6401)) ([`8708a5c`](https://github.com/juspay/hyperswitch/commit/8708a5cb8f7d64a382b2fe061c725d4854ba9e92)) + +**Full Changelog:** [`2024.10.24.0...2024.10.25.0`](https://github.com/juspay/hyperswitch/compare/2024.10.24.0...2024.10.25.0) + +- - - + +## 2024.10.24.0 + +### Features + +- **analytics:** Remove additional filters from PaymentIntentFilters ([#6403](https://github.com/juspay/hyperswitch/pull/6403)) ([`4ef48c3`](https://github.com/juspay/hyperswitch/commit/4ef48c39b3ed7c1fcda9c850da766a0bdb701335)) +- **router:** Add api_models and openapi changes for refunds create api v2 ([#6385](https://github.com/juspay/hyperswitch/pull/6385)) ([`5a10e58`](https://github.com/juspay/hyperswitch/commit/5a10e5867a0f3097a40c8a6868454ff06630ed2c)) + +### Bug Fixes + +- **connector_config:** Include the `payment_processing_details_at` `Hyperswitch` option only if apple pay token decryption flow is supported for the connector ([#6386](https://github.com/juspay/hyperswitch/pull/6386)) ([`af0aeee`](https://github.com/juspay/hyperswitch/commit/af0aeeea53014d8fe5c955cbad3fe8b371c44889)) +- **deployment-config:** Remove invalid currencies from worldpay filters ([#6400](https://github.com/juspay/hyperswitch/pull/6400)) ([`aee11c5`](https://github.com/juspay/hyperswitch/commit/aee11c560e427195a0d321dff19c0d33ec60ba64)) + +### Refactors + +- **connector:** Move connectors Forte, Nexinets, Payeezy, Payu and Zen from Router to Hyperswitch Connector Trait ([#6261](https://github.com/juspay/hyperswitch/pull/6261)) ([`829a20c`](https://github.com/juspay/hyperswitch/commit/829a20cc933267551e49565d06eb08e03e5f13bb)) + +**Full Changelog:** [`2024.10.23.0...2024.10.24.0`](https://github.com/juspay/hyperswitch/compare/2024.10.23.0...2024.10.24.0) + +- - - + +## 2024.10.23.0 + +### Features + +- **cypress:** Execute cypress tests in parallel ([#6225](https://github.com/juspay/hyperswitch/pull/6225)) ([`f247978`](https://github.com/juspay/hyperswitch/commit/f24797834553794f341bd4f3be3afe5fcba693ed)) + +### Refactors + +- **connector:** [WorldPay] propagate refusal codes as error code and messages ([#6392](https://github.com/juspay/hyperswitch/pull/6392)) ([`3d1a3cd`](https://github.com/juspay/hyperswitch/commit/3d1a3cdc8f942a3dca2e6a200bf9200366bd62f1)) +- **permissions:** Remove permissions field from permission info API response ([#6376](https://github.com/juspay/hyperswitch/pull/6376)) ([`e5710fa`](https://github.com/juspay/hyperswitch/commit/e5710fa084ed5b0a4969a63b14a7f8e3433a3c64)) + +**Full Changelog:** [`2024.10.22.0...2024.10.23.0`](https://github.com/juspay/hyperswitch/compare/2024.10.22.0...2024.10.23.0) + +- - - + +## 2024.10.22.0 + +### Features + +- **connector:** Add 3DS flow for Worldpay ([#6374](https://github.com/juspay/hyperswitch/pull/6374)) ([`b93c849`](https://github.com/juspay/hyperswitch/commit/b93c849623c46ad00fe8dfe5bed85a43c700b3c8)) + +### Bug Fixes + +- **mandates:** Allow connector_mandate_detail updation in case of 'Authorized' Payments ([#6379](https://github.com/juspay/hyperswitch/pull/6379)) ([`d09a805`](https://github.com/juspay/hyperswitch/commit/d09a805c0ab4e1224a94ef64b0d75a77355bc3f3)) + +### Refactors + +- **connector:** [WorldPay] migrate from modular to standard payment APIs ([#6317](https://github.com/juspay/hyperswitch/pull/6317)) ([`58296ff`](https://github.com/juspay/hyperswitch/commit/58296ffae6ff6f2f2c8f7b23dd28e92b374b9be3)) +- **router:** Introduce ApiKeyId id type ([#6324](https://github.com/juspay/hyperswitch/pull/6324)) ([`b3ce373`](https://github.com/juspay/hyperswitch/commit/b3ce373f8ecdce362296c9a4b3c3e3543e1baa6f)) + +**Full Changelog:** [`2024.10.21.0...2024.10.22.0`](https://github.com/juspay/hyperswitch/compare/2024.10.21.0...2024.10.22.0) + +- - - + ## 2024.10.21.0 ### Features diff --git a/Cargo.lock b/Cargo.lock index 26ad619ee0ba..d232fcbf024c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -353,6 +353,7 @@ dependencies = [ "bigdecimal", "common_enums", "common_utils", + "currency_conversion", "diesel_models", "error-stack", "futures 0.3.30", @@ -363,6 +364,7 @@ dependencies = [ "opensearch", "reqwest 0.11.27", "router_env", + "rust_decimal", "serde", "serde_json", "sqlx", @@ -3126,8 +3128,10 @@ dependencies = [ "dyn-clone", "error-stack", "hex", + "http-body-util", "hyper 0.14.30", "hyper-proxy", + "hyper-util", "hyperswitch_interfaces", "masking", "once_cell", @@ -3959,9 +3963,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" dependencies = [ "bytes 1.7.1", "futures-channel", @@ -3972,7 +3976,6 @@ dependencies = [ "pin-project-lite", "socket2", "tokio 1.40.0", - "tower", "tower-service", "tracing", ] @@ -3997,6 +4000,7 @@ dependencies = [ "hyperswitch_interfaces", "image", "masking", + "mime", "once_cell", "qrcode", "rand", @@ -4007,9 +4011,11 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "serde_with", "strum 0.26.3", "time", "url", + "urlencoding", "uuid", ] @@ -6438,6 +6444,7 @@ dependencies = [ "unicode-segmentation", "unidecode", "url", + "urlencoding", "utoipa", "uuid", "validator", diff --git a/INSTALL_dependencies.sh b/INSTALL_dependencies.sh index 3ec36ccc66e0..e1d666b97a30 100755 --- a/INSTALL_dependencies.sh +++ b/INSTALL_dependencies.sh @@ -37,7 +37,7 @@ set -o nounset # utilities # convert semver to comparable integer -if [[ `id -u` -ne 0 ]]; then +if [[ "$(id -u)" -ne 0 ]]; then print_info "requires sudo" SUDO=sudo else @@ -45,10 +45,10 @@ else fi ver () { - printf "%03d%03d%03d%03d" `echo "$1" | tr '.' ' '`; + printf "%03d%03d%03d%03d" "$(echo "$1" | tr '.' ' ')"; } -PROGNAME=`basename $0` +PROGNAME="$(basename $0)" print_info () { echo -e "$PROGNAME: $*" } @@ -125,10 +125,10 @@ if command -v cargo > /dev/null; then need_cmd rustc - RUST_VERSION=`rustc -V | cut -d " " -f 2` + RUST_VERSION="$(rustc -V | cut -d " " -f 2)" - _HAVE_VERSION=`ver ${RUST_VERSION}` - _NEED_VERSION=`ver ${RUST_MSRV}` + _HAVE_VERSION="$(ver ${RUST_VERSION})" + _NEED_VERSION="$(ver ${RUST_MSRV})" print_info "Found rust version \"${RUST_VERSION}\". MSRV is \"${RUST_MSRV}\"" @@ -166,7 +166,7 @@ install_dep () { $INSTALL_CMD $* } -if [[ ! -x "`command -v psql`" ]] || [[ ! -x "`command -v redis-server`" ]] ; then +if [[ ! -x "$(command -v psql)" ]] || [[ ! -x "$(command -v redis-server)" ]] ; then print_info "Missing dependencies. Trying to install" # java has an apt which seems to mess up when we look for apt diff --git a/README.md b/README.md index ccdd6e19b6d2..10fdb6afc760 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ The single API to access payment ecosystems across 130+ countries

- + @@ -44,7 +44,6 @@ The single API to access payment ecosystems across 130+ countries


- Hyperswitch is a community-led, open payments switch designed to empower digital businesses by providing fast, reliable, and affordable access to the best payments infrastructure. @@ -58,7 +57,8 @@ Here are the components of Hyperswitch that deliver the whole solution: Jump in and contribute to these repositories to help improve and expand Hyperswitch! -
+ +

⚡️ Quick Setup

diff --git a/add_connector.md b/add_connector.md index eda368db9c83..4d6e885b7edf 100644 --- a/add_connector.md +++ b/add_connector.md @@ -311,7 +311,7 @@ impl TryFrom> let payments_response_data = types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id.clone()), redirection_data, - mandate_reference: None, + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some( 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 000000000000..58624c2771b9 --- /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/api-reference/payments/payments--get-intent.mdx b/api-reference-v2/api-reference/payments/payments--get-intent.mdx new file mode 100644 index 000000000000..cd1321be217e --- /dev/null +++ b/api-reference-v2/api-reference/payments/payments--get-intent.mdx @@ -0,0 +1,3 @@ +--- +openapi: get /v2/payments/{id}/get-intent +--- \ No newline at end of file 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 000000000000..fa52f18c2867 --- /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 4d990aa5d40f..17dd6dfb7ffa 100644 --- a/api-reference-v2/mint.json +++ b/api-reference-v2/mint.json @@ -38,7 +38,9 @@ "group": "Payments", "pages": [ "api-reference/payments/payments--create-intent", - "api-reference/payments/payments--session-token" + "api-reference/payments/payments--get-intent", + "api-reference/payments/payments--session-token", + "api-reference/payments/payments--confirm-intent" ] }, { @@ -107,6 +109,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 41bda6be8543..4c1559fe099b 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -453,6 +453,20 @@ "summary": "Merchant Account - Create", "description": "Create a new account for a *merchant* and the *merchant* could be a seller or retailer or client who likes to receive and send payments.\n\nBefore creating the merchant account, it is mandatory to create an organization.", "operationId": "Create a Merchant Account", + "parameters": [ + { + "name": "X-Organization-Id", + "in": "header", + "description": "Organization ID for which the merchant account has to be created.", + "required": true, + "schema": { + "type": "string" + }, + "example": { + "X-Organization-Id": "org_abcdefghijklmnop" + } + } + ], "requestBody": { "content": { "application/json": { @@ -466,8 +480,7 @@ "primary_contact_person": "John Doe", "primary_email": "example@company.com" }, - "merchant_name": "Cloth Store", - "organization_id": "org_abcdefghijklmnop" + "merchant_name": "Cloth Store" } }, "Create a merchant account with metadata": { @@ -476,14 +489,12 @@ "metadata": { "key_1": "John Doe", "key_2": "Trends" - }, - "organization_id": "org_abcdefghijklmnop" + } } }, "Create a merchant account with minimal fields": { "value": { - "merchant_name": "Cloth Store", - "organization_id": "org_abcdefghijklmnop" + "merchant_name": "Cloth Store" } } } @@ -663,7 +674,7 @@ ] } }, - "/v2/payments/{payment_id}/create_external_sdk_tokens": { + "/v2/payments/{payment_id}/create-external-sdk-tokens": { "post": { "tags": [ "Payments" @@ -1832,7 +1843,170 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PaymentsCreateIntentResponse" + "$ref": "#/components/schemas/PaymentsIntentResponse" + } + } + } + }, + "400": { + "description": "Missing Mandatory fields" + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/v2/payments/{id}/get-intent": { + "get": { + "tags": [ + "Payments" + ], + "summary": "Payments - Get Intent", + "description": "**Get a payment intent object when id is passed in path**\n\nYou will require the 'API - Key' from the Hyperswitch dashboard to make the call.", + "operationId": "Get the Payment Intent details", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The unique identifier for the Payment Intent", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Payment Intent", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaymentsIntentResponse" + } + } + } + }, + "404": { + "description": "Payment Intent not found" + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/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": [ + "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" } } } @@ -2406,6 +2580,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": { @@ -5419,76 +5652,158 @@ "greater_than_equal" ] }, - "Connector": { - "type": "string", - "description": "A connector is an integration to fulfill payments", - "enum": [ - "adyenplatform", - "phonypay", - "fauxpay", - "pretendpay", - "stripe_test", - "adyen_test", - "checkout_test", - "paypal_test", - "aci", - "adyen", - "airwallex", - "authorizedotnet", - "bambora", - "bamboraapac", - "bankofamerica", - "billwerk", - "bitpay", - "bluesnap", - "boku", - "braintree", - "cashtocode", - "checkout", - "coinbase", - "cryptopay", - "cybersource", - "datatrans", - "deutschebank", - "dlocal", - "ebanx", - "fiserv", - "fiservemea", - "fiuu", - "forte", - "globalpay", - "globepay", - "gocardless", - "gpayments", - "helcim", - "iatapay", - "itaubank", - "klarna", - "mifinity", - "mollie", - "multisafepay", - "netcetera", - "nexinets", - "nexixpay", - "nmi", - "noon", - "novalnet", - "nuvei", - "opennode", - "paybox", - "payme", - "payone", - "paypal", - "payu", - "placetopay", - "powertranz", - "prophetpay", - "rapyd", - "razorpay", - "shift4", - "square", - "stax", - "stripe", + "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", + "enum": [ + "adyenplatform", + "phonypay", + "fauxpay", + "pretendpay", + "stripe_test", + "adyen_test", + "checkout_test", + "paypal_test", + "aci", + "adyen", + "airwallex", + "authorizedotnet", + "bambora", + "bamboraapac", + "bankofamerica", + "billwerk", + "bitpay", + "bluesnap", + "boku", + "braintree", + "cashtocode", + "checkout", + "coinbase", + "cryptopay", + "cybersource", + "datatrans", + "deutschebank", + "dlocal", + "ebanx", + "fiserv", + "fiservemea", + "fiuu", + "forte", + "globalpay", + "globepay", + "gocardless", + "gpayments", + "helcim", + "iatapay", + "itaubank", + "klarna", + "mifinity", + "mollie", + "multisafepay", + "netcetera", + "nexinets", + "nexixpay", + "nmi", + "noon", + "novalnet", + "nuvei", + "opennode", + "paybox", + "payme", + "payone", + "paypal", + "payu", + "placetopay", + "powertranz", + "prophetpay", + "rapyd", + "razorpay", + "shift4", + "square", + "stax", + "stripe", "taxjar", "threedsecureio", "trustpay", @@ -7035,6 +7350,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": [ @@ -9094,8 +9437,7 @@ "MerchantAccountCreate": { "type": "object", "required": [ - "merchant_name", - "organization_id" + "merchant_name" ], "properties": { "merchant_name": { @@ -9116,13 +9458,6 @@ "type": "object", "description": "Metadata is useful for storing additional, unstructured information about the merchant account.", "nullable": true - }, - "organization_id": { - "type": "string", - "description": "The id of the organization to which the merchant belongs to. Please use the organization endpoint to create an organization", - "example": "org_q98uSGAYbjEwqs0mJwnz", - "maxLength": 64, - "minLength": 1 } }, "additionalProperties": false @@ -10683,9 +11018,7 @@ "minimum": 0 }, "amount": { - "type": "integer", - "format": "int64", - "description": "the amount per quantity of product" + "$ref": "#/components/schemas/MinorUnit" }, "requires_shipping": { "type": "boolean", @@ -12943,222 +13276,128 @@ } } }, - "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" - } - ], - "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, + "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 }, - "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_data": { + "$ref": "#/components/schemas/PaymentMethodDataRequest" }, - "routing": { - "allOf": [ - { - "$ref": "#/components/schemas/StraightThroughAlgorithm" - } - ], - "nullable": true + "payment_method_type": { + "$ref": "#/components/schemas/PaymentMethod" }, - "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 + "payment_method_subtype": { + "$ref": "#/components/schemas/PaymentMethodType" }, - "capture_method": { + "shipping": { "allOf": [ { - "$ref": "#/components/schemas/CaptureMethod" + "$ref": "#/components/schemas/Address" } ], "nullable": true }, - "authentication_type": { + "customer_acceptance": { "allOf": [ { - "$ref": "#/components/schemas/AuthenticationType" + "$ref": "#/components/schemas/CustomerAcceptance" } ], - "default": "three_ds", "nullable": true }, - "billing": { + "browser_info": { "allOf": [ { - "$ref": "#/components/schemas/Address" + "$ref": "#/components/schemas/BrowserInformation" } ], "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": { + } + } + }, + "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": "The identifier for the customer", - "example": "cus_y3oqhf46pyzuxjbcn2giaqnb44", - "nullable": true, + "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": 1 + "minLength": 32 }, - "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 + "status": { + "$ref": "#/components/schemas/IntentStatus" }, - "description": { + "amount": { + "$ref": "#/components/schemas/ConfirmIntentAmountDetailsResponse" + }, + "connector": { "type": "string", - "description": "A description for the payment", - "example": "It's my first payment request", - "nullable": true + "description": "The connector used for the payment", + "example": "stripe" }, - "return_url": { + "client_secret": { "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 + "description": "It's a token used for client side verification." }, - "setup_future_usage": { - "allOf": [ - { - "$ref": "#/components/schemas/FutureUsage" - } - ], - "nullable": true + "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/PaymentMethodDataRequest" - } - ], - "nullable": true - }, - "payment_method": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentMethod" + "$ref": "#/components/schemas/PaymentMethodDataResponseWithBilling" } ], "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 - }, - "shipping": { - "allOf": [ - { - "$ref": "#/components/schemas/Address" - } - ], - "nullable": true + "payment_method_type": { + "$ref": "#/components/schemas/PaymentMethod" }, - "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 + "payment_method_subtype": { + "$ref": "#/components/schemas/PaymentMethodType" }, - "statement_descriptor_suffix": { + "connector_transaction_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": "A unique identifier for a payment provided by the connector", + "example": "993672945374576J", "nullable": true }, - "client_secret": { + "connector_reference_id": { "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" - } - ], + "description": "reference(Identifier) to the payment at connector side", + "example": "993672945374576J", "nullable": true }, - "mandate_id": { + "merchant_connector_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 + "description": "Identifier of the connector ( merchant connector account ) which was chosen to make the payment" }, "browser_info": { "allOf": [ @@ -13168,138 +13407,13 @@ ], "nullable": true }, - "payment_experience": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentExperience" - } - ], - "nullable": true - }, - "payment_method_type": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentMethodType" - } - ], - "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 - }, - "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 - }, - "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 - }, - "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": { + "error": { "allOf": [ { - "$ref": "#/components/schemas/PaymentChargeRequest" + "$ref": "#/components/schemas/ErrorDetails" } ], "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 } } }, @@ -13495,339 +13609,259 @@ }, "additionalProperties": false }, - "PaymentsCreateIntentResponse": { + "PaymentsCreateResponseOpenApi": { "type": "object", "required": [ - "id", - "amount_details", - "client_secret", - "capture_method", - "authentication_type", - "customer_present", - "setup_future_usage", - "apply_mit_exemption", - "payment_link_enabled", - "request_incremental_authorization", - "expires_on", - "request_external_three_ds_authentication" + "payment_id", + "merchant_id", + "status", + "amount", + "net_amount", + "amount_capturable", + "currency", + "payment_method", + "attempt_count" ], "properties": { - "id": { - "type": "string", - "description": "Global Payment Id for the payment" - }, - "amount_details": { - "$ref": "#/components/schemas/AmountDetails" - }, - "client_secret": { - "type": "string", - "description": "It's a token used for client side verification.", - "example": "pay_U42c409qyHwOkWo3vK60_secret_el9ksDkiB8hi6j9N78yo" - }, - "merchant_reference_id": { + "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", - "nullable": true, "maxLength": 30, "minLength": 30 }, - "routing_algorithm_id": { + "merchant_id": { "type": "string", - "description": "The routing algorithm id to be used for the payment", - "nullable": true - }, - "capture_method": { - "$ref": "#/components/schemas/CaptureMethod" + "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 }, - "authentication_type": { + "status": { "allOf": [ { - "$ref": "#/components/schemas/AuthenticationType" + "$ref": "#/components/schemas/IntentStatus" } ], - "default": "no_three_ds" + "default": "requires_confirmation" }, - "billing": { - "allOf": [ - { - "$ref": "#/components/schemas/Address" - } - ], + "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 }, - "shipping": { - "allOf": [ - { - "$ref": "#/components/schemas/Address" - } - ], + "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", + "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_present": { - "$ref": "#/components/schemas/PresenceOfCustomerDuringPayment" - }, "description": { "type": "string", - "description": "A description for the payment", + "description": "A description of 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", + "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 }, - "setup_future_usage": { - "$ref": "#/components/schemas/FutureUsage" - }, - "apply_mit_exemption": { - "$ref": "#/components/schemas/MitExemptionRequest" - }, - "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": { + "disputes": { "type": "array", "items": { - "$ref": "#/components/schemas/OrderDetailsWithAmount" + "$ref": "#/components/schemas/DisputeResponsePaymentsRetrieve" }, - "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": "List of disputes that happened on this intent", "nullable": true }, - "allowed_payment_method_types": { + "attempts": { "type": "array", "items": { - "$ref": "#/components/schemas/PaymentMethodType" + "$ref": "#/components/schemas/PaymentAttemptResponse" }, - "description": "Use this parameter to restrict the Payment Method Types to show for a given PaymentIntent", + "description": "List of attempts that happened on this intent", "nullable": true }, - "metadata": { - "type": "object", - "description": "Metadata is useful for storing additional, unstructured information on an object.", + "captures": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CaptureResponse" + }, + "description": "List of captures done on latest attempt", "nullable": true }, - "connector_metadata": { + "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/ConnectorMetadata" + "$ref": "#/components/schemas/MandateData" } ], "nullable": true }, - "feature_metadata": { + "setup_future_usage": { "allOf": [ { - "$ref": "#/components/schemas/FeatureMetadata" + "$ref": "#/components/schemas/FutureUsage" } ], "nullable": true }, - "payment_link_enabled": { - "$ref": "#/components/schemas/EnablePaymentLinkRequest" + "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 }, - "payment_link_config": { + "capture_method": { "allOf": [ { - "$ref": "#/components/schemas/PaymentLinkConfigRequest" + "$ref": "#/components/schemas/CaptureMethod" } ], "nullable": true }, - "request_incremental_authorization": { - "$ref": "#/components/schemas/RequestIncrementalAuthorization" - }, - "expires_on": { - "type": "string", - "format": "date-time", - "description": "Will be used to expire client secret after certain amount of time to be supplied in seconds" + "payment_method": { + "$ref": "#/components/schemas/PaymentMethod" }, - "frm_metadata": { - "type": "object", - "description": "Additional data related to some frm(Fraud Risk Management) connectors", + "payment_method_data": { + "allOf": [ + { + "$ref": "#/components/schemas/PaymentMethodDataResponseWithBilling" + } + ], "nullable": true }, - "request_external_three_ds_authentication": { - "$ref": "#/components/schemas/External3dsAuthenticationRequest" - } - }, - "additionalProperties": false - }, - "PaymentsCreateRequest": { - "type": "object", - "required": [ - "amount", - "currency" - ], - "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)", - "minimum": 0 - }, - "currency": { - "$ref": "#/components/schemas/Currency" - }, - "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, + "payment_token": { + "type": "string", + "description": "Provide a reference to a stored payment method", + "example": "187282ab-40ef-47a9-9206-5099ba31e432", "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, + "shipping": { + "allOf": [ + { + "$ref": "#/components/schemas/Address" + } + ], "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 - }, - "routing": { + "billing": { "allOf": [ { - "$ref": "#/components/schemas/StraightThroughAlgorithm" + "$ref": "#/components/schemas/Address" } ], "nullable": true }, - "connector": { + "order_details": { "type": "array", "items": { - "$ref": "#/components/schemas/Connector" + "$ref": "#/components/schemas/OrderDetailsWithAmount" }, - "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 - }, - "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" - } - ], + "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 }, - "customer_id": { + "email": { "type": "string", - "description": "The identifier for the customer", - "example": "cus_y3oqhf46pyzuxjbcn2giaqnb44", + "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": 64, - "minLength": 1 + "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 + "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 }, - "description": { + "phone": { "type": "string", - "description": "A description for the payment", - "example": "It's my first payment 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 }, "return_url": { "type": "string", - "description": "The URL to which you want the user to be redirected after the completion of the payment operation", + "description": "The URL to redirect after the completion of the 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 - }, - "shipping": { + "authentication_type": { "allOf": [ { - "$ref": "#/components/schemas/Address" + "$ref": "#/components/schemas/AuthenticationType" } ], + "default": "three_ds", "nullable": true }, "statement_descriptor_name": { @@ -13839,49 +13873,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": { @@ -13900,6 +13919,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": [ { @@ -13910,16 +13935,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": { @@ -13927,1969 +13948,712 @@ "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, + "reference_id": { + "type": "string", + "description": "reference(Identifier) to the payment at connector side", + "example": "993672945374576J", "nullable": true }, - "recurring_details": { + "payment_link": { "allOf": [ { - "$ref": "#/components/schemas/RecurringDetails" + "$ref": "#/components/schemas/PaymentLinkResponse" } ], "nullable": true }, - "charges": { + "profile_id": { + "type": "string", + "description": "The business profile that is associated with this payment", + "nullable": true + }, + "surcharge_details": { "allOf": [ { - "$ref": "#/components/schemas/PaymentChargeRequest" + "$ref": "#/components/schemas/RequestSurchargeDetails" } ], "nullable": true }, - "merchant_order_reference_id": { + "attempt_count": { + "type": "integer", + "format": "int32", + "description": "Total number of attempts associated with this payment" + }, + "merchant_decision": { "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": "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 }, - "skip_external_tax_calculation": { - "type": "boolean", - "description": "Whether to calculate tax for this payment intent", - "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": { - "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 - }, - "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", - "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/MandateData" - } - ], - "nullable": true - }, - "setup_future_usage": { - "allOf": [ - { - "$ref": "#/components/schemas/FutureUsage" - } - ], - "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_method": { - "allOf": [ - { - "$ref": "#/components/schemas/CaptureMethod" - } - ], - "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": { + "merchant_connector_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" - } - ], + "description": "Identifier of the connector ( merchant connector account ) which was chosen to make the payment", "nullable": true }, - "request_incremental_authorization": { + "incremental_authorization_allowed": { "type": "boolean", - "description": "Request an incremental authorization, i.e., increase the authorized amount on a confirmed payment before you capture it.", + "description": "If true, incremental authorization can be performed on this payment, in case the funds authorized initially fall short.", "nullable": true }, - "session_expiry": { + "authorization_count": { "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", + "description": "Total number of authorizations happened in an incremental_authorization payment", "nullable": true }, - "captures": { + "incremental_authorizations": { "type": "array", "items": { - "$ref": "#/components/schemas/CaptureResponse" + "$ref": "#/components/schemas/IncrementalAuthorizationResponse" }, - "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/MandateData" - } - ], + "description": "List of incremental authorizations happened to the payment", "nullable": true }, - "setup_future_usage": { + "external_authentication_details": { "allOf": [ { - "$ref": "#/components/schemas/FutureUsage" + "$ref": "#/components/schemas/ExternalAuthenticationDetailsResponse" } ], "nullable": true }, - "off_session": { + "external_3ds_authentication_attempted": { "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, + "description": "Flag indicating if external 3ds authentication is made or not", "nullable": true }, - "capture_on": { + "expires_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", + "description": "Date Time for expiry of the payment", "example": "2022-09-10T10:11:12Z", "nullable": true }, - "capture_method": { - "allOf": [ - { - "$ref": "#/components/schemas/CaptureMethod" - } - ], + "fingerprint": { + "type": "string", + "description": "Payment Fingerprint, to identify a particular card.\nIt is a 20 character long alphanumeric code.", "nullable": true }, - "payment_method": { - "$ref": "#/components/schemas/PaymentMethod" - }, - "payment_method_data": { + "browser_info": { "allOf": [ { - "$ref": "#/components/schemas/PaymentMethodDataResponseWithBilling" + "$ref": "#/components/schemas/BrowserInformation" } ], "nullable": true }, - "payment_token": { + "payment_method_id": { "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" - } - ], + "description": "Identifier for Payment Method used for the payment", "nullable": true }, - "billing": { + "payment_method_status": { "allOf": [ { - "$ref": "#/components/schemas/Address" + "$ref": "#/components/schemas/PaymentMethodStatus" } ], "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": { + "updated": { "type": "string", - "description": "The URL to redirect after the completion of the operation", - "example": "https://hyperswitch.io", + "format": "date-time", + "description": "Date time at which payment was updated", + "example": "2022-09-10T10:11:12Z", "nullable": true }, - "authentication_type": { + "charges": { "allOf": [ { - "$ref": "#/components/schemas/AuthenticationType" + "$ref": "#/components/schemas/PaymentChargeResponse" } ], - "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 + "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 }, - "statement_descriptor_suffix": { + "merchant_order_reference_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 255 characters for the concatenated descriptor.", - "example": "Payment for shoes purchase", + "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 }, - "next_action": { + "order_tax_amount": { "allOf": [ { - "$ref": "#/components/schemas/NextActionData" + "$ref": "#/components/schemas/MinorUnit" } ], "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 - }, - "unified_code": { + "connector_mandate_id": { "type": "string", - "description": "error code unified across the connectors is received here if there was an error while calling connector", + "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" }, - "unified_message": { + "client_secret": { "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 + "description": "Client Secret" }, "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 + "$ref": "#/components/schemas/PaymentMethodType" }, - "connector_transaction_id": { + "session_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" - } - ], + "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" }, - "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 + "net_amount": { + "$ref": "#/components/schemas/MinorUnit" }, - "connector_metadata": { + "order_tax_amount": { "allOf": [ { - "$ref": "#/components/schemas/ConnectorMetadata" + "$ref": "#/components/schemas/MinorUnit" } ], "nullable": true }, - "feature_metadata": { + "shipping_cost": { "allOf": [ { - "$ref": "#/components/schemas/FeatureMetadata" + "$ref": "#/components/schemas/MinorUnit" } ], "nullable": true }, - "reference_id": { + "display_amount": { + "$ref": "#/components/schemas/DisplayAmountOnSdk" + } + } + }, + "PaymentsExternalAuthenticationRequest": { + "type": "object", + "required": [ + "client_secret", + "device_channel", + "threeds_method_comp_ind" + ], + "properties": { + "client_secret": { "type": "string", - "description": "reference(Identifier) to the payment at connector side", - "example": "993672945374576J", - "nullable": true + "description": "Client Secret" }, - "payment_link": { + "sdk_information": { "allOf": [ { - "$ref": "#/components/schemas/PaymentLinkResponse" + "$ref": "#/components/schemas/SdkInformation" } ], "nullable": true }, - "profile_id": { + "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": "The business profile that is associated with this payment", + "description": "Access Server URL to be used for challenge submission", "nullable": true }, - "surcharge_details": { - "allOf": [ - { - "$ref": "#/components/schemas/RequestSurchargeDetails" - } - ], + "challenge_request": { + "type": "string", + "description": "Challenge request which should be sent to acs_url", "nullable": true }, - "attempt_count": { - "type": "integer", - "format": "int32", - "description": "Total number of attempts associated with this payment" + "acs_reference_number": { + "type": "string", + "description": "Unique identifier assigned by the EMVCo(Europay, Mastercard and Visa)", + "nullable": true }, - "merchant_decision": { + "acs_trans_id": { "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": "Unique identifier assigned by the ACS to identify a single transaction", "nullable": true }, - "merchant_connector_id": { + "three_dsserver_trans_id": { "type": "string", - "description": "Identifier of the connector ( merchant connector account ) which was chosen to make the payment", + "description": "Unique identifier assigned by the 3DS Server to identify a single transaction", "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.", + "acs_signed_content": { + "type": "string", + "description": "Contains the JWS object created by the ACS for the ARes(Authentication Response) message", "nullable": true }, - "authorization_count": { + "three_ds_requestor_url": { + "type": "string", + "description": "Three DS Requestor URL" + } + } + }, + "PaymentsIncrementalAuthorizationRequest": { + "type": "object", + "required": [ + "amount" + ], + "properties": { + "amount": { "type": "integer", - "format": "int32", - "description": "Total number of authorizations happened in an incremental_authorization payment", - "nullable": true + "format": "int64", + "description": "The total amount including previously authorized amount and additional amount", + "example": 6540 }, - "incremental_authorizations": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IncrementalAuthorizationResponse" - }, - "description": "List of incremental authorizations happened to the payment", + "reason": { + "type": "string", + "description": "Reason for incremental authorization", "nullable": true + } + } + }, + "PaymentsIntentResponse": { + "type": "object", + "required": [ + "id", + "amount_details", + "client_secret", + "capture_method", + "authentication_type", + "customer_present", + "setup_future_usage", + "apply_mit_exemption", + "payment_link_enabled", + "request_incremental_authorization", + "expires_on", + "request_external_three_ds_authentication" + ], + "properties": { + "id": { + "type": "string", + "description": "Global Payment Id for the payment" }, - "external_authentication_details": { - "allOf": [ - { - "$ref": "#/components/schemas/ExternalAuthenticationDetailsResponse" - } - ], - "nullable": true + "amount_details": { + "$ref": "#/components/schemas/AmountDetailsResponse" }, - "external_3ds_authentication_attempted": { - "type": "boolean", - "description": "Flag indicating if external 3ds authentication is made or not", - "nullable": true + "client_secret": { + "type": "string", + "description": "It's a token used for client side verification.", + "example": "pay_U42c409qyHwOkWo3vK60_secret_el9ksDkiB8hi6j9N78yo" }, - "expires_on": { + "merchant_reference_id": { "type": "string", - "format": "date-time", - "description": "Date Time for expiry of the payment", - "example": "2022-09-10T10:11:12Z", - "nullable": true + "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 }, - "fingerprint": { + "routing_algorithm_id": { "type": "string", - "description": "Payment Fingerprint, to identify a particular card.\nIt is a 20 character long alphanumeric code.", + "description": "The routing algorithm id to be used for the payment", "nullable": true }, - "browser_info": { + "capture_method": { + "$ref": "#/components/schemas/CaptureMethod" + }, + "authentication_type": { "allOf": [ { - "$ref": "#/components/schemas/BrowserInformation" + "$ref": "#/components/schemas/AuthenticationType" } ], - "nullable": true + "default": "no_three_ds" }, - "payment_method_id": { - "type": "string", - "description": "Identifier for Payment Method used for the payment", + "billing": { + "allOf": [ + { + "$ref": "#/components/schemas/Address" + } + ], "nullable": true }, - "payment_method_status": { + "shipping": { "allOf": [ { - "$ref": "#/components/schemas/PaymentMethodStatus" + "$ref": "#/components/schemas/Address" } ], "nullable": true }, - "updated": { + "customer_id": { "type": "string", - "format": "date-time", - "description": "Date time at which payment was updated", - "example": "2022-09-10T10:11:12Z", + "description": "The identifier for the customer", + "example": "cus_y3oqhf46pyzuxjbcn2giaqnb44", + "nullable": true, + "maxLength": 64, + "minLength": 1 + }, + "customer_present": { + "$ref": "#/components/schemas/PresenceOfCustomerDuringPayment" + }, + "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": { + "$ref": "#/components/schemas/FutureUsage" + }, + "apply_mit_exemption": { + "$ref": "#/components/schemas/MitExemptionRequest" + }, + "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 }, - "charges": { + "connector_metadata": { "allOf": [ { - "$ref": "#/components/schemas/PaymentChargeResponse" + "$ref": "#/components/schemas/ConnectorMetadata" } ], "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.", + "feature_metadata": { + "allOf": [ + { + "$ref": "#/components/schemas/FeatureMetadata" + } + ], "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 + "payment_link_enabled": { + "$ref": "#/components/schemas/EnablePaymentLinkRequest" }, - "order_tax_amount": { + "payment_link_config": { "allOf": [ { - "$ref": "#/components/schemas/MinorUnit" + "$ref": "#/components/schemas/PaymentLinkConfigRequest" } ], "nullable": true }, - "connector_mandate_id": { + "request_incremental_authorization": { + "$ref": "#/components/schemas/RequestIncrementalAuthorization" + }, + "expires_on": { "type": "string", - "description": "Connector Identifier for the payment method", + "format": "date-time", + "description": "Will be used to expire client secret after certain amount of time to be supplied in seconds" + }, + "frm_metadata": { + "type": "object", + "description": "Additional data related to some frm(Fraud Risk Management) connectors", "nullable": true + }, + "request_external_three_ds_authentication": { + "$ref": "#/components/schemas/External3dsAuthenticationRequest" } - } + }, + "additionalProperties": false }, - "PaymentsRetrieveRequest": { + "PaymentsResponse": { "type": "object", "required": [ - "resource_id", - "force_sync" + "payment_id", + "merchant_id", + "status", + "amount", + "net_amount", + "amount_capturable", + "currency", + "payment_method", + "attempt_count" ], "properties": { - "resource_id": { + "payment_id": { "type": "string", - "description": "The type of ID (ex: payment intent id, payment attempt id or connector txn id)" + "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": "The identifier for the Merchant Account.", + "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 }, - "force_sync": { - "type": "boolean", - "description": "Decider to enable or disable the connector call for retrieve request" + "amount_capturable": { + "type": "integer", + "format": "int64", + "description": "The maximum amount that could be captured from the payment", + "example": 6540, + "minimum": 100 }, - "param": { - "type": "string", - "description": "The parameters passed to a retrieve request", + "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 name of the connector", + "description": "The connector used for the payment", + "example": "stripe", "nullable": true }, - "merchant_connector_details": { + "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/MerchantConnectorDetailsWrap" + "$ref": "#/components/schemas/CustomerDetailsResponse" } ], "nullable": true }, - "client_secret": { + "description": { "type": "string", - "description": "This is a token which expires after 15 minutes, used from the client to authenticate and create sessions from the SDK", + "description": "A description of the payment", + "example": "It's my first payment request", "nullable": true }, - "expand_captures": { - "type": "boolean", - "description": "If enabled provides list of captures linked to latest attempt", + "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 }, - "expand_attempts": { - "type": "boolean", - "description": "If enabled provides list of attempts linked to payment intent", + "disputes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DisputeResponsePaymentsRetrieve" + }, + "description": "List of disputes that happened on this 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" + "attempts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PaymentAttemptResponse" + }, + "description": "List of attempts that happened on this intent", + "nullable": true }, - "session_token": { + "captures": { "type": "array", "items": { - "$ref": "#/components/schemas/SessionToken" + "$ref": "#/components/schemas/CaptureResponse" }, - "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": "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, - "minimum": 0 + "maxLength": 255 }, - "currency": { + "mandate_data": { "allOf": [ { - "$ref": "#/components/schemas/Currency" + "$ref": "#/components/schemas/MandateData" } ], "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 - }, - "routing": { + "setup_future_usage": { "allOf": [ { - "$ref": "#/components/schemas/StraightThroughAlgorithm" + "$ref": "#/components/schemas/FutureUsage" } ], "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" - ], + "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": { + "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": { @@ -15900,16 +14664,24 @@ ], "nullable": true }, - "authentication_type": { + "payment_method": { + "$ref": "#/components/schemas/PaymentMethod" + }, + "payment_method_data": { "allOf": [ { - "$ref": "#/components/schemas/AuthenticationType" + "$ref": "#/components/schemas/PaymentMethodDataResponseWithBilling" } ], - "default": "three_ds", "nullable": true }, - "billing": { + "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" @@ -15917,275 +14689,439 @@ ], "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": { + "billing": { "allOf": [ { - "$ref": "#/components/schemas/CustomerDetails" + "$ref": "#/components/schemas/Address" } ], "nullable": true }, - "customer_id": { + "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": "The identifier for the customer", - "example": "cus_y3oqhf46pyzuxjbcn2giaqnb44", + "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": 64, - "minLength": 1 + "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 + "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 }, - "description": { + "phone": { "type": "string", - "description": "A description for the payment", - "example": "It's my first payment 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 }, "return_url": { "type": "string", - "description": "The URL to which you want the user to be redirected after the completion of the payment operation", + "description": "The URL to redirect after the completion of the operation", "example": "https://hyperswitch.io", "nullable": true }, - "setup_future_usage": { + "authentication_type": { "allOf": [ { - "$ref": "#/components/schemas/FutureUsage" + "$ref": "#/components/schemas/AuthenticationType" } ], + "default": "three_ds", "nullable": true }, - "payment_method_data": { + "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/PaymentMethodDataRequest" + "$ref": "#/components/schemas/NextActionData" } ], "nullable": true }, - "payment_method": { + "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 + }, + "unified_code": { + "type": "string", + "description": "error code unified across the connectors is received here if there was an error while calling connector", + "nullable": true + }, + "unified_message": { + "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/PaymentMethod" + "$ref": "#/components/schemas/PaymentExperience" } ], "nullable": true }, - "payment_token": { + "payment_method_type": { + "allOf": [ + { + "$ref": "#/components/schemas/PaymentMethodType" + } + ], + "nullable": true + }, + "connector_label": { "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": "The connector used for this payment along with the country and business details", + "example": "stripe_US_food", "nullable": true }, - "shipping": { + "business_country": { "allOf": [ { - "$ref": "#/components/schemas/Address" + "$ref": "#/components/schemas/CountryAlpha2" } ], "nullable": true }, - "statement_descriptor_name": { + "business_label": { "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 + "description": "The business label of merchant for this payment", + "nullable": true }, - "statement_descriptor_suffix": { + "business_sub_label": { "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 + "description": "The business_sub_label for this payment", + "nullable": true }, - "order_details": { + "allowed_payment_method_types": { "type": "array", "items": { - "$ref": "#/components/schemas/OrderDetailsWithAmount" + "$ref": "#/components/schemas/PaymentMethodType" }, - "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": "Allowed Payment Method Types for a given PaymentIntent", "nullable": true }, - "mandate_data": { + "ephemeral_key": { "allOf": [ { - "$ref": "#/components/schemas/MandateData" + "$ref": "#/components/schemas/EphemeralKeyCreateResponse" } ], "nullable": true }, - "customer_acceptance": { + "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/CustomerAcceptance" + "$ref": "#/components/schemas/FrmMessage" } ], "nullable": true }, - "browser_info": { + "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/BrowserInformation" + "$ref": "#/components/schemas/ConnectorMetadata" } ], "nullable": true }, - "payment_experience": { + "feature_metadata": { "allOf": [ { - "$ref": "#/components/schemas/PaymentExperience" + "$ref": "#/components/schemas/FeatureMetadata" } ], "nullable": true }, - "payment_method_type": { + "reference_id": { + "type": "string", + "description": "reference(Identifier) to the payment at connector side", + "example": "993672945374576J", + "nullable": true + }, + "payment_link": { "allOf": [ { - "$ref": "#/components/schemas/PaymentMethodType" + "$ref": "#/components/schemas/PaymentLinkResponse" } ], "nullable": true }, - "merchant_connector_details": { + "profile_id": { + "type": "string", + "description": "The business profile that is associated with this payment", + "nullable": true + }, + "surcharge_details": { "allOf": [ { - "$ref": "#/components/schemas/MerchantConnectorDetailsWrap" + "$ref": "#/components/schemas/RequestSurchargeDetails" } ], "nullable": true }, - "allowed_payment_method_types": { + "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/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 + }, + "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 }, - "connector_metadata": { + "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" }, @@ -17305,7 +16241,9 @@ "required": [ "client_id", "client_name", - "client_profile_id" + "client_profile_id", + "transaction_currency_code", + "transaction_amount" ], "properties": { "client_id": { @@ -17319,6 +16257,21 @@ "client_profile_id": { "type": "string", "description": "Paze Client Profile ID" + }, + "transaction_currency_code": { + "$ref": "#/components/schemas/Currency" + }, + "transaction_amount": { + "type": "string", + "description": "The transaction amount", + "example": "38.02" + }, + "email_address": { + "type": "string", + "description": "Email Address", + "example": "johntest@test.com", + "nullable": true, + "maxLength": 255 } } }, @@ -18092,19 +17045,18 @@ } } }, - "RefundAggregateResponse": { + "RefundErrorDetails": { "type": "object", "required": [ - "status_with_count" + "code", + "message" ], "properties": { - "status_with_count": { - "type": "object", - "description": "The list of refund status with their count", - "additionalProperties": { - "type": "integer", - "format": "int64" - } + "code": { + "type": "string" + }, + "message": { + "type": "string" } } }, @@ -18298,89 +17250,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 +17373,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": [ @@ -21000,7 +20005,8 @@ } } } - ] + ], + "description": "Hyperswitch supports SDK integration with Apple Pay and Google Pay wallets. For other wallets, we integrate with their respective connectors, redirecting the customer to the connector for wallet payments. As a result, we don’t receive any payment method data in the confirm call for payments made through other wallets." }, "WeChatPay": { "type": "object" diff --git a/api-reference-v2/rust_locker_open_api_spec.yml b/api-reference-v2/rust_locker_open_api_spec.yml index 729886d9cd0d..17a19fec44da 100644 --- a/api-reference-v2/rust_locker_open_api_spec.yml +++ b/api-reference-v2/rust_locker_open_api_spec.yml @@ -2,16 +2,16 @@ openapi: "3.0.2" info: title: Tartarus - OpenAPI 3.0 description: |- - This the the open API 3.0 specification for the card locker. + This is the OpenAPI 3.0 specification for the card locker. This is used by the [hyperswitch](https://github.com/juspay/hyperswitch) for storing card information securely. version: "1.0" tags: - name: Key Custodian description: API used to initialize the locker after deployment. - name: Data - description: CRUD APIs to for working with data to be stored in the locker + description: CRUD APIs for working with data to be stored in the locker - name: Cards - description: CRUD APIs to for working with cards data to be stored in the locker (deprecated) + description: CRUD APIs for working with cards data to be stored in the locker (deprecated) paths: /custodian/key1: post: @@ -39,7 +39,7 @@ paths: tags: - Key Custodian summary: Provide Key 2 - description: Provide the first key to unlock the locker + description: Provide the second key to unlock the locker operationId: setKey2 requestBody: description: Provide key 2 to unlock the locker diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index 9374acb024d1..f86664d459f5 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -3952,12 +3952,12 @@ } }, { - "name": "status", + "name": "enable", "in": "query", - "description": "Boolean value for mentioning the expected state of dynamic routing", + "description": "Feature to enable for success based routing", "required": true, "schema": { - "type": "boolean" + "$ref": "#/components/schemas/SuccessBasedRoutingFeatures" } } ], @@ -3998,87 +3998,6 @@ ] } }, - "/account/:account_id/business_profile/:profile_id/dynamic_routing/success_based/config/:algorithm_id": { - "patch": { - "tags": [ - "Routing" - ], - "summary": "Routing - Update config for success based dynamic routing", - "description": "Update config for success based dynamic routing", - "operationId": "Update configs for success based dynamic routing algorithm", - "parameters": [ - { - "name": "account_id", - "in": "path", - "description": "Merchant id", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "profile_id", - "in": "path", - "description": "The unique identifier for a profile", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "algorithm_id", - "in": "path", - "description": "The unique identifier for routing algorithm", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessBasedRoutingConfig" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Routing Algorithm updated", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoutingDictionaryRecord" - } - } - } - }, - "400": { - "description": "Request body is malformed" - }, - "403": { - "description": "Forbidden" - }, - "404": { - "description": "Resource missing" - }, - "422": { - "description": "Unprocessable request" - }, - "500": { - "description": "Internal server error" - } - }, - "security": [ - { - "admin_api_key": [] - } - ] - } - }, "/blocklist": { "delete": { "tags": [ @@ -9458,23 +9377,6 @@ "ZWL" ] }, - "CurrentBlockThreshold": { - "type": "object", - "properties": { - "duration_in_mins": { - "type": "integer", - "format": "int64", - "nullable": true, - "minimum": 0 - }, - "max_total_count": { - "type": "integer", - "format": "int64", - "nullable": true, - "minimum": 0 - } - } - }, "CustomerAcceptance": { "type": "object", "description": "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.", @@ -14317,9 +14219,7 @@ "minimum": 0 }, "amount": { - "type": "integer", - "format": "int64", - "description": "the amount per quantity of product" + "$ref": "#/components/schemas/MinorUnit" }, "requires_shipping": { "type": "boolean", @@ -21086,7 +20986,9 @@ "required": [ "client_id", "client_name", - "client_profile_id" + "client_profile_id", + "transaction_currency_code", + "transaction_amount" ], "properties": { "client_id": { @@ -21100,6 +21002,21 @@ "client_profile_id": { "type": "string", "description": "Paze Client Profile ID" + }, + "transaction_currency_code": { + "$ref": "#/components/schemas/Currency" + }, + "transaction_amount": { + "type": "string", + "description": "The transaction amount", + "example": "38.02" + }, + "email_address": { + "type": "string", + "description": "Email Address", + "example": "johntest@test.com", + "nullable": true, + "maxLength": 255 } } }, @@ -21907,22 +21824,6 @@ } } }, - "RefundAggregateResponse": { - "type": "object", - "required": [ - "status_with_count" - ], - "properties": { - "status_with_count": { - "type": "object", - "description": "The list of refund status with their count", - "additionalProperties": { - "type": "integer", - "format": "int64" - } - } - } - }, "RefundListRequest": { "allOf": [ { @@ -23624,80 +23525,14 @@ "destination" ] }, - "SuccessBasedRoutingConfig": { - "type": "object", - "properties": { - "params": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SuccessBasedRoutingConfigParams" - }, - "nullable": true - }, - "config": { - "allOf": [ - { - "$ref": "#/components/schemas/SuccessBasedRoutingConfigBody" - } - ], - "nullable": true - } - } - }, - "SuccessBasedRoutingConfigBody": { - "type": "object", - "properties": { - "min_aggregates_size": { - "type": "integer", - "format": "int32", - "nullable": true, - "minimum": 0 - }, - "default_success_rate": { - "type": "number", - "format": "double", - "nullable": true - }, - "max_aggregates_size": { - "type": "integer", - "format": "int32", - "nullable": true, - "minimum": 0 - }, - "current_block_threshold": { - "allOf": [ - { - "$ref": "#/components/schemas/CurrentBlockThreshold" - } - ], - "nullable": true - } - } - }, - "SuccessBasedRoutingConfigParams": { + "SuccessBasedRoutingFeatures": { "type": "string", "enum": [ - "PaymentMethod", - "PaymentMethodType", - "Currency", - "AuthenticationType" + "metrics", + "dynamic_connector_selection", + "none" ] }, - "SuccessBasedRoutingUpdateConfigQuery": { - "type": "object", - "required": [ - "algorithm_id", - "profile_id" - ], - "properties": { - "algorithm_id": { - "type": "string" - }, - "profile_id": { - "type": "string" - } - } - }, "SurchargeDetailsResponse": { "type": "object", "required": [ @@ -23961,11 +23796,11 @@ "ToggleSuccessBasedRoutingQuery": { "type": "object", "required": [ - "status" + "enable" ], "properties": { - "status": { - "type": "boolean" + "enable": { + "$ref": "#/components/schemas/SuccessBasedRoutingFeatures" } } }, @@ -24880,7 +24715,8 @@ } } } - ] + ], + "description": "Hyperswitch supports SDK integration with Apple Pay and Google Pay wallets. For other wallets, we integrate with their respective connectors, redirecting the customer to the connector for wallet payments. As a result, we don’t receive any payment method data in the confirm call for payments made through other wallets." }, "WeChatPay": { "type": "object" diff --git a/api-reference/rust_locker_open_api_spec.yml b/api-reference/rust_locker_open_api_spec.yml index 729886d9cd0d..17a19fec44da 100644 --- a/api-reference/rust_locker_open_api_spec.yml +++ b/api-reference/rust_locker_open_api_spec.yml @@ -2,16 +2,16 @@ openapi: "3.0.2" info: title: Tartarus - OpenAPI 3.0 description: |- - This the the open API 3.0 specification for the card locker. + This is the OpenAPI 3.0 specification for the card locker. This is used by the [hyperswitch](https://github.com/juspay/hyperswitch) for storing card information securely. version: "1.0" tags: - name: Key Custodian description: API used to initialize the locker after deployment. - name: Data - description: CRUD APIs to for working with data to be stored in the locker + description: CRUD APIs for working with data to be stored in the locker - name: Cards - description: CRUD APIs to for working with cards data to be stored in the locker (deprecated) + description: CRUD APIs for working with cards data to be stored in the locker (deprecated) paths: /custodian/key1: post: @@ -39,7 +39,7 @@ paths: tags: - Key Custodian summary: Provide Key 2 - description: Provide the first key to unlock the locker + description: Provide the second key to unlock the locker operationId: setKey2 requestBody: description: Provide key 2 to unlock the locker diff --git a/aws/hyperswitch_aws_setup.sh b/aws/hyperswitch_aws_setup.sh index dd71b698e93e..e3af286a58da 100644 --- a/aws/hyperswitch_aws_setup.sh +++ b/aws/hyperswitch_aws_setup.sh @@ -38,12 +38,11 @@ echo "Creating Security Group for Application..." export EC2_SG="application-sg" -echo `(aws ec2 create-security-group \ +echo "$(aws ec2 create-security-group \ --region $REGION \ --group-name $EC2_SG \ --description "Security Group for Hyperswitch EC2 instance" \ ---tag-specifications "ResourceType=security-group,Tags=[{Key=ManagedBy,Value=hyperswitch}]" \ -)` +--tag-specifications "ResourceType=security-group,Tags=[{Key=ManagedBy,Value=hyperswitch}]")" export APP_SG_ID=$(aws ec2 describe-security-groups --group-names $EC2_SG --region $REGION --output text --query 'SecurityGroups[0].GroupId') @@ -51,24 +50,23 @@ echo "Security Group for Application CREATED.\n" echo "Creating Security Group ingress for port 80..." -echo `aws ec2 authorize-security-group-ingress \ +echo "$(aws ec2 authorize-security-group-ingress \ --group-id $APP_SG_ID \ --protocol tcp \ --port 80 \ --cidr 0.0.0.0/0 \ ---region $REGION` +--region $REGION)" echo "Security Group ingress for port 80 CREATED.\n" - echo "Creating Security Group ingress for port 22..." -echo `aws ec2 authorize-security-group-ingress \ +echo "$(aws ec2 authorize-security-group-ingress \ --group-id $APP_SG_ID \ --protocol tcp \ --port 22 \ --cidr 0.0.0.0/0 \ ---region $REGION` +--region $REGION)" echo "Security Group ingress for port 22 CREATED.\n" @@ -78,11 +76,11 @@ echo "Security Group ingress for port 22 CREATED.\n" echo "Creating Security Group for Elasticache..." export REDIS_GROUP_NAME=redis-sg -echo `aws ec2 create-security-group \ +echo "$(aws ec2 create-security-group \ --group-name $REDIS_GROUP_NAME \ --description "SG attached to elasticache" \ --tag-specifications "ResourceType=security-group,Tags=[{Key=ManagedBy,Value=hyperswitch}]" \ ---region $REGION` +--region $REGION)" echo "Security Group for Elasticache CREATED.\n" @@ -91,12 +89,12 @@ echo "Creating Inbound rules for Redis..." export REDIS_SG_ID=$(aws ec2 describe-security-groups --group-names $REDIS_GROUP_NAME --region $REGION --output text --query 'SecurityGroups[0].GroupId') # CREATE INBOUND RULES -echo `aws ec2 authorize-security-group-ingress \ +echo "$(aws ec2 authorize-security-group-ingress \ --group-id $REDIS_SG_ID \ --protocol tcp \ --port 6379 \ --source-group $EC2_SG \ ---region $REGION` +--region $REGION)" echo "Inbound rules for Redis CREATED.\n" @@ -105,11 +103,11 @@ echo "Inbound rules for Redis CREATED.\n" echo "Creating Security Group for RDS..." export RDS_GROUP_NAME=rds-sg -echo `aws ec2 create-security-group \ +echo "$(aws ec2 create-security-group \ --group-name $RDS_GROUP_NAME \ --description "SG attached to RDS" \ --tag-specifications "ResourceType=security-group,Tags=[{Key=ManagedBy,Value=hyperswitch}]" \ ---region $REGION` +--region $REGION)" echo "Security Group for RDS CREATED.\n" @@ -118,21 +116,21 @@ echo "Creating Inbound rules for RDS..." export RDS_SG_ID=$(aws ec2 describe-security-groups --group-names $RDS_GROUP_NAME --region $REGION --output text --query 'SecurityGroups[0].GroupId') # CREATE INBOUND RULES -echo `aws ec2 authorize-security-group-ingress \ +echo "$(aws ec2 authorize-security-group-ingress \ --group-id $RDS_SG_ID \ --protocol tcp \ --port 5432 \ --source-group $EC2_SG \ ---region $REGION` +--region $REGION)" echo "Inbound rules for RDS CREATED.\n" -echo `aws ec2 authorize-security-group-ingress \ +echo "$(aws ec2 authorize-security-group-ingress \ --group-id $RDS_SG_ID \ --protocol tcp \ --port 5432 \ --cidr 0.0.0.0/0 \ - --region $REGION` + --region $REGION)" echo "Inbound rules for RDS (from any IP) CREATED.\n" @@ -140,7 +138,7 @@ echo "Creating Elasticache with Redis engine..." export CACHE_CLUSTER_ID=hyperswitch-cluster -echo `aws elasticache create-cache-cluster \ +echo "$(aws elasticache create-cache-cluster \ --cache-cluster-id $CACHE_CLUSTER_ID \ --cache-node-type cache.t3.medium \ --engine redis \ @@ -148,14 +146,14 @@ echo `aws elasticache create-cache-cluster \ --security-group-ids $REDIS_SG_ID \ --engine-version 7.0 \ --tags "Key=ManagedBy,Value=hyperswitch" \ ---region $REGION` +--region $REGION)" echo "Elasticache with Redis engine CREATED.\n" echo "Creating RDS with PSQL..." export DB_INSTANCE_ID=hyperswitch-db -echo `aws rds create-db-instance \ +echo "$(aws rds create-db-instance \ --db-instance-identifier $DB_INSTANCE_ID\ --db-instance-class db.t3.micro \ --engine postgres \ @@ -166,7 +164,7 @@ echo `aws rds create-db-instance \ --region $REGION \ --db-name hyperswitch_db \ --tags "Key=ManagedBy,Value=hyperswitch" \ - --vpc-security-group-ids $RDS_SG_ID` + --vpc-security-group-ids $RDS_SG_ID)" echo "RDS with PSQL CREATED.\n" @@ -308,17 +306,17 @@ echo "EC2 instance launched.\n" echo "Add Tags to EC2 instance..." -echo `aws ec2 create-tags \ +echo "$(aws ec2 create-tags \ --resources $HYPERSWITCH_INSTANCE_ID \ --tags "Key=Name,Value=hyperswitch-router" \ ---region $REGION` +--region $REGION)" echo "Tag added to EC2 instance.\n" -echo `aws ec2 create-tags \ +echo "$(aws ec2 create-tags \ --resources $HYPERSWITCH_INSTANCE_ID \ --tags "Key=ManagedBy,Value=hyperswitch" \ ---region $REGION` +--region $REGION)" echo "ManagedBy tag added to EC2 instance.\n" diff --git a/aws/hyperswitch_cleanup_setup.sh b/aws/hyperswitch_cleanup_setup.sh index 383f23d5bd00..df75623746c9 100644 --- a/aws/hyperswitch_cleanup_setup.sh +++ b/aws/hyperswitch_cleanup_setup.sh @@ -45,7 +45,7 @@ for cluster_arn in $ALL_ELASTIC_CACHE; do if [[ $? -eq 0 ]]; then echo -n "Delete $cluster_id (Y/n)? " if yes_or_no; then - echo `aws elasticache delete-cache-cluster --region $REGION --cache-cluster-id $cluster_id` + echo "$(aws elasticache delete-cache-cluster --region $REGION --cache-cluster-id $cluster_id)" fi fi done @@ -59,7 +59,7 @@ echo -n "Deleting ( $ALL_KEY_PAIRS ) key pairs? (Y/n)?" if yes_or_no; then for KEY_ID in $ALL_KEY_PAIRS; do - echo `aws ec2 delete-key-pair --key-pair-id $KEY_ID --region $REGION` + echo "$(aws ec2 delete-key-pair --key-pair-id $KEY_ID --region $REGION)" done fi @@ -78,7 +78,7 @@ echo -n "Terminating ( $ALL_INSTANCES ) instances? (Y/n)?" if yes_or_no; then for INSTANCE_ID in $ALL_INSTANCES; do - echo `aws ec2 terminate-instances --instance-ids $INSTANCE_ID --region $REGION` + echo "$(aws ec2 terminate-instances --instance-ids $INSTANCE_ID --region $REGION)" done fi @@ -105,15 +105,15 @@ for resource_id in $ALL_DB_RESOURCES; do echo -n "Create a snapshot before deleting ( $DB_INSTANCE_ID ) the database (Y/n)? " if yes_or_no; then - echo `aws rds delete-db-instance \ + echo "$(aws rds delete-db-instance \ --db-instance-identifier $DB_INSTANCE_ID \ --region $REGION \ - --final-db-snapshot-identifier hyperswitch-db-snapshot-`date +%s`` + --final-db-snapshot-identifier hyperswitch-db-snapshot-$(date +%s))" else - echo `aws rds delete-db-instance \ + echo "$(aws rds delete-db-instance \ --region $REGION \ --db-instance-identifier $DB_INSTANCE_ID \ - --skip-final-snapshot` + --skip-final-snapshot)" fi fi fi diff --git a/config/config.example.toml b/config/config.example.toml index d6ac28548af9..ef7dcc560850 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -206,6 +206,7 @@ digitalvirgo.base_url = "https://dcb-integration-service-sandbox-external.stagin dlocal.base_url = "https://sandbox.dlocal.com/" dummyconnector.base_url = "http://localhost:8080/dummy-connector" ebanx.base_url = "https://sandbox.ebanxpay.com/" +elavon.base_url = "https://api.demo.convergepay.com" fiserv.base_url = "https://cert.api.fiservapps.com/" fiservemea.base_url = "https://prod.emea.api.fiservapps.com/sandbox" fiuu.base_url = "https://sandbox.merchant.razer.com/" @@ -219,6 +220,7 @@ gpayments.base_url = "https://{{merchant_endpoint_prefix}}-test.api.as1.gpayment helcim.base_url = "https://api.helcim.com/" iatapay.base_url = "https://sandbox.iata-pay.iata.org/api/v1" itaubank.base_url = "https://sandbox.devportal.itau.com.br/" +jpmorgan.base_url = "https://api-mock.payments.jpmorgan.com/api/v2" klarna.base_url = "https://api{{klarna_region}}.playground.klarna.com/" mifinity.base_url = "https://demo.mifinity.com/" mollie.base_url = "https://api.mollie.com/v2/" @@ -395,6 +397,7 @@ password_validity_in_days = 90 # Number of days after which password shoul two_factor_auth_expiry_in_secs = 300 # Number of seconds after which 2FA should be done again if doing update/change from inside totp_issuer_name = "Hyperswitch" # Name of the issuer for TOTP base_url = "" # Base url used for user specific redirects and emails +force_two_factor_auth = false # Whether to force two factor authentication for all users #tokenization configuration which describe token lifetime and payment method for specific connector [tokenization] @@ -741,7 +744,7 @@ enabled = false global_tenant = { schema = "public", redis_key_prefix = "", clickhouse_database = "default"} [multitenancy.tenants] -public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default" } # schema -> Postgres db schema, redis_key_prefix -> redis key distinguisher, base_url -> url of the tenant +public = { base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default" } # schema -> Postgres db schema, redis_key_prefix -> redis key distinguisher, base_url -> url of the tenant [user_auth_methods] encryption_key = "" # Encryption key used for encrypting data in user_authentication_methods table diff --git a/config/deployments/env_specific.toml b/config/deployments/env_specific.toml index fd25b18fd8cd..fa0c0484a773 100644 --- a/config/deployments/env_specific.toml +++ b/config/deployments/env_specific.toml @@ -305,7 +305,7 @@ enabled = false global_tenant = { schema = "public", redis_key_prefix = "", clickhouse_database = "default"} [multitenancy.tenants] -public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default" } +public = { base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default" } [user_auth_methods] encryption_key = "user_auth_table_encryption_key" # Encryption key used for encrypting data in user_authentication_methods table diff --git a/config/deployments/integration_test.toml b/config/deployments/integration_test.toml index dafc6048154e..ebc1e36d1591 100644 --- a/config/deployments/integration_test.toml +++ b/config/deployments/integration_test.toml @@ -48,6 +48,7 @@ digitalvirgo.base_url = "https://dcb-integration-service-sandbox-external.stagin dlocal.base_url = "https://sandbox.dlocal.com/" dummyconnector.base_url = "http://localhost:8080/dummy-connector" ebanx.base_url = "https://sandbox.ebanxpay.com/" +elavon.base_url = "https://api.demo.convergepay.com" fiserv.base_url = "https://cert.api.fiservapps.com/" fiservemea.base_url = "https://prod.emea.api.fiservapps.com/sandbox" fiuu.base_url = "https://sandbox.merchant.razer.com/" @@ -61,6 +62,7 @@ gpayments.base_url = "https://{{merchant_endpoint_prefix}}-test.api.as1.gpayment helcim.base_url = "https://api.helcim.com/" iatapay.base_url = "https://sandbox.iata-pay.iata.org/api/v1" itaubank.base_url = "https://sandbox.devportal.itau.com.br/" +jpmorgan.base_url = "https://api-mock.payments.jpmorgan.com/api/v2" klarna.base_url = "https://api{{klarna_region}}.playground.klarna.com/" mifinity.base_url = "https://demo.mifinity.com/" mollie.base_url = "https://api.mollie.com/v2/" @@ -138,6 +140,7 @@ password_validity_in_days = 90 two_factor_auth_expiry_in_secs = 300 totp_issuer_name = "Hyperswitch Integ" base_url = "https://integ.hyperswitch.io" +force_two_factor_auth = false [frm] enabled = true @@ -196,7 +199,7 @@ alfamart = { country = "ID", currency = "IDR" } ali_pay = { country = "AU,JP,HK,SG,MY,TH,ES,GB,SE,NO,AT,NL,DE,CY,CH,BE,FR,DK,FI,RO,MT,SI,GR,PT,IE,IT,CA,US", currency = "USD,EUR,GBP,JPY,AUD,SGD,CHF,SEK,NOK,NZD,THB,HKD,CAD" } ali_pay_hk = { country = "HK", currency = "HKD" } alma = { country = "FR", currency = "EUR" } -apple_pay = { country = "AU,NZ,CN,JP,HK,SG,MY,BH,AE,KW,BR,ES,GB,SE,NO,AT,NL,DE,HU,CY,LU,CH,BE,FR,DK,FI,RO,HR,LI,UA,MT,SI,GR,PT,IE,CZ,EE,LT,LV,IT,PL,IS,CA,US", currency = "AUD,CHF,CAD,EUR,GBP,HKD,SGD,USD" } +apple_pay = { country = "AU,NZ,CN,JP,HK,SG,MY,BH,AE,KW,BR,ES,GB,SE,NO,AT,NL,DE,HU,CY,LU,CH,BE,FR,DK,FI,RO,HR,LI,UA,MT,SI,GR,PT,IE,CZ,EE,LT,LV,IT,PL,IS,CA,US", currency = "AUD,CHF,CAD,EUR,GBP,HKD,SGD,USD,MYR" } atome = { country = "MY,SG", currency = "MYR,SGD" } bacs = { country = "GB", currency = "GBP" } bancontact_card = { country = "BE", currency = "EUR" } @@ -341,6 +344,9 @@ red_pagos = { country = "UY", currency = "UYU" } [pm_filters.zsl] local_bank_transfer = { country = "CN", currency = "CNY" } +[pm_filters.fiuu] +duit_now = { country ="MY", currency = "MYR" } + [payout_method_filters.adyenplatform] sepa = { country = "ES,SK,AT,NL,DE,BE,FR,FI,PT,IE,EE,LT,LV,IT,CZ,DE,HU,NO,PL,SE,GB,CH" , currency = "EUR,CZK,DKK,HUF,NOK,PLN,SEK,GBP,CHF" } @@ -391,4 +397,4 @@ connector_list = "" card_networks = "Visa, AmericanExpress, Mastercard" [network_tokenization_supported_connectors] -connector_list = "cybersource" \ No newline at end of file +connector_list = "cybersource" diff --git a/config/deployments/production.toml b/config/deployments/production.toml index caf8c0305683..ef1ee42b9e67 100644 --- a/config/deployments/production.toml +++ b/config/deployments/production.toml @@ -52,6 +52,7 @@ digitalvirgo.base_url = "https://dcb-integration-service-sandbox-external.stagin dlocal.base_url = "https://sandbox.dlocal.com/" dummyconnector.base_url = "http://localhost:8080/dummy-connector" ebanx.base_url = "https://sandbox.ebanxpay.com/" +elavon.base_url = "https://api.convergepay.com" fiserv.base_url = "https://cert.api.fiservapps.com/" fiservemea.base_url = "https://prod.emea.api.fiservapps.com" fiuu.base_url = "https://pay.merchant.razer.com/" @@ -65,6 +66,7 @@ gpayments.base_url = "https://{{merchant_endpoint_prefix}}-test.api.as1.gpayment helcim.base_url = "https://api.helcim.com/" iatapay.base_url = "https://iata-pay.iata.org/api/v1" itaubank.base_url = "https://secure.api.itau/" +jpmorgan.base_url = "https://api-ms.payments.jpmorgan.com/api/v2" klarna.base_url = "https://api{{klarna_region}}.klarna.com/" mifinity.base_url = "https://secure.mifinity.com/" mollie.base_url = "https://api.mollie.com/v2/" @@ -145,6 +147,7 @@ password_validity_in_days = 90 two_factor_auth_expiry_in_secs = 300 totp_issuer_name = "Hyperswitch Production" base_url = "https://live.hyperswitch.io" +force_two_factor_auth = false [frm] enabled = false @@ -209,7 +212,7 @@ alfamart = { country = "ID", currency = "IDR" } ali_pay = { country = "AU,JP,HK,SG,MY,TH,ES,GB,SE,NO,AT,NL,DE,CY,CH,BE,FR,DK,FI,RO,MT,SI,GR,PT,IE,IT,CA,US", currency = "USD,EUR,GBP,JPY,AUD,SGD,CHF,SEK,NOK,NZD,THB,HKD,CAD" } ali_pay_hk = { country = "HK", currency = "HKD" } alma = { country = "FR", currency = "EUR" } -apple_pay = { country = "AE,AM,AR,AT,AU,AZ,BE,BG,BH,BR,BY,CA,CH,CN,CO,CR,CY,CZ,DE,DK,EE,ES,FI,FO,FR,GB,GE,GG,GL,GR,HK,HR,HU,IE,IL,IM,IS,IT,JE,JO,JP,KW,KZ,LI,LT,LU,LV,MC,MD,ME,MO,MT,MX,MY,NL,NO,NZ,PE,PL,PS,PT,QA,RO,RS,SA,SE,SG,SI,SK,SM,TW,UA,GB,UM,US", currency = "AUD,CHF,CAD,EUR,GBP,HKD,SGD,USD" } +apple_pay = { country = "AE,AM,AR,AT,AU,AZ,BE,BG,BH,BR,BY,CA,CH,CN,CO,CR,CY,CZ,DE,DK,EE,ES,FI,FO,FR,GB,GE,GG,GL,GR,HK,HR,HU,IE,IL,IM,IS,IT,JE,JO,JP,KW,KZ,LI,LT,LU,LV,MC,MD,ME,MO,MT,MX,MY,NL,NO,NZ,PE,PL,PS,PT,QA,RO,RS,SA,SE,SG,SI,SK,SM,TW,UA,GB,UM,US", currency = "AUD,CHF,CAD,EUR,GBP,HKD,SGD,USD,MYR" } atome = { country = "MY,SG", currency = "MYR,SGD" } bacs = { country = "GB", currency = "GBP" } bancontact_card = { country = "BE", currency = "EUR" } @@ -354,6 +357,10 @@ red_pagos = { country = "UY", currency = "UYU" } [pm_filters.zsl] local_bank_transfer = { country = "CN", currency = "CNY" } + +[pm_filters.fiuu] +duit_now = { country ="MY", currency = "MYR" } + [payout_method_filters.adyenplatform] sepa = { country = "ES,SK,AT,NL,DE,BE,FR,FI,PT,IE,EE,LT,LV,IT,CZ,DE,HU,NO,PL,SE,GB,CH" , currency = "EUR,CZK,DKK,HUF,NOK,PLN,SEK,GBP,CHF" } @@ -404,4 +411,4 @@ connector_list = "" card_networks = "Visa, AmericanExpress, Mastercard" [network_tokenization_supported_connectors] -connector_list = "cybersource" \ No newline at end of file +connector_list = "cybersource" diff --git a/config/deployments/sandbox.toml b/config/deployments/sandbox.toml index 6cc1193ab558..a09dba1a9a66 100644 --- a/config/deployments/sandbox.toml +++ b/config/deployments/sandbox.toml @@ -52,6 +52,7 @@ digitalvirgo.base_url = "https://dcb-integration-service-sandbox-external.stagin dlocal.base_url = "https://sandbox.dlocal.com/" dummyconnector.base_url = "http://localhost:8080/dummy-connector" ebanx.base_url = "https://sandbox.ebanxpay.com/" +elavon.base_url = "https://api.demo.convergepay.com" fiserv.base_url = "https://cert.api.fiservapps.com/" fiservemea.base_url = "https://prod.emea.api.fiservapps.com/sandbox" fiuu.base_url = "https://sandbox.merchant.razer.com/" @@ -65,6 +66,7 @@ gpayments.base_url = "https://{{merchant_endpoint_prefix}}-test.api.as1.gpayment helcim.base_url = "https://api.helcim.com/" iatapay.base_url = "https://sandbox.iata-pay.iata.org/api/v1" itaubank.base_url = "https://sandbox.devportal.itau.com.br/" +jpmorgan.base_url = "https://api-mock.payments.jpmorgan.com/api/v2" klarna.base_url = "https://api{{klarna_region}}.playground.klarna.com/" mifinity.base_url = "https://demo.mifinity.com/" mollie.base_url = "https://api.mollie.com/v2/" @@ -145,6 +147,7 @@ password_validity_in_days = 90 two_factor_auth_expiry_in_secs = 300 totp_issuer_name = "Hyperswitch Sandbox" base_url = "https://app.hyperswitch.io" +force_two_factor_auth = false [frm] enabled = true @@ -212,7 +215,7 @@ alfamart = { country = "ID", currency = "IDR" } ali_pay = { country = "AU,JP,HK,SG,MY,TH,ES,GB,SE,NO,AT,NL,DE,CY,CH,BE,FR,DK,FI,RO,MT,SI,GR,PT,IE,IT,CA,US", currency = "USD,EUR,GBP,JPY,AUD,SGD,CHF,SEK,NOK,NZD,THB,HKD,CAD" } ali_pay_hk = { country = "HK", currency = "HKD" } alma = { country = "FR", currency = "EUR" } -apple_pay = { country = "AU,NZ,CN,JP,HK,SG,MY,BH,AE,KW,BR,ES,GB,SE,NO,AT,NL,DE,HU,CY,LU,CH,BE,FR,DK,FI,RO,HR,LI,UA,MT,SI,GR,PT,IE,CZ,EE,LT,LV,IT,PL,IS,CA,US", currency = "AUD,CHF,CAD,EUR,GBP,HKD,SGD,USD" } +apple_pay = { country = "AU,NZ,CN,JP,HK,SG,MY,BH,AE,KW,BR,ES,GB,SE,NO,AT,NL,DE,HU,CY,LU,CH,BE,FR,DK,FI,RO,HR,LI,UA,MT,SI,GR,PT,IE,CZ,EE,LT,LV,IT,PL,IS,CA,US", currency = "AUD,CHF,CAD,EUR,GBP,HKD,SGD,USD,MYR" } atome = { country = "MY,SG", currency = "MYR,SGD" } bacs = { country = "GB", currency = "GBP" } bancontact_card = { country = "BE", currency = "EUR" } @@ -340,10 +343,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" } @@ -358,6 +361,10 @@ red_pagos = { country = "UY", currency = "UYU" } [pm_filters.zsl] local_bank_transfer = { country = "CN", currency = "CNY" } + +[pm_filters.fiuu] +duit_now = { country ="MY", currency = "MYR" } + [payout_method_filters.adyenplatform] sepa = { country = "ES,SK,AT,NL,DE,BE,FR,FI,PT,IE,EE,LT,LV,IT,CZ,DE,HU,NO,PL,SE,GB,CH" , currency = "EUR,CZK,DKK,HUF,NOK,PLN,SEK,GBP,CHF" } diff --git a/config/development.toml b/config/development.toml index 8e5d9582e2f7..46d6378f0832 100644 --- a/config/development.toml +++ b/config/development.toml @@ -118,6 +118,7 @@ cards = [ "dlocal", "dummyconnector", "ebanx", + "elavon", "fiserv", "fiservemea", "fiuu", @@ -129,6 +130,7 @@ cards = [ "helcim", "iatapay", "itaubank", + "jpmorgan", "mollie", "multisafepay", "netcetera", @@ -216,6 +218,7 @@ digitalvirgo.base_url = "https://dcb-integration-service-sandbox-external.stagin dlocal.base_url = "https://sandbox.dlocal.com/" dummyconnector.base_url = "http://localhost:8080/dummy-connector" ebanx.base_url = "https://sandbox.ebanxpay.com/" +elavon.base_url = "https://api.demo.convergepay.com" fiserv.base_url = "https://cert.api.fiservapps.com/" fiservemea.base_url = "https://prod.emea.api.fiservapps.com/sandbox" fiuu.base_url = "https://sandbox.merchant.razer.com/" @@ -229,6 +232,7 @@ gpayments.base_url = "https://{{merchant_endpoint_prefix}}-test.api.as1.gpayment helcim.base_url = "https://api.helcim.com/" iatapay.base_url = "https://sandbox.iata-pay.iata.org/api/v1" itaubank.base_url = "https://sandbox.devportal.itau.com.br/" +jpmorgan.base_url = "https://api-mock.payments.jpmorgan.com/api/v2" klarna.base_url = "https://api{{klarna_region}}.playground.klarna.com/" mifinity.base_url = "https://demo.mifinity.com/" mollie.base_url = "https://api.mollie.com/v2/" @@ -316,6 +320,7 @@ password_validity_in_days = 90 two_factor_auth_expiry_in_secs = 300 totp_issuer_name = "Hyperswitch Dev" base_url = "http://localhost:8080" +force_two_factor_auth = false [bank_config.eps] stripe = { banks = "arzte_und_apotheker_bank,austrian_anadi_bank_ag,bank_austria,bankhaus_carl_spangler,bankhaus_schelhammer_und_schattera_ag,bawag_psk_ag,bks_bank_ag,brull_kallmus_bank_ag,btv_vier_lander_bank,capital_bank_grawe_gruppe_ag,dolomitenbank,easybank_ag,erste_bank_und_sparkassen,hypo_alpeadriabank_international_ag,hypo_noe_lb_fur_niederosterreich_u_wien,hypo_oberosterreich_salzburg_steiermark,hypo_tirol_bank_ag,hypo_vorarlberg_bank_ag,hypo_bank_burgenland_aktiengesellschaft,marchfelder_bank,oberbank_ag,raiffeisen_bankengruppe_osterreich,schoellerbank_ag,sparda_bank_wien,volksbank_gruppe,volkskreditbank_ag,vr_bank_braunau" } @@ -383,7 +388,7 @@ open_banking_pis = {currency = "EUR,GBP"} [pm_filters.adyen] google_pay = { country = "AU,NZ,JP,HK,SG,MY,TH,VN,BH,AE,KW,BR,ES,GB,SE,NO,SK,AT,NL,DE,HU,CY,LU,CH,BE,FR,DK,RO,HR,LI,MT,SI,GR,PT,IE,CZ,EE,LT,LV,IT,PL,TR,IS,CA,US", currency = "AED,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BMD,BND,BOB,BRL,BSD,BWP,BYN,BZD,CAD,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HTG,HUF,IDR,ILS,INR,IQD,JMD,JOD,JPY,KES,KGS,KHR,KMF,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LYD,MAD,MDL,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SEK,SGD,SHP,SLE,SOS,SRD,STN,SVC,SZL,THB,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW" } -apple_pay = { country = "AU,NZ,CN,JP,HK,SG,MY,BH,AE,KW,BR,ES,GB,SE,NO,AT,NL,DE,HU,CY,LU,CH,BE,FR,DK,FI,RO,HR,LI,UA,MT,SI,GR,PT,IE,CZ,EE,LT,LV,IT,PL,IS,CA,US", currency = "AUD,CHF,CAD,EUR,GBP,HKD,SGD,USD" } +apple_pay = { country = "AU,NZ,CN,JP,HK,SG,MY,BH,AE,KW,BR,ES,GB,SE,NO,AT,NL,DE,HU,CY,LU,CH,BE,FR,DK,FI,RO,HR,LI,UA,MT,SI,GR,PT,IE,CZ,EE,LT,LV,IT,PL,IS,CA,US", currency = "AUD,CHF,CAD,EUR,GBP,HKD,SGD,USD,MYR" } paypal = { country = "AU,NZ,CN,JP,HK,MY,TH,KR,PH,ID,AE,KW,BR,ES,GB,SE,NO,SK,AT,NL,DE,HU,CY,LU,CH,BE,FR,DK,FI,RO,HR,UA,MT,SI,GI,PT,IE,CZ,EE,LT,LV,IT,PL,IS,CA,US", currency = "AUD,BRL,CAD,CZK,DKK,EUR,HKD,HUF,INR,JPY,MYR,MXN,NZD,NOK,PHP,PLN,RUB,GBP,SGD,SEK,CHF,THB,USD" } mobile_pay = { country = "DK,FI", currency = "DKK,SEK,NOK,EUR" } ali_pay = { country = "AU,JP,HK,SG,MY,TH,ES,GB,SE,NO,AT,NL,DE,CY,CH,BE,FR,DK,FI,RO,MT,SI,GR,PT,IE,IT,CA,US", currency = "USD,EUR,GBP,JPY,AUD,SGD,CHF,SEK,NOK,NZD,THB,HKD,CAD" } @@ -531,6 +536,9 @@ region = "" credit = { currency = "USD" } debit = { currency = "USD" } +[pm_filters.fiuu] +duit_now = { country ="MY", currency = "MYR" } + [tokenization] stripe = { long_lived_token = false, payment_method = "wallet", payment_method_type = { type = "disable_only", list = "google_pay" } } checkout = { long_lived_token = false, payment_method = "wallet", apple_pay_pre_decrypt_flow = "network_tokenization" } @@ -590,8 +598,8 @@ pay_later.klarna = { connector_list = "adyen" } wallet.google_pay = { connector_list = "stripe,adyen,cybersource,bankofamerica" } wallet.apple_pay = { connector_list = "stripe,adyen,cybersource,noon,bankofamerica" } wallet.paypal = { connector_list = "adyen" } -card.credit = { connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon,bankofamerica,braintree" } -card.debit = { connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon,bankofamerica,braintree" } +card.credit = { connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon,bankofamerica,braintree,fiuu" } +card.debit = { connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon,bankofamerica,braintree,fiuu" } bank_debit.ach = { connector_list = "gocardless,adyen" } bank_debit.becs = { connector_list = "gocardless" } bank_debit.bacs = { connector_list = "adyen" } @@ -747,7 +755,7 @@ enabled = false global_tenant = { schema = "public", redis_key_prefix = "", clickhouse_database = "default"} [multitenancy.tenants] -public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default"} +public = { base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default"} [user_auth_methods] encryption_key = "A8EF32E029BC3342E54BF2E172A4D7AA43E8EF9D2C3A624A9F04E2EF79DC698F" diff --git a/config/docker_compose.toml b/config/docker_compose.toml index dde0902af912..5a2e7249fda4 100644 --- a/config/docker_compose.toml +++ b/config/docker_compose.toml @@ -56,6 +56,7 @@ password_validity_in_days = 90 two_factor_auth_expiry_in_secs = 300 totp_issuer_name = "Hyperswitch" base_url = "http://localhost:8080" +force_two_factor_auth = false [locker] host = "" @@ -135,6 +136,7 @@ digitalvirgo.base_url = "https://dcb-integration-service-sandbox-external.stagin dlocal.base_url = "https://sandbox.dlocal.com/" dummyconnector.base_url = "http://localhost:8080/dummy-connector" ebanx.base_url = "https://sandbox.ebanxpay.com/" +elavon.base_url = "https://api.demo.convergepay.com" fiserv.base_url = "https://cert.api.fiservapps.com/" fiservemea.base_url = "https://prod.emea.api.fiservapps.com/sandbox" fiuu.base_url = "https://sandbox.merchant.razer.com/" @@ -148,6 +150,7 @@ gpayments.base_url = "https://{{merchant_endpoint_prefix}}-test.api.as1.gpayment helcim.base_url = "https://api.helcim.com/" iatapay.base_url = "https://sandbox.iata-pay.iata.org/api/v1" itaubank.base_url = "https://sandbox.devportal.itau.com.br/" +jpmorgan.base_url = "https://api-mock.payments.jpmorgan.com/api/v2" klarna.base_url = "https://api{{klarna_region}}.playground.klarna.com/" mifinity.base_url = "https://demo.mifinity.com/" mollie.base_url = "https://api.mollie.com/v2/" @@ -231,6 +234,7 @@ cards = [ "dlocal", "dummyconnector", "ebanx", + "elavon", "fiserv", "fiservemea", "fiuu", @@ -242,6 +246,7 @@ cards = [ "helcim", "iatapay", "itaubank", + "jpmorgan", "mollie", "multisafepay", "netcetera", @@ -348,34 +353,68 @@ discord_invite_url = "https://discord.gg/wJZ7DVW8mm" payout_eligibility = true [pm_filters.adyen] -online_banking_fpx = { country = "MY", currency = "MYR" } -online_banking_thailand = { country = "TH", currency = "THB" } -touch_n_go = { country = "MY", currency = "MYR" } +ach = { country = "US", currency = "USD" } +affirm = { country = "US", currency = "USD" } +afterpay_clearpay = { country = "US,CA,GB,AU,NZ", currency = "GBP,AUD,NZD,CAD,USD" } +alfamart = { country = "ID", currency = "IDR" } +ali_pay = { country = "AU,JP,HK,SG,MY,TH,ES,GB,SE,NO,AT,NL,DE,CY,CH,BE,FR,DK,FI,RO,MT,SI,GR,PT,IE,IT,CA,US", currency = "USD,EUR,GBP,JPY,AUD,SGD,CHF,SEK,NOK,NZD,THB,HKD,CAD" } +ali_pay_hk = { country = "HK", currency = "HKD" } +alma = { country = "FR", currency = "EUR" } +apple_pay = { country = "AU,NZ,CN,JP,HK,SG,MY,BH,AE,KW,BR,ES,GB,SE,NO,AT,NL,DE,HU,CY,LU,CH,BE,FR,DK,FI,RO,HR,LI,UA,MT,SI,GR,PT,IE,CZ,EE,LT,LV,IT,PL,IS,CA,US", currency = "AUD,CHF,CAD,EUR,GBP,HKD,SGD,USD,MYR" } atome = { country = "MY,SG", currency = "MYR,SGD" } -swish = { country = "SE", currency = "SEK" } -permata_bank_transfer = { country = "ID", currency = "IDR" } +bacs = { country = "GB", currency = "GBP" } +bancontact_card = { country = "BE", currency = "EUR" } bca_bank_transfer = { country = "ID", currency = "IDR" } +bizum = { country = "ES", currency = "EUR" } +blik = { country = "PL", currency = "PLN" } bni_va = { country = "ID", currency = "IDR" } +boleto = { country = "BR", currency = "BRL" } bri_va = { country = "ID", currency = "IDR" } cimb_va = { country = "ID", currency = "IDR" } +dana = { country = "ID", currency = "IDR" } danamon_va = { country = "ID", currency = "IDR" } -mandiri_va = { country = "ID", currency = "IDR" } -alfamart = { country = "ID", currency = "IDR" } +eps = { country = "AT", currency = "EUR" } +family_mart = { country = "JP", currency = "JPY" } +gcash = { country = "PH", currency = "PHP" } +giropay = { country = "DE", currency = "EUR" } +go_pay = { country = "ID", currency = "IDR" } +google_pay = { country = "AU,NZ,JP,HK,SG,MY,TH,VN,BH,AE,KW,BR,ES,GB,SE,NO,SK,AT,NL,DE,HU,CY,LU,CH,BE,FR,DK,RO,HR,LI,MT,SI,GR,PT,IE,CZ,EE,LT,LV,IT,PL,TR,IS,CA,US", currency = "AED,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BMD,BND,BOB,BRL,BSD,BWP,BYN,BZD,CAD,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HTG,HUF,IDR,ILS,INR,IQD,JMD,JOD,JPY,KES,KGS,KHR,KMF,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LYD,MAD,MDL,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SEK,SGD,SHP,SLE,SOS,SRD,STN,SVC,SZL,THB,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW" } +ideal = { country = "NL", currency = "EUR" } indomaret = { country = "ID", currency = "IDR" } +kakao_pay = { country = "KR", currency = "KRW" } +klarna = { country = "AU,AT,BE,CA,CZ,DK,FI,FR,DE,GR,IE,IT,NO,PL,PT,RO,ES,SE,CH,NL,GB,US", currency = "AUD,EUR,CAD,CZK,DKK,NOK,PLN,RON,SEK,CHF,GBP,USD"} +lawson = { country = "JP", currency = "JPY" } +mandiri_va = { country = "ID", currency = "IDR" } +mb_way = { country = "PT", currency = "EUR" } +mini_stop = { country = "JP", currency = "JPY" } +mobile_pay = { country = "DK,FI", currency = "DKK,SEK,NOK,EUR" } +momo = { country = "VN", currency = "VND" } +momo_atm = { country = "VN", currency = "VND" } +online_banking_czech_republic = { country = "CZ", currency = "EUR,CZK" } +online_banking_finland = { country = "FI", currency = "EUR" } +online_banking_fpx = { country = "MY", currency = "MYR" } +online_banking_poland = { country = "PL", currency = "PLN" } +online_banking_slovakia = { country = "SK", currency = "EUR,CZK" } +online_banking_thailand = { country = "TH", currency = "THB" } open_banking_uk = { country = "GB", currency = "GBP" } oxxo = { country = "MX", currency = "MXN" } +pay_bright = { country = "CA", currency = "CAD" } +pay_easy = { country = "JP", currency = "JPY" } pay_safe_card = { country = "AT,AU,BE,BR,BE,CA,HR,CY,CZ,DK,FI,FR,GE,DE,GI,HU,IS,IE,KW,LV,IE,LI,LT,LU,MT,MX,MD,ME,NL,NZ,NO,PY,PE,PL,PT,RO,SA,RS,SK,SI,ES,SE,CH,TR,AE,GB,US,UY", currency = "EUR,AUD,BRL,CAD,CZK,DKK,GEL,GIP,HUF,KWD,CHF,MXN,MDL,NZD,NOK,PYG,PEN,PLN,RON,SAR,RSD,SEK,TRY,AED,GBP,USD,UYU" } -seven_eleven = { country = "JP", currency = "JPY" } -lawson = { country = "JP", currency = "JPY" } -mini_stop = { country = "JP", currency = "JPY" } -family_mart = { country = "JP", currency = "JPY" } +permata_bank_transfer = { country = "ID", currency = "IDR" } seicomart = { country = "JP", currency = "JPY" } -pay_easy = { country = "JP", currency = "JPY" } -boleto = { country = "BR", currency = "BRL" } -ideal = { country = "NL", currency = "EUR" } -klarna = { country = "AU,AT,BE,CA,CZ,DK,FI,FR,DE,GR,IE,IT,NO,PL,PT,RO,ES,SE,CH,NL,GB,US", currency = "AUD,EUR,CAD,CZK,DKK,NOK,PLN,RON,SEK,CHF,GBP,USD" } +sepa = { country = "ES,SK,AT,NL,DE,BE,FR,FI,PT,IE,EE,LT,LV,IT", currency = "EUR" } +seven_eleven = { country = "JP", currency = "JPY" } +sofort = { country = "AT,BE,DE,ES,CH,NL", currency = "CHF,EUR"} paypal = { country = "AU,NZ,CN,JP,HK,MY,TH,KR,PH,ID,AE,KW,BR,ES,GB,SE,NO,SK,AT,NL,DE,HU,CY,LU,CH,BE,FR,DK,FI,RO,HR,UA,MT,SI,GI,PT,IE,CZ,EE,LT,LV,IT,PL,IS,CA,US", currency = "AUD,BRL,CAD,CZK,DKK,EUR,HKD,HUF,INR,JPY,MYR,MXN,NZD,NOK,PHP,PLN,RUB,GBP,SGD,SEK,CHF,THB,USD" } -sofort = { country = "AT,BE,DE,ES,CH,NL", currency = "CHF,EUR" } + +swish = { country = "SE", currency = "SEK" } +touch_n_go = { country = "MY", currency = "MYR" } +trustly = { country = "ES,GB,SE,NO,AT,NL,DE,DK,FI,EE,LT,LV", currency = "CZK,DKK,EUR,GBP,NOK,SEK" } +twint = { country = "CH", currency = "CHF" } +vipps = { country = "NO", currency = "NOK" } +walley = { country = "SE,NO,DK,FI", currency = "DKK,EUR,NOK,SEK" } +we_chat_pay = { country = "AU,NZ,CN,JP,HK,SG,ES,GB,SE,NO,AT,NL,DE,CY,CH,BE,FR,DK,LI,MT,SI,GR,PT,IT,CA,US", currency = "AUD,CAD,CNY,EUR,GBP,HKD,JPY,NZD,SGD,USD,CNY" } [pm_filters.volt] @@ -575,7 +614,7 @@ enabled = false global_tenant = { schema = "public", redis_key_prefix = "", clickhouse_database = "default" } [multitenancy.tenants] -public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default" } +public = { base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default" } [user_auth_methods] encryption_key = "A8EF32E029BC3342E54BF2E172A4D7AA43E8EF9D2C3A624A9F04E2EF79DC698F" diff --git a/config/vector.yaml b/config/vector.yaml index 3f0709ae03cf..4b801935ae5b 100644 --- a/config/vector.yaml +++ b/config/vector.yaml @@ -1,5 +1,16 @@ acknowledgements: enabled: true +enrichment_tables: + sdk_map: + type: file + file: + path: /etc/vector/config/sdk_map.csv + encoding: + type: csv + schema: + publishable_key: string + merchant_id: string + api: enabled: true @@ -87,6 +98,21 @@ transforms: key_field: "{{ .payment_id }}{{ .merchant_id }}" threshold: 1000 window_secs: 60 + + amend_sdk_logs: + type: remap + inputs: + - sdk_transformed + source: | + .before_transform = now() + + merchant_id = .merchant_id + row = get_enrichment_table_record!("sdk_map", { "publishable_key" : merchant_id }, case_sensitive: true) + .merchant_id = row.merchant_id + + .after_transform = now() + + sinks: opensearch_events_1: @@ -110,6 +136,9 @@ sinks: - offset - partition - topic + - clickhouse_database + - last_synced + - sign_flag bulk: index: "vector-{{ .topic }}" @@ -134,6 +163,9 @@ sinks: - offset - partition - topic + - clickhouse_database + - last_synced + - sign_flag bulk: # Add a date suffixed index for better grouping index: "vector-{{ .topic }}-%Y-%m-%d" @@ -224,7 +256,7 @@ sinks: - "path" - "source_type" inputs: - - "sdk_transformed" + - "amend_sdk_logs" bootstrap_servers: kafka0:29092 topic: hyper-sdk-logs key_field: ".merchant_id" diff --git a/connector-template/transformers.rs b/connector-template/transformers.rs index 1454be66c8b0..b508596cbc08 100644 --- a/connector-template/transformers.rs +++ b/connector-template/transformers.rs @@ -132,8 +132,8 @@ impl TryFrom for AnalyticsError { @@ -32,6 +34,12 @@ impl ErrorSwitch for AnalyticsError { Self::AccessForbiddenError => { ApiErrorResponse::Unauthorized(ApiError::new("IR", 0, "Access Forbidden", None)) } + Self::ForexFetchFailed => ApiErrorResponse::InternalServerError(ApiError::new( + "HE", + 0, + "Failed to fetch currency exchange rate", + None, + )), } } } diff --git a/crates/analytics/src/payment_intents/accumulator.rs b/crates/analytics/src/payment_intents/accumulator.rs index cbb8335cea01..ef3cd3129c48 100644 --- a/crates/analytics/src/payment_intents/accumulator.rs +++ b/crates/analytics/src/payment_intents/accumulator.rs @@ -86,7 +86,7 @@ impl PaymentIntentMetricAccumulator for CountAccumulator { } impl PaymentIntentMetricAccumulator for SmartRetriedAmountAccumulator { - type MetricOutput = (Option, Option); + type MetricOutput = (Option, Option, Option, Option); #[inline] fn add_metrics_bucket(&mut self, metrics: &PaymentIntentMetricRow) { self.amount = match ( @@ -117,7 +117,7 @@ impl PaymentIntentMetricAccumulator for SmartRetriedAmountAccumulator { .amount_without_retries .and_then(|i| u64::try_from(i).ok()) .or(Some(0)); - (with_retries, without_retries) + (with_retries, without_retries, Some(0), Some(0)) } } @@ -185,7 +185,14 @@ impl PaymentIntentMetricAccumulator for PaymentsSuccessRateAccumulator { } impl PaymentIntentMetricAccumulator for ProcessedAmountAccumulator { - type MetricOutput = (Option, Option, Option, Option); + type MetricOutput = ( + Option, + Option, + Option, + Option, + Option, + Option, + ); #[inline] fn add_metrics_bucket(&mut self, metrics: &PaymentIntentMetricRow) { self.total_with_retries = match ( @@ -235,6 +242,8 @@ impl PaymentIntentMetricAccumulator for ProcessedAmountAccumulator { count_with_retries, total_without_retries, count_without_retries, + Some(0), + Some(0), ) } } @@ -301,13 +310,19 @@ impl PaymentIntentMetricsAccumulator { payments_success_rate, payments_success_rate_without_smart_retries, ) = self.payments_success_rate.collect(); - let (smart_retried_amount, smart_retried_amount_without_smart_retries) = - self.smart_retried_amount.collect(); + let ( + smart_retried_amount, + smart_retried_amount_without_smart_retries, + smart_retried_amount_in_usd, + smart_retried_amount_without_smart_retries_in_usd, + ) = self.smart_retried_amount.collect(); let ( payment_processed_amount, payment_processed_count, payment_processed_amount_without_smart_retries, payment_processed_count_without_smart_retries, + payment_processed_amount_in_usd, + payment_processed_amount_without_smart_retries_in_usd, ) = self.payment_processed_amount.collect(); let ( payments_success_rate_distribution_without_smart_retries, @@ -317,7 +332,9 @@ impl PaymentIntentMetricsAccumulator { successful_smart_retries: self.successful_smart_retries.collect(), total_smart_retries: self.total_smart_retries.collect(), smart_retried_amount, + smart_retried_amount_in_usd, smart_retried_amount_without_smart_retries, + smart_retried_amount_without_smart_retries_in_usd, payment_intent_count: self.payment_intent_count.collect(), successful_payments, successful_payments_without_smart_retries, @@ -330,6 +347,8 @@ impl PaymentIntentMetricsAccumulator { payment_processed_count_without_smart_retries, payments_success_rate_distribution_without_smart_retries, payments_failure_rate_distribution_without_smart_retries, + payment_processed_amount_in_usd, + payment_processed_amount_without_smart_retries_in_usd, } } } diff --git a/crates/analytics/src/payment_intents/core.rs b/crates/analytics/src/payment_intents/core.rs index e04c3b7bd9eb..7ea8e9007f7b 100644 --- a/crates/analytics/src/payment_intents/core.rs +++ b/crates/analytics/src/payment_intents/core.rs @@ -10,8 +10,10 @@ use api_models::analytics::{ PaymentIntentFiltersResponse, PaymentIntentsAnalyticsMetadata, PaymentIntentsMetricsResponse, SankeyResponse, }; -use common_enums::IntentStatus; +use bigdecimal::ToPrimitive; +use common_enums::{Currency, IntentStatus}; use common_utils::{errors::CustomResult, types::TimeRange}; +use currency_conversion::{conversion::convert, types::ExchangeRates}; use error_stack::ResultExt; use router_env::{ instrument, logger, @@ -120,6 +122,7 @@ pub async fn get_sankey( #[instrument(skip_all)] pub async fn get_metrics( pool: &AnalyticsProvider, + ex_rates: &ExchangeRates, auth: &AuthInfo, req: GetPaymentIntentMetricRequest, ) -> AnalyticsResult> { @@ -205,7 +208,8 @@ pub async fn get_metrics( | PaymentIntentMetrics::SessionizedPaymentsSuccessRate => metrics_builder .payments_success_rate .add_metrics_bucket(&value), - PaymentIntentMetrics::SessionizedPaymentProcessedAmount => metrics_builder + PaymentIntentMetrics::SessionizedPaymentProcessedAmount + | PaymentIntentMetrics::PaymentProcessedAmount => metrics_builder .payment_processed_amount .add_metrics_bucket(&value), PaymentIntentMetrics::SessionizedPaymentsDistribution => metrics_builder @@ -226,16 +230,20 @@ pub async fn get_metrics( let mut success = 0; let mut success_without_smart_retries = 0; let mut total_smart_retried_amount = 0; + let mut total_smart_retried_amount_in_usd = 0; let mut total_smart_retried_amount_without_smart_retries = 0; + let mut total_smart_retried_amount_without_smart_retries_in_usd = 0; let mut total = 0; let mut total_payment_processed_amount = 0; + let mut total_payment_processed_amount_in_usd = 0; let mut total_payment_processed_count = 0; let mut total_payment_processed_amount_without_smart_retries = 0; + let mut total_payment_processed_amount_without_smart_retries_in_usd = 0; let mut total_payment_processed_count_without_smart_retries = 0; let query_data: Vec = metrics_accumulator .into_iter() .map(|(id, val)| { - let collected_values = val.collect(); + let mut collected_values = val.collect(); if let Some(success_count) = collected_values.successful_payments { success += success_count; } @@ -247,20 +255,95 @@ pub async fn get_metrics( total += total_count; } if let Some(retried_amount) = collected_values.smart_retried_amount { + let amount_in_usd = id + .currency + .and_then(|currency| { + i64::try_from(retried_amount) + .inspect_err(|e| logger::error!("Amount conversion error: {:?}", e)) + .ok() + .and_then(|amount_i64| { + convert(ex_rates, currency, Currency::USD, amount_i64) + .inspect_err(|e| { + logger::error!("Currency conversion error: {:?}", e) + }) + .ok() + }) + }) + .map(|amount| (amount * rust_decimal::Decimal::new(100, 0)).to_u64()) + .unwrap_or_default(); + collected_values.smart_retried_amount_in_usd = amount_in_usd; total_smart_retried_amount += retried_amount; + total_smart_retried_amount_in_usd += amount_in_usd.unwrap_or(0); } if let Some(retried_amount) = collected_values.smart_retried_amount_without_smart_retries { + let amount_in_usd = id + .currency + .and_then(|currency| { + i64::try_from(retried_amount) + .inspect_err(|e| logger::error!("Amount conversion error: {:?}", e)) + .ok() + .and_then(|amount_i64| { + convert(ex_rates, currency, Currency::USD, amount_i64) + .inspect_err(|e| { + logger::error!("Currency conversion error: {:?}", e) + }) + .ok() + }) + }) + .map(|amount| (amount * rust_decimal::Decimal::new(100, 0)).to_u64()) + .unwrap_or_default(); + collected_values.smart_retried_amount_without_smart_retries_in_usd = amount_in_usd; total_smart_retried_amount_without_smart_retries += retried_amount; + total_smart_retried_amount_without_smart_retries_in_usd += + amount_in_usd.unwrap_or(0); } if let Some(amount) = collected_values.payment_processed_amount { + let amount_in_usd = id + .currency + .and_then(|currency| { + i64::try_from(amount) + .inspect_err(|e| logger::error!("Amount conversion error: {:?}", e)) + .ok() + .and_then(|amount_i64| { + convert(ex_rates, currency, Currency::USD, amount_i64) + .inspect_err(|e| { + logger::error!("Currency conversion error: {:?}", e) + }) + .ok() + }) + }) + .map(|amount| (amount * rust_decimal::Decimal::new(100, 0)).to_u64()) + .unwrap_or_default(); + collected_values.payment_processed_amount_in_usd = amount_in_usd; + total_payment_processed_amount_in_usd += amount_in_usd.unwrap_or(0); total_payment_processed_amount += amount; } if let Some(count) = collected_values.payment_processed_count { total_payment_processed_count += count; } if let Some(amount) = collected_values.payment_processed_amount_without_smart_retries { + let amount_in_usd = id + .currency + .and_then(|currency| { + i64::try_from(amount) + .inspect_err(|e| logger::error!("Amount conversion error: {:?}", e)) + .ok() + .and_then(|amount_i64| { + convert(ex_rates, currency, Currency::USD, amount_i64) + .inspect_err(|e| { + logger::error!("Currency conversion error: {:?}", e) + }) + .ok() + }) + }) + .map(|amount| (amount * rust_decimal::Decimal::new(100, 0)).to_u64()) + .unwrap_or_default(); + collected_values.payment_processed_amount_without_smart_retries_in_usd = + amount_in_usd; + total_payment_processed_amount_without_smart_retries_in_usd += + amount_in_usd.unwrap_or(0); total_payment_processed_amount_without_smart_retries += amount; } if let Some(count) = collected_values.payment_processed_count_without_smart_retries { @@ -293,6 +376,14 @@ pub async fn get_metrics( total_payment_processed_amount_without_smart_retries: Some( total_payment_processed_amount_without_smart_retries, ), + total_smart_retried_amount_in_usd: Some(total_smart_retried_amount_in_usd), + total_smart_retried_amount_without_smart_retries_in_usd: Some( + total_smart_retried_amount_without_smart_retries_in_usd, + ), + total_payment_processed_amount_in_usd: Some(total_payment_processed_amount_in_usd), + total_payment_processed_amount_without_smart_retries_in_usd: Some( + total_payment_processed_amount_without_smart_retries_in_usd, + ), total_payment_processed_count: Some(total_payment_processed_count), total_payment_processed_count_without_smart_retries: Some( total_payment_processed_count_without_smart_retries, @@ -371,15 +462,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 25d43e76f037..d03d6c2a15f9 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,5 @@ 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, + pub customer_id: Option, } diff --git a/crates/analytics/src/payment_intents/metrics.rs b/crates/analytics/src/payment_intents/metrics.rs index 8ee9d24b5a0f..9aa7d3e97719 100644 --- a/crates/analytics/src/payment_intents/metrics.rs +++ b/crates/analytics/src/payment_intents/metrics.rs @@ -17,6 +17,7 @@ use crate::{ }; mod payment_intent_count; +mod payment_processed_amount; mod payments_success_rate; mod sessionized_metrics; mod smart_retried_amount; @@ -24,6 +25,7 @@ mod successful_smart_retries; mod total_smart_retries; use payment_intent_count::PaymentIntentCount; +use payment_processed_amount::PaymentProcessedAmount; use payments_success_rate::PaymentsSuccessRate; use smart_retried_amount::SmartRetriedAmount; use successful_smart_retries::SuccessfulSmartRetries; @@ -34,15 +36,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, @@ -116,6 +109,11 @@ where .load_metrics(dimensions, auth, filters, granularity, time_range, pool) .await } + Self::PaymentProcessedAmount => { + PaymentProcessedAmount + .load_metrics(dimensions, auth, filters, granularity, time_range, pool) + .await + } Self::SessionizedSuccessfulSmartRetries => { sessionized_metrics::SuccessfulSmartRetries .load_metrics(dimensions, auth, filters, granularity, time_range, pool) 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 b301a9b9b23b..4632cbe9f370 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/payment_processed_amount.rs b/crates/analytics/src/payment_intents/metrics/payment_processed_amount.rs new file mode 100644 index 000000000000..51b574f4ad38 --- /dev/null +++ b/crates/analytics/src/payment_intents/metrics/payment_processed_amount.rs @@ -0,0 +1,161 @@ +use std::collections::HashSet; + +use api_models::analytics::{ + payment_intents::{ + PaymentIntentDimensions, PaymentIntentFilters, PaymentIntentMetricsBucketIdentifier, + }, + Granularity, TimeRange, +}; +use common_utils::errors::ReportSwitchExt; +use diesel_models::enums as storage_enums; +use error_stack::ResultExt; +use time::PrimitiveDateTime; + +use super::PaymentIntentMetricRow; +use crate::{ + enums::AuthInfo, + query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, SeriesBucket, ToSql, Window}, + types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult}, +}; + +#[derive(Default)] +pub(super) struct PaymentProcessedAmount; + +#[async_trait::async_trait] +impl super::PaymentIntentMetric for PaymentProcessedAmount +where + T: AnalyticsDataSource + super::PaymentIntentMetricAnalytics, + PrimitiveDateTime: ToSql, + AnalyticsCollection: ToSql, + Granularity: GroupByClause, + Aggregate<&'static str>: ToSql, + Window<&'static str>: ToSql, +{ + async fn load_metrics( + &self, + dimensions: &[PaymentIntentDimensions], + auth: &AuthInfo, + filters: &PaymentIntentFilters, + granularity: &Option, + time_range: &TimeRange, + pool: &T, + ) -> MetricsResult> + { + let mut query_builder: QueryBuilder = + QueryBuilder::new(AnalyticsCollection::PaymentIntent); + + let mut dimensions = dimensions.to_vec(); + + dimensions.push(PaymentIntentDimensions::PaymentIntentStatus); + + for dim in dimensions.iter() { + query_builder.add_select_column(dim).switch()?; + } + + query_builder + .add_select_column(Aggregate::Count { + field: None, + alias: Some("count"), + }) + .switch()?; + + query_builder + .add_select_column("attempt_count == 1 as first_attempt") + .switch()?; + + query_builder.add_select_column("currency").switch()?; + + query_builder + .add_select_column(Aggregate::Sum { + field: "amount", + alias: Some("total"), + }) + .switch()?; + + query_builder + .add_select_column(Aggregate::Min { + field: "created_at", + alias: Some("start_bucket"), + }) + .switch()?; + + query_builder + .add_select_column(Aggregate::Max { + field: "created_at", + alias: Some("end_bucket"), + }) + .switch()?; + + filters.set_filter_clause(&mut query_builder).switch()?; + + auth.set_filter_clause(&mut query_builder).switch()?; + + time_range + .set_filter_clause(&mut query_builder) + .attach_printable("Error filtering time range") + .switch()?; + + for dim in dimensions.iter() { + query_builder + .add_group_by_clause(dim) + .attach_printable("Error grouping by dimensions") + .switch()?; + } + + query_builder + .add_group_by_clause("attempt_count") + .attach_printable("Error grouping by attempt_count") + .switch()?; + + query_builder + .add_group_by_clause("currency") + .attach_printable("Error grouping by currency") + .switch()?; + + if let Some(granularity) = granularity.as_ref() { + granularity + .set_group_by_clause(&mut query_builder) + .attach_printable("Error adding granularity") + .switch()?; + } + + query_builder + .add_filter_clause( + PaymentIntentDimensions::PaymentIntentStatus, + storage_enums::IntentStatus::Succeeded, + ) + .switch()?; + + query_builder + .execute_query::(pool) + .await + .change_context(MetricsError::QueryBuildingError)? + .change_context(MetricsError::QueryExecutionFailure)? + .into_iter() + .map(|i| { + Ok(( + PaymentIntentMetricsBucketIdentifier::new( + None, + i.currency.as_ref().map(|i| i.0), + i.profile_id.clone(), + TimeRange { + start_time: match (granularity, i.start_bucket) { + (Some(g), Some(st)) => g.clip_to_start(st)?, + _ => time_range.start_time, + }, + end_time: granularity.as_ref().map_or_else( + || Ok(time_range.end_time), + |g| i.end_bucket.map(|et| g.clip_to_end(et)).transpose(), + )?, + }, + ), + i, + )) + }) + .collect::, + crate::query::PostProcessingError, + >>() + .change_context(MetricsError::PostProcessingFailure) + } +} 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 07b1bfcf69fe..14e168b3523d 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 7475a75bb532..644bf35a7236 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 506965375f5b..01d580534834 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 @@ -61,7 +61,7 @@ where query_builder .add_select_column("attempt_count == 1 as first_attempt") .switch()?; - + query_builder.add_select_column("currency").switch()?; query_builder .add_select_column(Aggregate::Sum { field: "amount", @@ -101,7 +101,10 @@ where .add_group_by_clause("attempt_count") .attach_printable("Error grouping by attempt_count") .switch()?; - + query_builder + .add_group_by_clause("currency") + .attach_printable("Error grouping by currency") + .switch()?; if let Some(granularity) = granularity.as_ref() { granularity .set_group_by_clause(&mut query_builder) @@ -128,15 +131,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 0b55c101a7c9..eed6bf85a2c4 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 8c340d0b2d6e..bd1f8bbbcd95 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 8105a4c82a4a..cf7af6e11e7e 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 @@ -63,6 +63,7 @@ where .add_select_column("attempt_count == 1 as first_attempt") .switch()?; + query_builder.add_select_column("currency").switch()?; query_builder .add_select_column(Aggregate::Min { field: "created_at", @@ -102,7 +103,10 @@ where .add_group_by_clause("first_attempt") .attach_printable("Error grouping by first_attempt") .switch()?; - + query_builder + .add_group_by_clause("currency") + .attach_printable("Error grouping by first_attempt") + .switch()?; if let Some(granularity) = granularity.as_ref() { granularity .set_group_by_clause(&mut query_builder) @@ -122,15 +126,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 0b28cb5366d6..bf97e4c41eff 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 20ef8be62770..cea5b2fa4656 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 8468911f7bbb..9497dc89f42c 100644 --- a/crates/analytics/src/payment_intents/metrics/smart_retried_amount.rs +++ b/crates/analytics/src/payment_intents/metrics/smart_retried_amount.rs @@ -62,7 +62,7 @@ where query_builder .add_select_column("attempt_count == 1 as first_attempt") .switch()?; - + query_builder.add_select_column("currency").switch()?; query_builder .add_select_column(Aggregate::Min { field: "created_at", @@ -102,7 +102,10 @@ where .add_group_by_clause("first_attempt") .attach_printable("Error grouping by first_attempt") .switch()?; - + query_builder + .add_group_by_clause("currency") + .attach_printable("Error grouping by currency") + .switch()?; if let Some(granularity) = granularity.as_ref() { granularity .set_group_by_clause(&mut query_builder) @@ -122,15 +125,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 a19bdec518c4..4fe5f3a26f51 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 f5539abd9f50..e98efa9f6abc 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 1a9a2f2ed658..bb5141297c56 100644 --- a/crates/analytics/src/payment_intents/types.rs +++ b/crates/analytics/src/payment_intents/types.rs @@ -30,62 +30,10 @@ where .add_filter_in_range_clause(PaymentIntentDimensions::ProfileId, &self.profile_id) .attach_printable("Error adding profile id filter")?; } - if !self.connector.is_empty() { + if !self.customer_id.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")?; + .add_filter_in_range_clause("customer_id", &self.customer_id) + .attach_printable("Error adding customer id filter")?; } Ok(()) } diff --git a/crates/analytics/src/payments/accumulator.rs b/crates/analytics/src/payments/accumulator.rs index 4388b2071fee..651eeb0bcfe7 100644 --- a/crates/analytics/src/payments/accumulator.rs +++ b/crates/analytics/src/payments/accumulator.rs @@ -272,7 +272,14 @@ impl PaymentMetricAccumulator for CountAccumulator { } impl PaymentMetricAccumulator for ProcessedAmountAccumulator { - type MetricOutput = (Option, Option, Option, Option); + type MetricOutput = ( + Option, + Option, + Option, + Option, + Option, + Option, + ); #[inline] fn add_metrics_bucket(&mut self, metrics: &PaymentMetricRow) { self.total_with_retries = match ( @@ -322,6 +329,8 @@ impl PaymentMetricAccumulator for ProcessedAmountAccumulator { count_with_retries, total_without_retries, count_without_retries, + Some(0), + Some(0), ) } } @@ -378,6 +387,8 @@ impl PaymentMetricsAccumulator { payment_processed_count, payment_processed_amount_without_smart_retries, payment_processed_count_without_smart_retries, + payment_processed_amount_usd, + payment_processed_amount_without_smart_retries_usd, ) = self.processed_amount.collect(); let ( payments_success_rate_distribution, @@ -406,6 +417,8 @@ impl PaymentMetricsAccumulator { payments_failure_rate_distribution_without_smart_retries, failure_reason_count, failure_reason_count_without_smart_retries, + payment_processed_amount_usd, + payment_processed_amount_without_smart_retries_usd, } } } diff --git a/crates/analytics/src/payments/core.rs b/crates/analytics/src/payments/core.rs index 59ae549b2839..bcd009270dc1 100644 --- a/crates/analytics/src/payments/core.rs +++ b/crates/analytics/src/payments/core.rs @@ -9,7 +9,10 @@ use api_models::analytics::{ FilterValue, GetPaymentFiltersRequest, GetPaymentMetricRequest, PaymentFiltersResponse, PaymentsAnalyticsMetadata, PaymentsMetricsResponse, }; +use bigdecimal::ToPrimitive; +use common_enums::Currency; use common_utils::errors::CustomResult; +use currency_conversion::{conversion::convert, types::ExchangeRates}; use error_stack::ResultExt; use router_env::{ instrument, logger, @@ -46,6 +49,7 @@ pub enum TaskType { #[instrument(skip_all)] pub async fn get_metrics( pool: &AnalyticsProvider, + ex_rates: &ExchangeRates, auth: &AuthInfo, req: GetPaymentMetricRequest, ) -> AnalyticsResult> { @@ -224,18 +228,57 @@ pub async fn get_metrics( let mut total_payment_processed_count_without_smart_retries = 0; let mut total_failure_reasons_count = 0; let mut total_failure_reasons_count_without_smart_retries = 0; + let mut total_payment_processed_amount_usd = 0; + let mut total_payment_processed_amount_without_smart_retries_usd = 0; let query_data: Vec = metrics_accumulator .into_iter() .map(|(id, val)| { - let collected_values = val.collect(); + let mut collected_values = val.collect(); if let Some(amount) = collected_values.payment_processed_amount { + let amount_in_usd = id + .currency + .and_then(|currency| { + i64::try_from(amount) + .inspect_err(|e| logger::error!("Amount conversion error: {:?}", e)) + .ok() + .and_then(|amount_i64| { + convert(ex_rates, currency, Currency::USD, amount_i64) + .inspect_err(|e| { + logger::error!("Currency conversion error: {:?}", e) + }) + .ok() + }) + }) + .map(|amount| (amount * rust_decimal::Decimal::new(100, 0)).to_u64()) + .unwrap_or_default(); + collected_values.payment_processed_amount_usd = amount_in_usd; total_payment_processed_amount += amount; + total_payment_processed_amount_usd += amount_in_usd.unwrap_or(0); } if let Some(count) = collected_values.payment_processed_count { total_payment_processed_count += count; } if let Some(amount) = collected_values.payment_processed_amount_without_smart_retries { + let amount_in_usd = id + .currency + .and_then(|currency| { + i64::try_from(amount) + .inspect_err(|e| logger::error!("Amount conversion error: {:?}", e)) + .ok() + .and_then(|amount_i64| { + convert(ex_rates, currency, Currency::USD, amount_i64) + .inspect_err(|e| { + logger::error!("Currency conversion error: {:?}", e) + }) + .ok() + }) + }) + .map(|amount| (amount * rust_decimal::Decimal::new(100, 0)).to_u64()) + .unwrap_or_default(); + collected_values.payment_processed_amount_without_smart_retries_usd = amount_in_usd; total_payment_processed_amount_without_smart_retries += amount; + total_payment_processed_amount_without_smart_retries_usd += + amount_in_usd.unwrap_or(0); } if let Some(count) = collected_values.payment_processed_count_without_smart_retries { total_payment_processed_count_without_smart_retries += count; @@ -252,14 +295,17 @@ pub async fn get_metrics( } }) .collect(); - Ok(PaymentsMetricsResponse { query_data, meta_data: [PaymentsAnalyticsMetadata { total_payment_processed_amount: Some(total_payment_processed_amount), + total_payment_processed_amount_usd: Some(total_payment_processed_amount_usd), total_payment_processed_amount_without_smart_retries: Some( total_payment_processed_amount_without_smart_retries, ), + total_payment_processed_amount_without_smart_retries_usd: Some( + total_payment_processed_amount_without_smart_retries_usd, + ), total_payment_processed_count: Some(total_payment_processed_count), total_payment_processed_count_without_smart_retries: Some( total_payment_processed_count_without_smart_retries, diff --git a/crates/analytics/src/payments/metrics/payment_processed_amount.rs b/crates/analytics/src/payments/metrics/payment_processed_amount.rs index b8b3868803c6..fa54c1730416 100644 --- a/crates/analytics/src/payments/metrics/payment_processed_amount.rs +++ b/crates/analytics/src/payments/metrics/payment_processed_amount.rs @@ -50,6 +50,7 @@ where alias: Some("total"), }) .switch()?; + query_builder.add_select_column("currency").switch()?; query_builder .add_select_column(Aggregate::Min { field: "created_at", @@ -79,6 +80,11 @@ where .switch()?; } + query_builder + .add_group_by_clause("currency") + .attach_printable("Error grouping by currency") + .switch()?; + if let Some(granularity) = granularity.as_ref() { granularity .set_group_by_clause(&mut query_builder) diff --git a/crates/analytics/src/payments/metrics/sessionized_metrics/failure_reasons.rs b/crates/analytics/src/payments/metrics/sessionized_metrics/failure_reasons.rs index 70ae64e01156..bcbce0502d2d 100644 --- a/crates/analytics/src/payments/metrics/sessionized_metrics/failure_reasons.rs +++ b/crates/analytics/src/payments/metrics/sessionized_metrics/failure_reasons.rs @@ -148,17 +148,20 @@ where .attach_printable("Error adding order by clause") .switch()?; - for dim in dimensions.iter() { - if dim != &PaymentDimensions::ErrorReason { - outer_query_builder - .add_order_by_clause(dim, Order::Ascending) - .attach_printable("Error adding order by clause") - .switch()?; - } + let filtered_dimensions: Vec<&PaymentDimensions> = dimensions + .iter() + .filter(|&&dim| dim != PaymentDimensions::ErrorReason) + .collect(); + + for dim in &filtered_dimensions { + outer_query_builder + .add_order_by_clause(*dim, Order::Ascending) + .attach_printable("Error adding order by clause") + .switch()?; } outer_query_builder - .set_limit_by(5, &[PaymentDimensions::Connector]) + .set_limit_by(5, &filtered_dimensions) .attach_printable("Error adding limit clause") .switch()?; diff --git a/crates/analytics/src/payments/metrics/sessionized_metrics/payment_processed_amount.rs b/crates/analytics/src/payments/metrics/sessionized_metrics/payment_processed_amount.rs index 9bc554eaae71..a315b2fc4c82 100644 --- a/crates/analytics/src/payments/metrics/sessionized_metrics/payment_processed_amount.rs +++ b/crates/analytics/src/payments/metrics/sessionized_metrics/payment_processed_amount.rs @@ -57,6 +57,8 @@ where query_builder.add_select_column("first_attempt").switch()?; + query_builder.add_select_column("currency").switch()?; + query_builder .add_select_column(Aggregate::Sum { field: "amount", @@ -95,6 +97,12 @@ where .add_group_by_clause("first_attempt") .attach_printable("Error grouping by first_attempt") .switch()?; + + query_builder + .add_group_by_clause("currency") + .attach_printable("Error grouping by currency") + .switch()?; + if let Some(granularity) = granularity.as_ref() { granularity .set_group_by_clause(&mut query_builder) diff --git a/crates/analytics/src/query.rs b/crates/analytics/src/query.rs index 7ce338f7db30..d746594e36ee 100644 --- a/crates/analytics/src/query.rs +++ b/crates/analytics/src/query.rs @@ -451,6 +451,12 @@ impl ToSql for &common_utils::id_type::PaymentId { } } +impl ToSql for common_utils::id_type::CustomerId { + fn to_sql(&self, _table_engine: &TableEngine) -> error_stack::Result { + Ok(self.get_string_repr().to_owned()) + } +} + /// Implement `ToSql` on arrays of types that impl `ToString`. macro_rules! impl_to_sql_for_to_string { ($($type:ty),+) => { diff --git a/crates/analytics/src/sqlx.rs b/crates/analytics/src/sqlx.rs index ae72bbeffea4..7c90e37c55fb 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,42 +652,7 @@ 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 { + let customer_id: Option = row.try_get("customer_id").or_else(|e| match e { ColumnNotFound(_) => Ok(Default::default()), e => Err(e), })?; @@ -743,15 +660,7 @@ impl<'a> FromRow<'a, PgRow> for super::payment_intents::filters::PaymentIntentFi status, currency, profile_id, - connector, - authentication_type, - payment_method, - payment_method_type, - card_network, - merchant_id, - card_last_4, - card_issuer, - error_reason, + customer_id, }) } } diff --git a/crates/analytics/src/utils.rs b/crates/analytics/src/utils.rs index fc21bf098192..435e95451fe4 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/admin.rs b/crates/api_models/src/admin.rs index 8f24bdf65bc5..c9da386a11de 100644 --- a/crates/api_models/src/admin.rs +++ b/crates/api_models/src/admin.rs @@ -178,7 +178,8 @@ impl MerchantAccountCreate { #[cfg(feature = "v2")] #[derive(Clone, Debug, Deserialize, ToSchema, Serialize)] #[serde(deny_unknown_fields)] -pub struct MerchantAccountCreate { +#[schema(as = MerchantAccountCreate)] +pub struct MerchantAccountCreateWithoutOrgId { /// Name of the Merchant Account, This will be used as a prefix to generate the id #[schema(value_type= String, max_length = 64, example = "NewAge Retailer")] pub merchant_name: Secret, @@ -189,9 +190,17 @@ pub struct MerchantAccountCreate { /// Metadata is useful for storing additional, unstructured information about the merchant account. #[schema(value_type = Option, example = r#"{ "city": "NY", "unit": "245" }"#)] pub metadata: Option, +} - /// The id of the organization to which the merchant belongs to. Please use the organization endpoint to create an organization - #[schema(value_type = String, max_length = 64, min_length = 1, example = "org_q98uSGAYbjEwqs0mJwnz")] +// In v2 the struct used in the API is MerchantAccountCreateWithoutOrgId +// The following struct is only used internally, so we can reuse the common +// part of `create_merchant_account` without duplicating its code for v2 +#[cfg(feature = "v2")] +#[derive(Clone, Debug, Serialize)] +pub struct MerchantAccountCreate { + pub merchant_name: Secret, + pub merchant_details: Option, + pub metadata: Option, pub organization_id: id_type::OrganizationId, } diff --git a/crates/api_models/src/analytics.rs b/crates/api_models/src/analytics.rs index b95404080b03..8d63bc3096ca 100644 --- a/crates/api_models/src/analytics.rs +++ b/crates/api_models/src/analytics.rs @@ -203,7 +203,9 @@ pub struct AnalyticsMetadata { #[derive(Debug, serde::Serialize)] pub struct PaymentsAnalyticsMetadata { pub total_payment_processed_amount: Option, + pub total_payment_processed_amount_usd: Option, pub total_payment_processed_amount_without_smart_retries: Option, + pub total_payment_processed_amount_without_smart_retries_usd: Option, pub total_payment_processed_count: Option, pub total_payment_processed_count_without_smart_retries: Option, pub total_failure_reasons_count: Option, @@ -218,6 +220,10 @@ pub struct PaymentIntentsAnalyticsMetadata { pub total_smart_retried_amount_without_smart_retries: Option, pub total_payment_processed_amount: Option, pub total_payment_processed_amount_without_smart_retries: Option, + pub total_smart_retried_amount_in_usd: Option, + pub total_smart_retried_amount_without_smart_retries_in_usd: Option, + pub total_payment_processed_amount_in_usd: Option, + pub total_payment_processed_amount_without_smart_retries_in_usd: Option, pub total_payment_processed_count: Option, pub total_payment_processed_count_without_smart_retries: Option, } diff --git a/crates/api_models/src/analytics/payment_intents.rs b/crates/api_models/src/analytics/payment_intents.rs index 41f11c19ef8d..3ac3c09d35f6 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 { @@ -19,23 +17,7 @@ pub struct PaymentIntentFilters { #[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, + pub customer_id: Vec, } #[derive( @@ -60,15 +42,6 @@ pub enum PaymentIntentDimensions { PaymentIntentStatus, Currency, ProfileId, - Connector, - AuthType, - PaymentMethod, - PaymentMethodType, - CardNetwork, - MerchantId, - CardLast4, - CardIssuer, - ErrorReason, } #[derive( @@ -91,6 +64,7 @@ pub enum PaymentIntentMetrics { SmartRetriedAmount, PaymentIntentCount, PaymentsSuccessRate, + PaymentProcessedAmount, SessionizedSuccessfulSmartRetries, SessionizedTotalSmartRetries, SessionizedSmartRetriedAmount, @@ -138,15 +112,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 +125,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 +142,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); } } @@ -223,7 +161,9 @@ pub struct PaymentIntentMetricsBucketValue { pub successful_smart_retries: Option, pub total_smart_retries: Option, pub smart_retried_amount: Option, + pub smart_retried_amount_in_usd: Option, pub smart_retried_amount_without_smart_retries: Option, + pub smart_retried_amount_without_smart_retries_in_usd: Option, pub payment_intent_count: Option, pub successful_payments: Option, pub successful_payments_without_smart_retries: Option, @@ -231,8 +171,10 @@ pub struct PaymentIntentMetricsBucketValue { pub payments_success_rate: Option, pub payments_success_rate_without_smart_retries: Option, pub payment_processed_amount: Option, + pub payment_processed_amount_in_usd: Option, pub payment_processed_count: Option, pub payment_processed_amount_without_smart_retries: Option, + pub payment_processed_amount_without_smart_retries_in_usd: Option, pub payment_processed_count_without_smart_retries: Option, pub payments_success_rate_distribution_without_smart_retries: Option, pub payments_failure_rate_distribution_without_smart_retries: Option, diff --git a/crates/api_models/src/analytics/payments.rs b/crates/api_models/src/analytics/payments.rs index 1120ab092d75..1faba79eb378 100644 --- a/crates/api_models/src/analytics/payments.rs +++ b/crates/api_models/src/analytics/payments.rs @@ -271,8 +271,10 @@ pub struct PaymentMetricsBucketValue { pub payment_count: Option, pub payment_success_count: Option, pub payment_processed_amount: Option, + pub payment_processed_amount_usd: Option, pub payment_processed_count: Option, pub payment_processed_amount_without_smart_retries: Option, + pub payment_processed_amount_without_smart_retries_usd: Option, pub payment_processed_count_without_smart_retries: Option, pub avg_ticket_size: Option, pub payment_error_message: Option>, diff --git a/crates/api_models/src/analytics/refunds.rs b/crates/api_models/src/analytics/refunds.rs index 8acb51e764c0..ef17387d1ea4 100644 --- a/crates/api_models/src/analytics/refunds.rs +++ b/crates/api_models/src/analytics/refunds.rs @@ -5,7 +5,7 @@ use std::{ use common_utils::id_type; -use crate::{enums::Currency, refunds::RefundStatus}; +use crate::enums::{Currency, RefundStatus}; #[derive( Clone, diff --git a/crates/api_models/src/api_keys.rs b/crates/api_models/src/api_keys.rs index 65cc6b9a25a7..d25cd989b0f0 100644 --- a/crates/api_models/src/api_keys.rs +++ b/crates/api_models/src/api_keys.rs @@ -29,8 +29,8 @@ pub struct CreateApiKeyRequest { #[derive(Debug, Serialize, ToSchema)] pub struct CreateApiKeyResponse { /// The identifier for the API Key. - #[schema(max_length = 64, example = "5hEEqkgJUyuxgSKGArHA4mWSnX")] - pub key_id: String, + #[schema(max_length = 64, example = "5hEEqkgJUyuxgSKGArHA4mWSnX", value_type = String)] + pub key_id: common_utils::id_type::ApiKeyId, /// The identifier for the Merchant Account. #[schema(max_length = 64, example = "y3oqhf46pyzuxjbcn2giaqnb44", value_type = String)] @@ -72,8 +72,8 @@ pub struct CreateApiKeyResponse { #[derive(Debug, Serialize, ToSchema)] pub struct RetrieveApiKeyResponse { /// The identifier for the API Key. - #[schema(max_length = 64, example = "5hEEqkgJUyuxgSKGArHA4mWSnX")] - pub key_id: String, + #[schema(max_length = 64, example = "5hEEqkgJUyuxgSKGArHA4mWSnX", value_type = String)] + pub key_id: common_utils::id_type::ApiKeyId, /// The identifier for the Merchant Account. #[schema(max_length = 64, example = "y3oqhf46pyzuxjbcn2giaqnb44", value_type = String)] @@ -131,7 +131,8 @@ pub struct UpdateApiKeyRequest { pub expiration: Option, #[serde(skip_deserializing)] - pub key_id: String, + #[schema(value_type = String)] + pub key_id: common_utils::id_type::ApiKeyId, #[serde(skip_deserializing)] #[schema(value_type = String)] @@ -146,8 +147,8 @@ pub struct RevokeApiKeyResponse { pub merchant_id: common_utils::id_type::MerchantId, /// The identifier for the API Key. - #[schema(max_length = 64, example = "5hEEqkgJUyuxgSKGArHA4mWSnX")] - pub key_id: String, + #[schema(max_length = 64, example = "5hEEqkgJUyuxgSKGArHA4mWSnX", value_type = String)] + pub key_id: common_utils::id_type::ApiKeyId, /// Indicates whether the API key was revoked or not. #[schema(example = "true")] pub revoked: bool, diff --git a/crates/api_models/src/connector_enums.rs b/crates/api_models/src/connector_enums.rs new file mode 100644 index 000000000000..68fd73cd0de0 --- /dev/null +++ b/crates/api_models/src/connector_enums.rs @@ -0,0 +1,299 @@ +pub use common_enums::enums::{PaymentMethod, PayoutType}; +#[cfg(feature = "dummy_connector")] +use common_utils::errors; +use utoipa::ToSchema; + +/// A connector is an integration to fulfill payments +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + ToSchema, + serde::Deserialize, + serde::Serialize, + strum::VariantNames, + strum::EnumIter, + strum::Display, + strum::EnumString, + Hash, +)] +#[serde(rename_all = "snake_case")] +#[strum(serialize_all = "snake_case")] +pub enum Connector { + Adyenplatform, + #[cfg(feature = "dummy_connector")] + #[serde(rename = "phonypay")] + #[strum(serialize = "phonypay")] + DummyConnector1, + #[cfg(feature = "dummy_connector")] + #[serde(rename = "fauxpay")] + #[strum(serialize = "fauxpay")] + DummyConnector2, + #[cfg(feature = "dummy_connector")] + #[serde(rename = "pretendpay")] + #[strum(serialize = "pretendpay")] + DummyConnector3, + #[cfg(feature = "dummy_connector")] + #[serde(rename = "stripe_test")] + #[strum(serialize = "stripe_test")] + DummyConnector4, + #[cfg(feature = "dummy_connector")] + #[serde(rename = "adyen_test")] + #[strum(serialize = "adyen_test")] + DummyConnector5, + #[cfg(feature = "dummy_connector")] + #[serde(rename = "checkout_test")] + #[strum(serialize = "checkout_test")] + DummyConnector6, + #[cfg(feature = "dummy_connector")] + #[serde(rename = "paypal_test")] + #[strum(serialize = "paypal_test")] + DummyConnector7, + Aci, + Adyen, + Airwallex, + Authorizedotnet, + Bambora, + Bamboraapac, + Bankofamerica, + Billwerk, + Bitpay, + Bluesnap, + Boku, + Braintree, + Cashtocode, + Checkout, + Coinbase, + Cryptopay, + Cybersource, + Datatrans, + Deutschebank, + // Digitalvirgo, template code for future usage + Dlocal, + Ebanx, + Fiserv, + Fiservemea, + Fiuu, + Forte, + Globalpay, + Globepay, + Gocardless, + Gpayments, + Helcim, + Iatapay, + Itaubank, + //Jpmorgan, + Klarna, + Mifinity, + Mollie, + Multisafepay, + Netcetera, + Nexinets, + Nexixpay, + Nmi, + Noon, + Novalnet, + Nuvei, + // Opayo, added as template code for future usage + Opennode, + Paybox, + // Payeezy, As psync and rsync are not supported by this connector, it is added as template code for future usage + Payme, + Payone, + Paypal, + Payu, + Placetopay, + Powertranz, + Prophetpay, + Rapyd, + Razorpay, + Shift4, + Square, + Stax, + Stripe, + Taxjar, + Threedsecureio, + //Thunes, + Trustpay, + Tsys, + Volt, + Wellsfargo, + // Wellsfargopayout, + Wise, + Worldline, + Worldpay, + Signifyd, + Plaid, + Riskified, + Zen, + Zsl, +} + +impl Connector { + #[cfg(feature = "payouts")] + pub fn supports_instant_payout(&self, payout_method: Option) -> bool { + matches!( + (self, payout_method), + (Self::Paypal, Some(PayoutType::Wallet)) + | (_, Some(PayoutType::Card)) + | (Self::Adyenplatform, _) + ) + } + #[cfg(feature = "payouts")] + pub fn supports_create_recipient(&self, payout_method: Option) -> bool { + matches!((self, payout_method), (_, Some(PayoutType::Bank))) + } + #[cfg(feature = "payouts")] + pub fn supports_payout_eligibility(&self, payout_method: Option) -> bool { + matches!((self, payout_method), (_, Some(PayoutType::Card))) + } + #[cfg(feature = "payouts")] + pub fn is_payout_quote_call_required(&self) -> bool { + matches!(self, Self::Wise) + } + #[cfg(feature = "payouts")] + pub fn supports_access_token_for_payout(&self, payout_method: Option) -> bool { + matches!((self, payout_method), (Self::Paypal, _)) + } + #[cfg(feature = "payouts")] + pub fn supports_vendor_disburse_account_create_for_payout(&self) -> bool { + matches!(self, Self::Stripe) + } + pub fn supports_access_token(&self, payment_method: PaymentMethod) -> bool { + matches!( + (self, payment_method), + (Self::Airwallex, _) + | (Self::Deutschebank, _) + | (Self::Globalpay, _) + | (Self::Paypal, _) + | (Self::Payu, _) + | (Self::Trustpay, PaymentMethod::BankRedirect) + | (Self::Iatapay, _) + | (Self::Volt, _) + | (Self::Itaubank, _) + ) + } + pub fn supports_file_storage_module(&self) -> bool { + matches!(self, Self::Stripe | Self::Checkout) + } + pub fn requires_defend_dispute(&self) -> bool { + matches!(self, Self::Checkout) + } + pub fn is_separate_authentication_supported(&self) -> bool { + match self { + #[cfg(feature = "dummy_connector")] + Self::DummyConnector1 + | Self::DummyConnector2 + | Self::DummyConnector3 + | Self::DummyConnector4 + | Self::DummyConnector5 + | Self::DummyConnector6 + | Self::DummyConnector7 => false, + Self::Aci + // Add Separate authentication support for connectors + | Self::Adyen + | Self::Adyenplatform + | Self::Airwallex + | Self::Authorizedotnet + | Self::Bambora + | Self::Bamboraapac + | Self::Bankofamerica + | Self::Billwerk + | Self::Bitpay + | Self::Bluesnap + | Self::Boku + | Self::Braintree + | Self::Cashtocode + | Self::Coinbase + | Self::Cryptopay + | Self::Deutschebank + | Self::Dlocal + | Self::Ebanx + | Self::Fiserv + | Self::Fiservemea + | Self::Fiuu + | Self::Forte + | Self::Globalpay + | Self::Globepay + | Self::Gocardless + | Self::Gpayments + | Self::Helcim + | Self::Iatapay + | Self::Itaubank + //| Self::Jpmorgan + | Self::Klarna + | Self::Mifinity + | Self::Mollie + | Self::Multisafepay + | Self::Nexinets + | Self::Nexixpay + | Self::Novalnet + | Self::Nuvei + | Self::Opennode + | Self::Paybox + | Self::Payme + | Self::Payone + | Self::Paypal + | Self::Payu + | Self::Placetopay + | Self::Powertranz + | Self::Prophetpay + | Self::Rapyd + | Self::Shift4 + | Self::Square + | Self::Stax + | Self::Taxjar + // | Self::Thunes + | Self::Trustpay + | Self::Tsys + | Self::Volt + | Self::Wellsfargo + // | Self::Wellsfargopayout + | Self::Wise + | Self::Worldline + | Self::Worldpay + | Self::Zen + | Self::Zsl + | Self::Signifyd + | Self::Plaid + | Self::Razorpay + | Self::Riskified + | Self::Threedsecureio + | Self::Datatrans + | Self::Netcetera + | Self::Noon + | Self::Stripe => false, + Self::Checkout | Self::Nmi | Self::Cybersource => true, + } + } + pub fn is_pre_processing_required_before_authorize(&self) -> bool { + matches!(self, Self::Airwallex) + } + #[cfg(feature = "dummy_connector")] + pub fn validate_dummy_connector_enabled( + &self, + is_dummy_connector_enabled: bool, + ) -> errors::CustomResult<(), errors::ValidationError> { + if !is_dummy_connector_enabled + && matches!( + self, + Self::DummyConnector1 + | Self::DummyConnector2 + | Self::DummyConnector3 + | Self::DummyConnector4 + | Self::DummyConnector5 + | Self::DummyConnector6 + | Self::DummyConnector7 + ) + { + Err(errors::ValidationError::InvalidValue { + message: "Invalid connector name".to_string(), + } + .into()) + } else { + Ok(()) + } + } +} diff --git a/crates/api_models/src/connector_onboarding.rs b/crates/api_models/src/connector_onboarding.rs index 2dca57d5953f..e86f4a6f2fa9 100644 --- a/crates/api_models/src/connector_onboarding.rs +++ b/crates/api_models/src/connector_onboarding.rs @@ -42,7 +42,7 @@ pub enum PayPalOnboardingStatus { MorePermissionsNeeded, EmailNotVerified, Success(PayPalOnboardingDone), - ConnectorIntegrated(admin::MerchantConnectorResponse), + ConnectorIntegrated(Box), } #[derive(serde::Serialize, Debug, Clone)] diff --git a/crates/api_models/src/customers.rs b/crates/api_models/src/customers.rs index eb196a720746..4f6411a42cd9 100644 --- a/crates/api_models/src/customers.rs +++ b/crates/api_models/src/customers.rs @@ -1,12 +1,5 @@ -use common_utils::{ - crypto, custom_serde, - encryption::Encryption, - id_type, - pii::{self, EmailStrategy}, - types::{keymanager::ToEncryptable, Description}, -}; -use masking::{ExposeInterface, Secret, SwitchStrategy}; -use rustc_hash::FxHashMap; +use common_utils::{crypto, custom_serde, id_type, pii, types::Description}; +use masking::Secret; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; @@ -129,85 +122,6 @@ impl CustomerRequest { } } -pub struct CustomerRequestWithEmail { - pub name: Option>, - pub email: Option, - pub phone: Option>, -} - -pub struct CustomerRequestWithEncryption { - pub name: Option, - pub phone: Option, - pub email: Option, -} - -pub struct EncryptableCustomer { - pub name: crypto::OptionalEncryptableName, - pub phone: crypto::OptionalEncryptablePhone, - pub email: crypto::OptionalEncryptableEmail, -} - -impl ToEncryptable, Encryption> - for CustomerRequestWithEncryption -{ - fn to_encryptable(self) -> FxHashMap { - let mut map = FxHashMap::with_capacity_and_hasher(3, Default::default()); - self.name.map(|x| map.insert("name".to_string(), x)); - self.phone.map(|x| map.insert("phone".to_string(), x)); - self.email.map(|x| map.insert("email".to_string(), x)); - map - } - - fn from_encryptable( - mut hashmap: FxHashMap>>, - ) -> common_utils::errors::CustomResult - { - Ok(EncryptableCustomer { - name: hashmap.remove("name"), - phone: hashmap.remove("phone"), - email: hashmap.remove("email").map(|email| { - let encryptable: crypto::Encryptable> = - crypto::Encryptable::new( - email.clone().into_inner().switch_strategy(), - email.into_encrypted(), - ); - encryptable - }), - }) - } -} - -impl ToEncryptable, Secret> - for CustomerRequestWithEmail -{ - fn to_encryptable(self) -> FxHashMap> { - let mut map = FxHashMap::with_capacity_and_hasher(3, Default::default()); - self.name.map(|x| map.insert("name".to_string(), x)); - self.phone.map(|x| map.insert("phone".to_string(), x)); - self.email - .map(|x| map.insert("email".to_string(), x.expose().switch_strategy())); - map - } - - fn from_encryptable( - mut hashmap: FxHashMap>>, - ) -> common_utils::errors::CustomResult - { - Ok(EncryptableCustomer { - name: hashmap.remove("name"), - email: hashmap.remove("email").map(|email| { - let encryptable: crypto::Encryptable> = - crypto::Encryptable::new( - email.clone().into_inner().switch_strategy(), - email.into_encrypted(), - ); - encryptable - }), - phone: hashmap.remove("phone"), - }) - } -} - #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] #[derive(Debug, Clone, Serialize, ToSchema)] pub struct CustomerResponse { diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs index 48939e430595..e2b2b7fde46f 100644 --- a/crates/api_models/src/enums.rs +++ b/crates/api_models/src/enums.rs @@ -1,10 +1,10 @@ use std::str::FromStr; pub use common_enums::*; -#[cfg(feature = "dummy_connector")] -use common_utils::errors; use utoipa::ToSchema; +pub use super::connector_enums::Connector; + #[derive( Clone, Copy, @@ -27,300 +27,6 @@ pub enum RoutingAlgorithm { Custom, } -/// A connector is an integration to fulfill payments -#[derive( - Clone, - Copy, - Debug, - Eq, - PartialEq, - ToSchema, - serde::Deserialize, - serde::Serialize, - strum::VariantNames, - strum::EnumIter, - strum::Display, - strum::EnumString, - Hash, -)] -#[serde(rename_all = "snake_case")] -#[strum(serialize_all = "snake_case")] -pub enum Connector { - Adyenplatform, - #[cfg(feature = "dummy_connector")] - #[serde(rename = "phonypay")] - #[strum(serialize = "phonypay")] - DummyConnector1, - #[cfg(feature = "dummy_connector")] - #[serde(rename = "fauxpay")] - #[strum(serialize = "fauxpay")] - DummyConnector2, - #[cfg(feature = "dummy_connector")] - #[serde(rename = "pretendpay")] - #[strum(serialize = "pretendpay")] - DummyConnector3, - #[cfg(feature = "dummy_connector")] - #[serde(rename = "stripe_test")] - #[strum(serialize = "stripe_test")] - DummyConnector4, - #[cfg(feature = "dummy_connector")] - #[serde(rename = "adyen_test")] - #[strum(serialize = "adyen_test")] - DummyConnector5, - #[cfg(feature = "dummy_connector")] - #[serde(rename = "checkout_test")] - #[strum(serialize = "checkout_test")] - DummyConnector6, - #[cfg(feature = "dummy_connector")] - #[serde(rename = "paypal_test")] - #[strum(serialize = "paypal_test")] - DummyConnector7, - Aci, - Adyen, - Airwallex, - Authorizedotnet, - Bambora, - Bamboraapac, - Bankofamerica, - Billwerk, - Bitpay, - Bluesnap, - Boku, - Braintree, - Cashtocode, - Checkout, - Coinbase, - Cryptopay, - Cybersource, - Datatrans, - Deutschebank, - // Digitalvirgo, template code for future usage - Dlocal, - Ebanx, - Fiserv, - Fiservemea, - Fiuu, - Forte, - Globalpay, - Globepay, - Gocardless, - Gpayments, - Helcim, - Iatapay, - Itaubank, - Klarna, - Mifinity, - Mollie, - Multisafepay, - Netcetera, - Nexinets, - Nexixpay, - Nmi, - Noon, - Novalnet, - Nuvei, - // Opayo, added as template code for future usage - Opennode, - Paybox, - // Payeezy, As psync and rsync are not supported by this connector, it is added as template code for future usage - Payme, - Payone, - Paypal, - Payu, - Placetopay, - Powertranz, - Prophetpay, - Rapyd, - Razorpay, - Shift4, - Square, - Stax, - Stripe, - Taxjar, - Threedsecureio, - //Thunes, - Trustpay, - Tsys, - Volt, - Wellsfargo, - // Wellsfargopayout, - Wise, - Worldline, - Worldpay, - Signifyd, - Plaid, - Riskified, - Zen, - Zsl, -} - -impl Connector { - #[cfg(feature = "payouts")] - pub fn supports_instant_payout(&self, payout_method: Option) -> bool { - matches!( - (self, payout_method), - (Self::Paypal, Some(PayoutType::Wallet)) - | (_, Some(PayoutType::Card)) - | (Self::Adyenplatform, _) - ) - } - #[cfg(feature = "payouts")] - pub fn supports_create_recipient(&self, payout_method: Option) -> bool { - matches!((self, payout_method), (_, Some(PayoutType::Bank))) - } - #[cfg(feature = "payouts")] - pub fn supports_payout_eligibility(&self, payout_method: Option) -> bool { - matches!((self, payout_method), (_, Some(PayoutType::Card))) - } - #[cfg(feature = "payouts")] - pub fn is_payout_quote_call_required(&self) -> bool { - matches!(self, Self::Wise) - } - #[cfg(feature = "payouts")] - pub fn supports_access_token_for_payout(&self, payout_method: Option) -> bool { - matches!((self, payout_method), (Self::Paypal, _)) - } - #[cfg(feature = "payouts")] - pub fn supports_vendor_disburse_account_create_for_payout(&self) -> bool { - matches!(self, Self::Stripe) - } - pub fn supports_access_token(&self, payment_method: PaymentMethod) -> bool { - matches!( - (self, payment_method), - (Self::Airwallex, _) - | (Self::Deutschebank, _) - | (Self::Globalpay, _) - | (Self::Paypal, _) - | (Self::Payu, _) - | (Self::Trustpay, PaymentMethod::BankRedirect) - | (Self::Iatapay, _) - | (Self::Volt, _) - | (Self::Itaubank, _) - ) - } - pub fn supports_file_storage_module(&self) -> bool { - matches!(self, Self::Stripe | Self::Checkout) - } - pub fn requires_defend_dispute(&self) -> bool { - matches!(self, Self::Checkout) - } - pub fn is_separate_authentication_supported(&self) -> bool { - match self { - #[cfg(feature = "dummy_connector")] - Self::DummyConnector1 - | Self::DummyConnector2 - | Self::DummyConnector3 - | Self::DummyConnector4 - | Self::DummyConnector5 - | Self::DummyConnector6 - | Self::DummyConnector7 => false, - Self::Aci - // Add Separate authentication support for connectors - // | Self::Fiuu - | Self::Adyen - | Self::Adyenplatform - | Self::Airwallex - | Self::Authorizedotnet - | Self::Bambora - | Self::Bamboraapac - | Self::Bankofamerica - | Self::Billwerk - | Self::Bitpay - | Self::Bluesnap - | Self::Boku - | Self::Braintree - | Self::Cashtocode - | Self::Coinbase - | Self::Cryptopay - | Self::Deutschebank - | Self::Dlocal - | Self::Ebanx - | Self::Fiserv - | Self::Fiservemea - | Self::Fiuu - | Self::Forte - | Self::Globalpay - | Self::Globepay - | Self::Gocardless - | Self::Gpayments - | Self::Helcim - | Self::Iatapay - | Self::Itaubank - | Self::Klarna - | Self::Mifinity - | Self::Mollie - | Self::Multisafepay - | Self::Nexinets - | Self::Nexixpay - | Self::Novalnet - | Self::Nuvei - | Self::Opennode - | Self::Paybox - | Self::Payme - | Self::Payone - | Self::Paypal - | Self::Payu - | Self::Placetopay - | Self::Powertranz - | Self::Prophetpay - | Self::Rapyd - | Self::Shift4 - | Self::Square - | Self::Stax - | Self::Taxjar - //| Self::Thunes - | Self::Trustpay - | Self::Tsys - | Self::Volt - | Self::Wellsfargo - // | Self::Wellsfargopayout - | Self::Wise - | Self::Worldline - | Self::Worldpay - | Self::Zen - | Self::Zsl - | Self::Signifyd - | Self::Plaid - | Self::Razorpay - | Self::Riskified - | Self::Threedsecureio - | Self::Datatrans - | Self::Netcetera - | Self::Noon - | Self::Stripe => false, - Self::Checkout | Self::Nmi | Self::Cybersource => true, - } - } - pub fn is_pre_processing_required_before_authorize(&self) -> bool { - matches!(self, Self::Airwallex) - } - #[cfg(feature = "dummy_connector")] - pub fn validate_dummy_connector_enabled( - &self, - is_dummy_connector_enabled: bool, - ) -> errors::CustomResult<(), errors::ValidationError> { - if !is_dummy_connector_enabled - && matches!( - self, - Self::DummyConnector1 - | Self::DummyConnector2 - | Self::DummyConnector3 - | Self::DummyConnector4 - | Self::DummyConnector5 - | Self::DummyConnector6 - | Self::DummyConnector7 - ) - { - Err(errors::ValidationError::InvalidValue { - message: "Invalid connector name".to_string(), - } - .into()) - } else { - Ok(()) - } - } -} - #[cfg(feature = "payouts")] #[derive( Clone, diff --git a/crates/api_models/src/events/payment.rs b/crates/api_models/src/events/payment.rs index 7bbff94d453e..b9dc1476fdb8 100644 --- a/crates/api_models/src/events/payment.rs +++ b/crates/api_models/src/events/payment.rs @@ -1,9 +1,10 @@ use common_utils::events::{ApiEventMetric, ApiEventsType}; #[cfg(feature = "v2")] -use super::PaymentsCreateIntentRequest; -#[cfg(feature = "v2")] -use super::PaymentsCreateIntentResponse; +use super::{ + PaymentsConfirmIntentResponse, PaymentsCreateIntentRequest, PaymentsGetIntentRequest, + PaymentsIntentResponse, +}; #[cfg(all( any(feature = "v2", feature = "v1"), not(feature = "payment_methods_v2") @@ -20,7 +21,7 @@ use crate::{ PaymentMethodResponse, PaymentMethodUpdate, }, payments::{ - ExtendedCardInfoResponse, PaymentIdType, PaymentListConstraints, + self, ExtendedCardInfoResponse, PaymentIdType, PaymentListConstraints, PaymentListFilterConstraints, PaymentListFilters, PaymentListFiltersV2, PaymentListResponse, PaymentListResponseV2, PaymentsAggregateResponse, PaymentsApproveRequest, PaymentsCancelRequest, PaymentsCaptureRequest, @@ -29,8 +30,8 @@ use crate::{ PaymentsExternalAuthenticationResponse, PaymentsIncrementalAuthorizationRequest, PaymentsManualUpdateRequest, PaymentsManualUpdateResponse, PaymentsPostSessionTokensRequest, PaymentsPostSessionTokensResponse, PaymentsRejectRequest, - PaymentsRequest, PaymentsResponse, PaymentsRetrieveRequest, PaymentsSessionResponse, - PaymentsStartRequest, RedirectionResponse, + PaymentsResponse, PaymentsRetrieveRequest, PaymentsSessionResponse, PaymentsStartRequest, + RedirectionResponse, }, }; @@ -131,7 +132,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 { @@ -150,7 +151,25 @@ impl ApiEventMetric for PaymentsCreateIntentRequest { } #[cfg(feature = "v2")] -impl ApiEventMetric for PaymentsCreateIntentResponse { +impl ApiEventMetric for PaymentsGetIntentRequest { + fn get_api_event_type(&self) -> Option { + Some(ApiEventsType::Payment { + payment_id: self.id.clone(), + }) + } +} + +#[cfg(feature = "v2")] +impl ApiEventMetric for PaymentsIntentResponse { + fn get_api_event_type(&self) -> Option { + Some(ApiEventsType::Payment { + payment_id: self.id.clone(), + }) + } +} + +#[cfg(feature = "v2")] +impl ApiEventMetric for PaymentsConfirmIntentResponse { fn get_api_event_type(&self) -> Option { Some(ApiEventsType::Payment { payment_id: self.id.clone(), diff --git a/crates/api_models/src/events/refund.rs b/crates/api_models/src/events/refund.rs index d180753735f3..e87ae1544714 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/events/user_role.rs b/crates/api_models/src/events/user_role.rs index a2c76ecc3944..e0df36a3349c 100644 --- a/crates/api_models/src/events/user_role.rs +++ b/crates/api_models/src/events/user_role.rs @@ -2,8 +2,9 @@ use common_utils::events::{ApiEventMetric, ApiEventsType}; use crate::user_role::{ role::{ - CreateRoleRequest, GetRoleRequest, ListRolesAtEntityLevelRequest, ListRolesRequest, - RoleInfoResponseNew, RoleInfoWithGroupsResponse, UpdateRoleRequest, + CreateRoleRequest, GetRoleRequest, GroupsAndResources, ListRolesAtEntityLevelRequest, + ListRolesRequest, RoleInfoResponseNew, RoleInfoWithGroupsResponse, RoleInfoWithParents, + UpdateRoleRequest, }, AuthorizationInfoResponse, DeleteUserRoleRequest, ListUsersInEntityRequest, UpdateUserRoleRequest, @@ -22,6 +23,8 @@ common_utils::impl_api_event_type!( RoleInfoResponseNew, RoleInfoWithGroupsResponse, ListUsersInEntityRequest, - ListRolesRequest + ListRolesRequest, + GroupsAndResources, + RoleInfoWithParents ) ); diff --git a/crates/api_models/src/lib.rs b/crates/api_models/src/lib.rs index daa329a76317..a28332e7fea0 100644 --- a/crates/api_models/src/lib.rs +++ b/crates/api_models/src/lib.rs @@ -5,6 +5,7 @@ pub mod apple_pay_certificates_migration; pub mod blocklist; pub mod cards_info; pub mod conditional_configs; +pub mod connector_enums; pub mod connector_onboarding; pub mod consts; pub mod currency; diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index 84106a87d9b6..47460e73b713 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -6,6 +6,8 @@ use cards::CardNumber; use common_utils::{ consts::SURCHARGE_PERCENTAGE_PRECISION_LENGTH, crypto::OptionalEncryptableName, + errors, + ext_traits::OptionExt, id_type, link_utils, pii, types::{MinorUnit, Percentage, Surcharge}, }; @@ -1217,12 +1219,14 @@ pub struct ResponsePaymentMethodIntermediate { pub card_networks: Option>, pub payment_method: api_enums::PaymentMethod, pub connector: String, + pub merchant_connector_id: String, } impl ResponsePaymentMethodIntermediate { pub fn new( pm_type: RequestPaymentMethodTypes, connector: String, + merchant_connector_id: String, pm: api_enums::PaymentMethod, ) -> Self { Self { @@ -1231,6 +1235,7 @@ impl ResponsePaymentMethodIntermediate { card_networks: pm_type.card_networks, payment_method: pm, connector, + merchant_connector_id, } } } @@ -2062,16 +2067,16 @@ pub struct PaymentMethodRecord { pub email: Option, pub phone: Option>, pub phone_country_code: Option, - pub merchant_id: id_type::MerchantId, + pub merchant_id: Option, pub payment_method: Option, pub payment_method_type: Option, pub nick_name: masking::Secret, - pub payment_instrument_id: masking::Secret, + pub payment_instrument_id: Option>, pub card_number_masked: masking::Secret, pub card_expiry_month: masking::Secret, pub card_expiry_year: masking::Secret, pub card_scheme: Option, - pub original_transaction_id: String, + pub original_transaction_id: Option, pub billing_address_zip: masking::Secret, pub billing_address_state: masking::Secret, pub billing_address_first_name: masking::Secret, @@ -2082,7 +2087,7 @@ pub struct PaymentMethodRecord { pub billing_address_line2: Option>, pub billing_address_line3: Option>, pub raw_card_number: Option>, - pub merchant_connector_id: id_type::MerchantConnectorAccountId, + pub merchant_connector_id: Option, pub original_transaction_amount: Option, pub original_transaction_currency: Option, pub line_number: Option, @@ -2168,31 +2173,54 @@ impl From for PaymentMethodMigrationResponse } } -impl From for PaymentMethodMigrate { - fn from(record: PaymentMethodRecord) -> Self { - let mut mandate_reference = HashMap::new(); - mandate_reference.insert( - record.merchant_connector_id, - PaymentsMandateReferenceRecord { - connector_mandate_id: record.payment_instrument_id.peek().to_string(), - payment_method_type: record.payment_method_type, - original_payment_authorized_amount: record.original_transaction_amount, - original_payment_authorized_currency: record.original_transaction_currency, - }, - ); - Self { - merchant_id: record.merchant_id, +impl + TryFrom<( + PaymentMethodRecord, + id_type::MerchantId, + Option, + )> for PaymentMethodMigrate +{ + type Error = error_stack::Report; + fn try_from( + item: ( + PaymentMethodRecord, + id_type::MerchantId, + Option, + ), + ) -> Result { + let (record, merchant_id, mca_id) = item; + + // if payment instrument id is present then only construct this + let connector_mandate_details = if record.payment_instrument_id.is_some() { + Some(PaymentsMandateReference(HashMap::from([( + mca_id.get_required_value("merchant_connector_id")?, + PaymentsMandateReferenceRecord { + connector_mandate_id: record + .payment_instrument_id + .get_required_value("payment_instrument_id")? + .peek() + .to_string(), + payment_method_type: record.payment_method_type, + original_payment_authorized_amount: record.original_transaction_amount, + original_payment_authorized_currency: record.original_transaction_currency, + }, + )]))) + } else { + None + }; + Ok(Self { + merchant_id, customer_id: Some(record.customer_id), card: Some(MigrateCardDetail { card_number: record.raw_card_number.unwrap_or(record.card_number_masked), card_exp_month: record.card_expiry_month, card_exp_year: record.card_expiry_year, - card_holder_name: record.name, + card_holder_name: record.name.clone(), card_network: None, card_type: None, card_issuer: None, card_issuing_country: None, - nick_name: Some(record.nick_name), + nick_name: Some(record.nick_name.clone()), }), payment_method: record.payment_method, payment_method_type: record.payment_method_type, @@ -2215,7 +2243,7 @@ impl From for PaymentMethodMigrate { }), email: record.email, }), - connector_mandate_details: Some(PaymentsMandateReference(mandate_reference)), + connector_mandate_details, metadata: None, payment_method_issuer_code: None, card_network: None, @@ -2224,17 +2252,18 @@ impl From for PaymentMethodMigrate { #[cfg(feature = "payouts")] wallet: None, payment_method_data: None, - network_transaction_id: record.original_transaction_id.into(), - } + network_transaction_id: record.original_transaction_id, + }) } } #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] -impl From for customers::CustomerRequest { - fn from(record: PaymentMethodRecord) -> Self { +impl From<(PaymentMethodRecord, id_type::MerchantId)> for customers::CustomerRequest { + fn from(value: (PaymentMethodRecord, id_type::MerchantId)) -> Self { + let (record, merchant_id) = value; Self { customer_id: Some(record.customer_id), - merchant_id: record.merchant_id, + merchant_id, name: record.name, email: record.email, phone: record.phone, diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index fd1286a555ea..8fd3b5d25dc6 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, @@ -14,13 +12,12 @@ use common_utils::{ ext_traits::{ConfigExt, Encode, ValueExt}, hashing::HashedString, id_type, - pii::{self, Email, EmailStrategy}, - types::{keymanager::ToEncryptable, MinorUnit, StringMajorUnit}, + pii::{self, Email}, + types::{MinorUnit, StringMajorUnit}, }; use error_stack::ResultExt; -use masking::{ExposeInterface, PeekInterface, Secret, SwitchStrategy, WithType}; +use masking::{PeekInterface, Secret, WithType}; use router_derive::Setter; -use rustc_hash::FxHashMap; use serde::{de, ser::Serializer, Deserialize, Deserializer, Serialize}; use strum::Display; use time::{Date, PrimitiveDateTime}; @@ -117,7 +114,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 +286,23 @@ impl PaymentsCreateIntentRequest { } } -#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)] +// This struct is only used internally, not visible in API Reference +#[derive(Debug, Clone, serde::Serialize)] +#[cfg(feature = "v2")] +pub struct PaymentsGetIntentRequest { + pub id: id_type::GlobalPaymentId, +} + +#[derive(Debug, serde::Serialize, Clone, ToSchema)] #[serde(deny_unknown_fields)] #[cfg(feature = "v2")] -pub struct PaymentsCreateIntentResponse { +pub struct PaymentsIntentResponse { /// 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 +453,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 +553,7 @@ impl AmountDetails { } } +#[cfg(feature = "v1")] #[derive( Default, Debug, @@ -787,6 +853,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 +866,7 @@ fn are_optional_values_invalid( } } +#[cfg(feature = "v1")] impl PaymentsRequest { /// Get the customer id /// @@ -850,8 +918,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 +1057,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 +1067,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 +1125,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 +1223,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), @@ -1280,12 +1315,59 @@ pub struct NetworkTokenWithNTIRef { #[derive(Debug, serde::Deserialize, serde::Serialize, Clone, Eq, PartialEq)] pub struct ConnectorMandateReferenceId { - pub connector_mandate_id: Option, - pub payment_method_id: Option, - pub update_history: Option>, - pub mandate_metadata: Option, -} + connector_mandate_id: Option, + payment_method_id: Option, + update_history: Option>, + mandate_metadata: Option, + connector_mandate_request_reference_id: Option, +} + +impl ConnectorMandateReferenceId { + pub fn new( + connector_mandate_id: Option, + payment_method_id: Option, + update_history: Option>, + mandate_metadata: Option, + connector_mandate_request_reference_id: Option, + ) -> Self { + Self { + connector_mandate_id, + payment_method_id, + update_history, + mandate_metadata, + connector_mandate_request_reference_id, + } + } + pub fn get_connector_mandate_id(&self) -> Option { + self.connector_mandate_id.clone() + } + pub fn get_payment_method_id(&self) -> Option { + self.payment_method_id.clone() + } + pub fn get_mandate_metadata(&self) -> Option { + self.mandate_metadata.clone() + } + pub fn get_connector_mandate_request_reference_id(&self) -> Option { + self.connector_mandate_request_reference_id.clone() + } + + pub fn update( + &mut self, + connector_mandate_id: Option, + payment_method_id: Option, + update_history: Option>, + mandate_metadata: Option, + connector_mandate_request_reference_id: Option, + ) { + self.connector_mandate_id = connector_mandate_id.or(self.connector_mandate_id.clone()); + self.payment_method_id = payment_method_id.or(self.payment_method_id.clone()); + self.update_history = update_history.or(self.update_history.clone()); + self.mandate_metadata = mandate_metadata.or(self.mandate_metadata.clone()); + self.connector_mandate_request_reference_id = connector_mandate_request_reference_id + .or(self.connector_mandate_request_reference_id.clone()); + } +} #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Eq, PartialEq)] pub struct UpdateHistory { pub connector_mandate_id: Option, @@ -1781,6 +1863,7 @@ impl GetAddressFromPaymentMethodData for BankDebitData { } } +#[cfg(feature = "v1")] /// Custom serializer and deserializer for PaymentMethodData mod payment_method_data_serde { @@ -1925,6 +2008,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. @@ -3534,6 +3620,7 @@ pub struct WalletResponse { details: Option, } +/// Hyperswitch supports SDK integration with Apple Pay and Google Pay wallets. For other wallets, we integrate with their respective connectors, redirecting the customer to the connector for wallet payments. As a result, we don’t receive any payment method data in the confirm call for payments made through other wallets. #[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize, ToSchema)] #[serde(rename_all = "snake_case")] pub enum WalletResponseData { @@ -3730,54 +3817,6 @@ pub struct EncryptableAddressDetails { pub email: crypto::OptionalEncryptableEmail, } -impl ToEncryptable, Secret> - for AddressDetailsWithPhone -{ - fn from_encryptable( - mut hashmap: FxHashMap>>, - ) -> common_utils::errors::CustomResult< - EncryptableAddressDetails, - common_utils::errors::ParsingError, - > { - Ok(EncryptableAddressDetails { - line1: hashmap.remove("line1"), - line2: hashmap.remove("line2"), - line3: hashmap.remove("line3"), - state: hashmap.remove("state"), - zip: hashmap.remove("zip"), - first_name: hashmap.remove("first_name"), - last_name: hashmap.remove("last_name"), - phone_number: hashmap.remove("phone_number"), - email: hashmap.remove("email").map(|x| { - let inner: Secret = x.clone().into_inner().switch_strategy(); - crypto::Encryptable::new(inner, x.into_encrypted()) - }), - }) - } - - fn to_encryptable(self) -> FxHashMap> { - let mut map = FxHashMap::with_capacity_and_hasher(9, Default::default()); - self.address.map(|address| { - address.line1.map(|x| map.insert("line1".to_string(), x)); - address.line2.map(|x| map.insert("line2".to_string(), x)); - address.line3.map(|x| map.insert("line3".to_string(), x)); - address.state.map(|x| map.insert("state".to_string(), x)); - address.zip.map(|x| map.insert("zip".to_string(), x)); - address - .first_name - .map(|x| map.insert("first_name".to_string(), x)); - address - .last_name - .map(|x| map.insert("last_name".to_string(), x)); - }); - self.email - .map(|x| map.insert("email".to_string(), x.expose().switch_strategy())); - self.phone_number - .map(|x| map.insert("phone_number".to_string(), x)); - map - } -} - #[derive(Debug, Clone, Default, Eq, PartialEq, ToSchema, serde::Deserialize, serde::Serialize)] pub struct PhoneDetails { /// The contact number @@ -4400,6 +4439,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 { @@ -4585,6 +4740,7 @@ impl PaymentListFilterConstraints { && self.payment_method_type.is_none() && self.authentication_type.is_none() && self.merchant_connector_id.is_none() + && self.card_network.is_none() } } @@ -4696,6 +4852,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 +4914,7 @@ impl From for PaymentsSessionResponse { } } +#[cfg(feature = "v1")] impl From for PaymentsRequest { fn from(item: PaymentsStartRequest) -> Self { Self { @@ -4928,7 +5086,7 @@ pub struct OrderDetailsWithAmount { #[schema(example = 1)] pub quantity: u16, /// the amount per quantity of product - pub amount: i64, + pub amount: MinorUnit, // Does the order includes shipping pub requires_shipping: Option, /// The image URL of the product @@ -5426,6 +5584,15 @@ pub struct PazeSessionTokenResponse { pub client_name: String, /// Paze Client Profile ID pub client_profile_id: String, + /// The transaction currency code + #[schema(value_type = Currency, example = "USD")] + pub transaction_currency_code: api_enums::Currency, + /// The transaction amount + #[schema(value_type = String, example = "38.02")] + pub transaction_amount: StringMajorUnit, + /// Email Address + #[schema(max_length = 255, value_type = Option, example = "johntest@test.com")] + pub email_address: Option, } #[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, ToSchema)] @@ -6346,6 +6513,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/api_models/src/payouts.rs b/crates/api_models/src/payouts.rs index a7be9703d380..237d165d572c 100644 --- a/crates/api_models/src/payouts.rs +++ b/crates/api_models/src/payouts.rs @@ -19,7 +19,7 @@ use crate::{enums as api_enums, payment_methods::RequiredFieldInfo, payments}; #[derive(Debug, Deserialize, Serialize, Clone, ToSchema)] pub enum PayoutRequest { PayoutActionRequest(PayoutActionRequest), - PayoutCreateRequest(PayoutCreateRequest), + PayoutCreateRequest(Box), PayoutRetrieveRequest(PayoutRetrieveRequest), } diff --git a/crates/api_models/src/refunds.rs b/crates/api_models/src/refunds.rs index 237a903d80c0..ac5e5cb46182 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 @@ -234,7 +346,7 @@ pub struct RefundListFilters { pub refund_status: Vec, } -#[derive(Clone, Debug, serde::Serialize, ToSchema)] +#[derive(Clone, Debug, serde::Serialize)] pub struct RefundAggregateResponse { /// The list of refund status with their count pub status_with_count: HashMap, diff --git a/crates/api_models/src/routing.rs b/crates/api_models/src/routing.rs index fc65ab037c2b..47d75b2e8357 100644 --- a/crates/api_models/src/routing.rs +++ b/crates/api_models/src/routing.rs @@ -522,22 +522,51 @@ pub struct DynamicAlgorithmWithTimestamp { #[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)] pub struct DynamicRoutingAlgorithmRef { - pub success_based_algorithm: - Option>, + pub success_based_algorithm: Option, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct SuccessBasedAlgorithm { + pub algorithm_id_with_timestamp: + DynamicAlgorithmWithTimestamp, + #[serde(default)] + pub enabled_feature: SuccessBasedRoutingFeatures, +} + +impl SuccessBasedAlgorithm { + pub fn update_enabled_features(&mut self, feature_to_enable: SuccessBasedRoutingFeatures) { + self.enabled_feature = feature_to_enable + } } impl DynamicRoutingAlgorithmRef { - pub fn update_algorithm_id(&mut self, new_id: common_utils::id_type::RoutingId) { - self.success_based_algorithm = Some(DynamicAlgorithmWithTimestamp { - algorithm_id: Some(new_id), - timestamp: common_utils::date_time::now_unix_timestamp(), + pub fn update_algorithm_id( + &mut self, + new_id: common_utils::id_type::RoutingId, + enabled_feature: SuccessBasedRoutingFeatures, + ) { + self.success_based_algorithm = Some(SuccessBasedAlgorithm { + algorithm_id_with_timestamp: DynamicAlgorithmWithTimestamp { + algorithm_id: Some(new_id), + timestamp: common_utils::date_time::now_unix_timestamp(), + }, + enabled_feature, }) } } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)] pub struct ToggleSuccessBasedRoutingQuery { - pub status: bool, + pub enable: SuccessBasedRoutingFeatures, +} + +#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum SuccessBasedRoutingFeatures { + Metrics, + DynamicConnectorSelection, + #[default] + None, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)] @@ -551,7 +580,7 @@ pub struct SuccessBasedRoutingUpdateConfigQuery { #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] pub struct ToggleSuccessBasedRoutingWrapper { pub profile_id: common_utils::id_type::ProfileId, - pub status: bool, + pub feature_to_enable: SuccessBasedRoutingFeatures, } #[derive(Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] diff --git a/crates/api_models/src/user.rs b/crates/api_models/src/user.rs index 089089038b8a..089426c68ba6 100644 --- a/crates/api_models/src/user.rs +++ b/crates/api_models/src/user.rs @@ -211,6 +211,7 @@ pub struct TwoFactorAuthStatusResponseWithAttempts { #[derive(Debug, serde::Deserialize, serde::Serialize)] pub struct TwoFactorStatus { pub status: Option, + pub is_skippable: bool, } #[derive(Debug, serde::Deserialize, serde::Serialize)] diff --git a/crates/api_models/src/user_role.rs b/crates/api_models/src/user_role.rs index ab32651e7293..19027c3cbf86 100644 --- a/crates/api_models/src/user_role.rs +++ b/crates/api_models/src/user_role.rs @@ -1,59 +1,9 @@ -use common_enums::PermissionGroup; +use common_enums::{ParentGroup, PermissionGroup}; use common_utils::pii; 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, - Connectors, - Workflows, - Analytics, - Users, - #[serde(rename = "MerchantAccess")] - Merchant, - #[serde(rename = "OrganizationAccess")] - Organization, - Recon, -} - #[derive(Debug, serde::Serialize)] pub struct AuthorizationInfoResponse(pub Vec); @@ -69,7 +19,6 @@ pub enum AuthorizationInfo { pub struct GroupInfo { pub group: PermissionGroup, pub description: &'static str, - pub permissions: Vec, } #[derive(Debug, serde::Serialize, Clone)] @@ -79,12 +28,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/api_models/src/user_role/role.rs b/crates/api_models/src/user_role/role.rs index 885ec455e4cf..7c877cd74777 100644 --- a/crates/api_models/src/user_role/role.rs +++ b/crates/api_models/src/user_role/role.rs @@ -1,5 +1,6 @@ -pub use common_enums::PermissionGroup; -use common_enums::{EntityType, RoleScope}; +use common_enums::{ + EntityType, ParentGroup, PermissionGroup, PermissionScope, Resource, RoleScope, +}; #[derive(Debug, serde::Deserialize, serde::Serialize)] pub struct CreateRoleRequest { @@ -22,6 +23,21 @@ pub struct RoleInfoWithGroupsResponse { pub role_scope: RoleScope, } +#[derive(Debug, serde::Serialize)] +pub struct RoleInfoWithParents { + pub role_id: String, + pub parent_groups: Vec, + pub role_name: String, + pub role_scope: RoleScope, +} + +#[derive(Debug, serde::Serialize)] +pub struct ParentGroupInfo { + pub name: ParentGroup, + pub description: String, + pub scopes: Vec, +} + #[derive(Debug, serde::Deserialize, serde::Serialize)] pub struct ListRolesRequest { pub entity_type: Option, @@ -57,3 +73,9 @@ pub struct MinimalRoleInfo { pub role_id: String, pub role_name: String, } + +#[derive(Debug, serde::Serialize)] +pub struct GroupsAndResources { + pub groups: Vec, + pub resources: Vec, +} diff --git a/crates/api_models/src/webhooks.rs b/crates/api_models/src/webhooks.rs index ce9b303066ed..56a566d170ae 100644 --- a/crates/api_models/src/webhooks.rs +++ b/crates/api_models/src/webhooks.rs @@ -229,16 +229,16 @@ pub struct OutgoingWebhook { #[serde(tag = "type", content = "object", rename_all = "snake_case")] pub enum OutgoingWebhookContent { #[schema(value_type = PaymentsResponse, title = "PaymentsResponse")] - PaymentDetails(payments::PaymentsResponse), + PaymentDetails(Box), #[schema(value_type = RefundResponse, title = "RefundResponse")] - RefundDetails(refunds::RefundResponse), + RefundDetails(Box), #[schema(value_type = DisputeResponse, title = "DisputeResponse")] DisputeDetails(Box), #[schema(value_type = MandateResponse, title = "MandateResponse")] MandateDetails(Box), #[cfg(feature = "payouts")] #[schema(value_type = PayoutCreateResponse, title = "PayoutCreateResponse")] - PayoutDetails(payouts::PayoutCreateResponse), + PayoutDetails(Box), } #[derive(Debug, Clone, Serialize)] diff --git a/crates/common_enums/src/connector_enums.rs b/crates/common_enums/src/connector_enums.rs new file mode 100644 index 000000000000..386b4c35a4b7 --- /dev/null +++ b/crates/common_enums/src/connector_enums.rs @@ -0,0 +1,127 @@ +use utoipa::ToSchema; +#[derive( + Clone, + Copy, + Debug, + Eq, + Hash, + PartialEq, + serde::Serialize, + serde::Deserialize, + strum::Display, + strum::EnumString, + strum::EnumIter, + strum::VariantNames, + ToSchema, +)] +#[router_derive::diesel_enum(storage_type = "db_enum")] +#[serde(rename_all = "snake_case")] +#[strum(serialize_all = "snake_case")] +/// Connectors eligible for payments routing +pub enum RoutableConnectors { + Adyenplatform, + #[cfg(feature = "dummy_connector")] + #[serde(rename = "phonypay")] + #[strum(serialize = "phonypay")] + DummyConnector1, + #[cfg(feature = "dummy_connector")] + #[serde(rename = "fauxpay")] + #[strum(serialize = "fauxpay")] + DummyConnector2, + #[cfg(feature = "dummy_connector")] + #[serde(rename = "pretendpay")] + #[strum(serialize = "pretendpay")] + DummyConnector3, + #[cfg(feature = "dummy_connector")] + #[serde(rename = "stripe_test")] + #[strum(serialize = "stripe_test")] + DummyConnector4, + #[cfg(feature = "dummy_connector")] + #[serde(rename = "adyen_test")] + #[strum(serialize = "adyen_test")] + DummyConnector5, + #[cfg(feature = "dummy_connector")] + #[serde(rename = "checkout_test")] + #[strum(serialize = "checkout_test")] + DummyConnector6, + #[cfg(feature = "dummy_connector")] + #[serde(rename = "paypal_test")] + #[strum(serialize = "paypal_test")] + DummyConnector7, + Aci, + Adyen, + Airwallex, + Authorizedotnet, + Bankofamerica, + Billwerk, + Bitpay, + Bambora, + Bamboraapac, + Bluesnap, + Boku, + Braintree, + Cashtocode, + Checkout, + Coinbase, + Cryptopay, + Cybersource, + Datatrans, + Deutschebank, + // Digitalvirgo, template code for future usage + Dlocal, + Ebanx, + Fiserv, + Fiservemea, + Fiuu, + Forte, + Globalpay, + Globepay, + Gocardless, + Helcim, + Iatapay, + Itaubank, + //Jpmorgan, + Klarna, + Mifinity, + Mollie, + Multisafepay, + Nexinets, + Nexixpay, + Nmi, + Noon, + Novalnet, + Nuvei, + // Opayo, added as template code for future usage + Opennode, + // Payeezy, As psync and rsync are not supported by this connector, it is added as template code for future usage + Paybox, + Payme, + Payone, + Paypal, + Payu, + Placetopay, + Powertranz, + Prophetpay, + Rapyd, + Razorpay, + Riskified, + Shift4, + Signifyd, + Square, + Stax, + Stripe, + // Taxjar, + Trustpay, + // Thunes + // Tsys, + Tsys, + Volt, + Wellsfargo, + // Wellsfargopayout, + Wise, + Worldline, + Worldpay, + Zen, + Plaid, + Zsl, +} diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index e36a6d74994e..917030c1e80e 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -3,6 +3,8 @@ use std::num::{ParseFloatError, TryFromIntError}; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; +pub use super::connector_enums::RoutableConnectors; + #[doc(hidden)] pub mod diesel_exports { pub use super::{ @@ -140,132 +142,6 @@ pub enum AttemptStatus { DeviceDataCollectionPending, } -#[derive( - Clone, - Copy, - Debug, - Eq, - Hash, - PartialEq, - serde::Serialize, - serde::Deserialize, - strum::Display, - strum::EnumString, - strum::EnumIter, - strum::VariantNames, - ToSchema, -)] -#[router_derive::diesel_enum(storage_type = "db_enum")] -#[serde(rename_all = "snake_case")] -#[strum(serialize_all = "snake_case")] -/// Connectors eligible for payments routing -pub enum RoutableConnectors { - Adyenplatform, - #[cfg(feature = "dummy_connector")] - #[serde(rename = "phonypay")] - #[strum(serialize = "phonypay")] - DummyConnector1, - #[cfg(feature = "dummy_connector")] - #[serde(rename = "fauxpay")] - #[strum(serialize = "fauxpay")] - DummyConnector2, - #[cfg(feature = "dummy_connector")] - #[serde(rename = "pretendpay")] - #[strum(serialize = "pretendpay")] - DummyConnector3, - #[cfg(feature = "dummy_connector")] - #[serde(rename = "stripe_test")] - #[strum(serialize = "stripe_test")] - DummyConnector4, - #[cfg(feature = "dummy_connector")] - #[serde(rename = "adyen_test")] - #[strum(serialize = "adyen_test")] - DummyConnector5, - #[cfg(feature = "dummy_connector")] - #[serde(rename = "checkout_test")] - #[strum(serialize = "checkout_test")] - DummyConnector6, - #[cfg(feature = "dummy_connector")] - #[serde(rename = "paypal_test")] - #[strum(serialize = "paypal_test")] - DummyConnector7, - Aci, - Adyen, - Airwallex, - Authorizedotnet, - Bankofamerica, - Billwerk, - Bitpay, - Bambora, - Bamboraapac, - Bluesnap, - Boku, - Braintree, - Cashtocode, - Checkout, - Coinbase, - Cryptopay, - Cybersource, - Datatrans, - Deutschebank, - // Digitalvirgo, template code for future usage - Dlocal, - Ebanx, - Fiserv, - Fiservemea, - Fiuu, - Forte, - Globalpay, - Globepay, - Gocardless, - Helcim, - Iatapay, - Itaubank, - Klarna, - Mifinity, - Mollie, - Multisafepay, - Nexinets, - Nexixpay, - Nmi, - Noon, - Novalnet, - Nuvei, - // Opayo, added as template code for future usage - Opennode, - // Payeezy, As psync and rsync are not supported by this connector, it is added as template code for future usage - Paybox, - Payme, - Payone, - Paypal, - Payu, - Placetopay, - Powertranz, - Prophetpay, - Rapyd, - Razorpay, - Riskified, - Shift4, - Signifyd, - Square, - Stax, - Stripe, - // Taxjar, - Trustpay, - // Thunes - // Tsys, - Tsys, - Volt, - Wellsfargo, - // Wellsfargopayout, - Wise, - Worldline, - Worldpay, - Zen, - Plaid, - Zsl, -} - impl AttemptStatus { pub fn is_terminal_status(self) -> bool { match self { @@ -1391,17 +1267,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, } @@ -2870,10 +2760,55 @@ pub enum PermissionGroup { AnalyticsView, UsersView, UsersManage, + // TODO: To be deprecated, make sure DB is migrated before removing MerchantDetailsView, + // TODO: To be deprecated, make sure DB is migrated before removing MerchantDetailsManage, + // TODO: To be deprecated, make sure DB is migrated before removing OrganizationManage, ReconOps, + AccountView, + AccountManage, +} + +#[derive(Clone, Debug, serde::Serialize, PartialEq, Eq, Hash, strum::EnumIter)] +pub enum ParentGroup { + Operations, + Connectors, + Workflows, + Analytics, + Users, + Recon, + Account, +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, serde::Serialize)] +#[serde(rename_all = "snake_case")] +pub enum Resource { + Payment, + Refund, + ApiKey, + Account, + Connector, + Routing, + Dispute, + Mandate, + Customer, + Analytics, + ThreeDsDecisionManager, + SurchargeDecisionManager, + User, + WebhookEvent, + Payout, + Report, + Recon, +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, serde::Serialize, Hash)] +#[serde(rename_all = "snake_case")] +pub enum PermissionScope { + Read = 0, + Write = 1, } /// Name of banks supported by Hyperswitch diff --git a/crates/common_enums/src/lib.rs b/crates/common_enums/src/lib.rs index 14966d15b5f5..ec5b78d4a508 100644 --- a/crates/common_enums/src/lib.rs +++ b/crates/common_enums/src/lib.rs @@ -1,3 +1,4 @@ +pub mod connector_enums; pub mod enums; pub mod transformers; diff --git a/crates/common_utils/src/consts.rs b/crates/common_utils/src/consts.rs index 21e5866aea00..5fc2fea9c8b2 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/common_utils/src/events.rs b/crates/common_utils/src/events.rs index 1b03f8f19f2a..a83c1d481cc7 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, @@ -45,6 +51,9 @@ pub enum ApiEventsType { BusinessProfile { profile_id: id_type::ProfileId, }, + ApiKey { + key_id: id_type::ApiKeyId, + }, User { user_id: String, }, @@ -96,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 { @@ -130,10 +148,6 @@ impl_api_event_type!( ( String, id_type::MerchantId, - (id_type::MerchantId, String), - (id_type::MerchantId, &String), - (&id_type::MerchantId, &String), - (&String, &String), (Option, Option, String), (Option, Option, id_type::MerchantId), bool diff --git a/crates/common_utils/src/id_type.rs b/crates/common_utils/src/id_type.rs index 78e3841690a1..3d57a72376ed 100644 --- a/crates/common_utils/src/id_type.rs +++ b/crates/common_utils/src/id_type.rs @@ -3,17 +3,20 @@ use std::{borrow::Cow, fmt::Debug}; +mod api_key; mod customer; mod merchant; mod merchant_connector_account; mod organization; mod payment; mod profile; +mod refunds; mod routing; #[cfg(feature = "v2")] mod global_id; +pub use api_key::ApiKeyId; pub use customer::CustomerId; use diesel::{ backend::Backend, @@ -23,12 +26,18 @@ use diesel::{ sql_types, }; #[cfg(feature = "v2")] -pub use global_id::{payment::GlobalPaymentId, payment_methods::GlobalPaymentMethodId, CellId}; +pub use global_id::{ + payment::{GlobalAttemptId, 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/api_key.rs b/crates/common_utils/src/id_type/api_key.rs new file mode 100644 index 000000000000..f252846e6ac3 --- /dev/null +++ b/crates/common_utils/src/id_type/api_key.rs @@ -0,0 +1,46 @@ +crate::id_type!( + ApiKeyId, + "A type for key_id that can be used for API key IDs" +); +crate::impl_id_type_methods!(ApiKeyId, "key_id"); + +// This is to display the `ApiKeyId` as ApiKeyId(abcd) +crate::impl_debug_id_type!(ApiKeyId); +crate::impl_try_from_cow_str_id_type!(ApiKeyId, "key_id"); + +crate::impl_serializable_secret_id_type!(ApiKeyId); +crate::impl_queryable_id_type!(ApiKeyId); +crate::impl_to_sql_from_sql_id_type!(ApiKeyId); + +impl ApiKeyId { + /// Generate Api Key Id from prefix + pub fn generate_key_id(prefix: &'static str) -> Self { + Self(crate::generate_ref_id_with_default_length(prefix)) + } +} + +impl crate::events::ApiEventMetric for ApiKeyId { + fn get_api_event_type(&self) -> Option { + Some(crate::events::ApiEventsType::ApiKey { + key_id: self.clone(), + }) + } +} + +impl crate::events::ApiEventMetric for (super::MerchantId, ApiKeyId) { + fn get_api_event_type(&self) -> Option { + Some(crate::events::ApiEventsType::ApiKey { + key_id: self.1.clone(), + }) + } +} + +impl crate::events::ApiEventMetric for (&super::MerchantId, &ApiKeyId) { + fn get_api_event_type(&self) -> Option { + Some(crate::events::ApiEventsType::ApiKey { + key_id: self.1.clone(), + }) + } +} + +crate::impl_default_id_type!(ApiKeyId, "key"); diff --git a/crates/common_utils/src/id_type/global_id.rs b/crates/common_utils/src/id_type/global_id.rs index 0709ce84d581..5490dcda7bd4 100644 --- a/crates/common_utils/src/id_type/global_id.rs +++ b/crates/common_utils/src/id_type/global_id.rs @@ -1,6 +1,6 @@ -#![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; @@ -23,7 +23,9 @@ pub(crate) struct GlobalId(LengthId) pub(crate) enum GlobalEntity { Customer, Payment, + Attempt, PaymentMethod, + Refund, } impl GlobalEntity { @@ -32,6 +34,8 @@ 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 a404c7bc9c40..6e5848e5a387 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/id_type/global_id/refunds.rs b/crates/common_utils/src/id_type/global_id/refunds.rs new file mode 100644 index 000000000000..64e475161140 --- /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/organization.rs b/crates/common_utils/src/id_type/organization.rs index f88a62daa1d6..a83f35db1d89 100644 --- a/crates/common_utils/src/id_type/organization.rs +++ b/crates/common_utils/src/id_type/organization.rs @@ -1,3 +1,5 @@ +use crate::errors::{CustomResult, ValidationError}; + crate::id_type!( OrganizationId, "A type for organization_id that can be used for organization ids" @@ -13,3 +15,10 @@ crate::impl_generate_id_id_type!(OrganizationId, "org"); crate::impl_serializable_secret_id_type!(OrganizationId); crate::impl_queryable_id_type!(OrganizationId); crate::impl_to_sql_from_sql_id_type!(OrganizationId); + +impl OrganizationId { + /// Get an organization id from String + pub fn wrap(org_id: String) -> CustomResult { + Self::try_from(std::borrow::Cow::from(org_id)) + } +} 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 000000000000..478ff03380b5 --- /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/common_utils/src/lib.rs b/crates/common_utils/src/lib.rs index 923bdf89c026..463ec3ee1b67 100644 --- a/crates/common_utils/src/lib.rs +++ b/crates/common_utils/src/lib.rs @@ -270,6 +270,11 @@ pub fn generate_time_ordered_id_without_prefix() -> String { uuid::Uuid::now_v7().as_simple().to_string() } +/// Generate a nanoid with the specified length +#[inline] +pub fn generate_id_with_len(length: usize) -> String { + nanoid::nanoid!(length, &consts::ALPHABETS) +} #[allow(missing_docs)] pub trait DbConnectionParams { fn get_username(&self) -> &str; diff --git a/crates/common_utils/src/macros.rs b/crates/common_utils/src/macros.rs index 94d8074c3014..21cec6f60fce 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 a1c9b4c00c28..ce2be525989e 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -7,7 +7,8 @@ pub mod authentication; use std::{ borrow::Cow, fmt::Display, - ops::{Add, Sub}, + iter::Sum, + ops::{Add, Mul, Sub}, primitive::i64, str::FromStr, }; @@ -483,6 +484,20 @@ impl Sub for MinorUnit { } } +impl Mul for MinorUnit { + type Output = Self; + + fn mul(self, a2: u16) -> Self::Output { + Self(self.0 * i64::from(a2)) + } +} + +impl Sum for MinorUnit { + fn sum>(iter: I) -> Self { + iter.fold(Self(0), |a, b| a + b) + } +} + /// Connector specific types to send #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, PartialEq)] @@ -580,6 +595,10 @@ impl StringMajorUnit { .ok_or(ParsingError::DecimalToI64ConversionFailure)?; Ok(MinorUnit::new(amount_i64)) } + /// forms a new StringMajorUnit default unit i.e zero + pub fn zero() -> Self { + Self("0".to_string()) + } /// Get string amount from struct to be removed in future pub fn get_amount_as_string(&self) -> String { @@ -603,6 +622,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 +693,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 +1146,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 +1329,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 0c460a9f2b32..f87289680987 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/connector_configs/src/common_config.rs b/crates/connector_configs/src/common_config.rs index d0becb80468f..26c9d33f405a 100644 --- a/crates/connector_configs/src/common_config.rs +++ b/crates/connector_configs/src/common_config.rs @@ -206,7 +206,7 @@ pub enum InputType { #[serde_with::skip_serializing_none] #[derive(Debug, Deserialize, serde::Serialize, Clone)] #[serde(rename_all = "snake_case")] -pub struct MetaDataInupt { +pub struct InputData { pub name: String, pub label: String, pub placeholder: String, diff --git a/crates/connector_configs/src/connector.rs b/crates/connector_configs/src/connector.rs index 7916efc1a84d..923edd386de7 100644 --- a/crates/connector_configs/src/connector.rs +++ b/crates/connector_configs/src/connector.rs @@ -10,7 +10,7 @@ use serde::Deserialize; #[cfg(any(feature = "sandbox", feature = "development", feature = "production"))] use toml; -use crate::common_config::{CardProvider, MetaDataInupt, Provider, ZenApplePay}; +use crate::common_config::{CardProvider, InputData, Provider, ZenApplePay}; #[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct Classic { @@ -83,38 +83,44 @@ pub enum KlarnaEndpoint { #[serde_with::skip_serializing_none] #[derive(Debug, Deserialize, serde::Serialize, Clone)] pub struct ConfigMerchantAdditionalDetails { - pub open_banking_recipient_data: Option, - pub account_data: Option, - pub iban: Option>, - pub bacs: Option>, - pub connector_recipient_id: Option, - pub wallet_id: Option, + pub open_banking_recipient_data: Option, + pub account_data: Option, + pub iban: Option>, + pub bacs: Option>, + pub connector_recipient_id: Option, + pub wallet_id: Option, } #[serde_with::skip_serializing_none] #[derive(Debug, Deserialize, serde::Serialize, Clone)] pub struct ConfigMetadata { - pub merchant_config_currency: Option, - pub merchant_account_id: Option, - pub account_name: Option, - pub terminal_id: Option, - pub google_pay: Option>, - pub apple_pay: Option>, - pub merchant_id: Option, - pub endpoint_prefix: Option, - pub mcc: Option, - pub merchant_country_code: Option, - pub merchant_name: Option, - pub acquirer_bin: Option, - pub acquirer_merchant_id: Option, - pub acquirer_country_code: Option, - pub three_ds_requestor_name: Option, - pub three_ds_requestor_id: Option, - pub pull_mechanism_for_external_3ds_enabled: Option, - pub klarna_region: Option, - pub source_balance_account: Option, - pub brand_id: Option, - pub destination_account_number: Option, + pub merchant_config_currency: Option, + pub merchant_account_id: Option, + pub account_name: Option, + pub terminal_id: Option, + pub google_pay: Option>, + pub apple_pay: Option>, + pub merchant_id: Option, + pub endpoint_prefix: Option, + pub mcc: Option, + pub merchant_country_code: Option, + pub merchant_name: Option, + pub acquirer_bin: Option, + pub acquirer_merchant_id: Option, + pub acquirer_country_code: Option, + pub three_ds_requestor_name: Option, + pub three_ds_requestor_id: Option, + pub pull_mechanism_for_external_3ds_enabled: Option, + pub klarna_region: Option, + pub source_balance_account: Option, + pub brand_id: Option, + pub destination_account_number: Option, +} + +#[serde_with::skip_serializing_none] +#[derive(Debug, Deserialize, serde::Serialize, Clone)] +pub struct ConnectorWalletDetailsConfig { + pub samsung_pay: Option>, } #[serde_with::skip_serializing_none] @@ -123,6 +129,7 @@ pub struct ConnectorTomlConfig { pub connector_auth: Option, pub connector_webhook_details: Option, pub metadata: Option>, + pub connector_wallets_details: Option>, pub additional_merchant_data: Option>, pub credit: Option>, pub debit: Option>, diff --git a/crates/connector_configs/toml/development.toml b/crates/connector_configs/toml/development.toml index 56c19637e517..886b2dd7ee7c 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" @@ -1215,6 +1215,8 @@ merchant_secret="Source verification key" payment_method_type = "google_pay" [[cybersource.wallet]] payment_method_type = "paze" +[[cybersource.wallet]] + payment_method_type = "samsung_pay" [cybersource.connector_auth.SignatureKey] api_key="Key" key1="Merchant ID" @@ -1296,6 +1298,33 @@ placeholder="Enter Google Pay Merchant Key" required=true type="Text" +[[cybersource.connector_wallets_details.samsung_pay]] +name="service_id" +label="Samsung Pay Service Id" +placeholder="Enter Samsung Pay Service Id" +required=true +type="Text" +[[cybersource.connector_wallets_details.samsung_pay]] +name="merchant_display_name" +label="Display Name" +placeholder="Enter Display Name" +required=true +type="Text" +[[cybersource.connector_wallets_details.samsung_pay]] +name="merchant_business_country" +label="Merchant Business Country" +placeholder="Enter Merchant Business Country" +required=true +type="Select" +options=[] +[[cybersource.connector_wallets_details.samsung_pay]] +name="allowed_brands" +label="Allowed Brands" +placeholder="Enter Allowed Brands" +required=true +type="MultiSelect" +options=["visa","masterCard","amex","discover"] + [cybersource.metadata.acquirer_bin] name="acquirer_bin" label="Acquirer Bin" @@ -1941,7 +1970,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 +2091,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 +2231,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" @@ -2260,12 +2289,89 @@ type="Text" payment_method_type = "CartesBancaires" [[novalnet.debit]] payment_method_type = "UnionPay" +[[novalnet.wallet]] + payment_method_type = "google_pay" +[[novalnet.wallet]] + payment_method_type = "paypal" +[[novalnet.wallet]] + payment_method_type = "apple_pay" [novalnet.connector_auth.SignatureKey] api_key="Product Activation Key" key1="Payment Access Key" api_secret="Tariff ID" [novalnet.connector_webhook_details] merchant_secret="Source verification key" +[[novalnet.metadata.google_pay]] +name="merchant_name" +label="Google Pay Merchant Name" +placeholder="Enter Google Pay Merchant Name" +required=true +type="Text" +[[novalnet.metadata.google_pay]] +name="merchant_id" +label="Google Pay Merchant Id" +placeholder="Enter Google Pay Merchant Id" +required=true +type="Text" +[[novalnet.metadata.google_pay]] +name="gateway_merchant_id" +label="Google Pay Merchant Key" +placeholder="Enter Google Pay Merchant Key" +required=true +type="Text" + +[[novalnet.metadata.apple_pay]] +name="certificate" +label="Merchant Certificate (Base64 Encoded)" +placeholder="Enter Merchant Certificate (Base64 Encoded)" +required=true +type="Text" +[[novalnet.metadata.apple_pay]] +name="certificate_keys" +label="Merchant PrivateKey (Base64 Encoded)" +placeholder="Enter Merchant PrivateKey (Base64 Encoded)" +required=true +type="Text" +[[novalnet.metadata.apple_pay]] +name="merchant_identifier" +label="Apple Merchant Identifier" +placeholder="Enter Apple Merchant Identifier" +required=true +type="Text" +[[novalnet.metadata.apple_pay]] +name="display_name" +label="Display Name" +placeholder="Enter Display Name" +required=true +type="Text" +[[novalnet.metadata.apple_pay]] +name="initiative" +label="Domain" +placeholder="Enter Domain" +required=true +type="Select" +options=["web","ios"] +[[novalnet.metadata.apple_pay]] +name="initiative_context" +label="Domain Name" +placeholder="Enter Domain Name" +required=true +type="Text" +[[novalnet.metadata.apple_pay]] +name="merchant_business_country" +label="Merchant Business Country" +placeholder="Enter Merchant Business Country" +required=true +type="Select" +options=[] +[[novalnet.metadata.apple_pay]] +name="payment_processing_details_at" +label="Payment Processing Details At" +placeholder="Enter Payment Processing Details At" +required=true +type="Radio" +options=["Connector"] + [nuvei] [[nuvei.credit]] @@ -2379,7 +2485,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 +2945,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 +3350,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" @@ -3416,6 +3522,12 @@ key1="Password" api_secret="Merchant Identifier" [worldpay.connector_webhook_details] merchant_secret="Source verification key" +[worldpay.metadata.merchant_name] +name="merchant_name" +label="Name of the merchant to de displayed during 3DS challenge" +placeholder="Enter Name of the merchant" +required=true +type="Text" [[worldpay.metadata.apple_pay]] name="certificate" @@ -3467,7 +3579,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 +4302,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 c8005087a167..cc501a4c101e 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]] @@ -1782,12 +1782,88 @@ merchant_secret="Source verification key" payment_method_type = "CartesBancaires" [[novalnet.debit]] payment_method_type = "UnionPay" +[[novalnet.wallet]] + payment_method_type = "google_pay" +[[novalnet.wallet]] + payment_method_type = "paypal" +[[novalnet.wallet]] + payment_method_type = "apple_pay" [novalnet.connector_auth.SignatureKey] api_key="Product Activation Key" key1="Payment Access Key" api_secret="Tariff ID" [novalnet.connector_webhook_details] merchant_secret="Source verification key" +[[novalnet.metadata.google_pay]] +name="merchant_name" +label="Google Pay Merchant Name" +placeholder="Enter Google Pay Merchant Name" +required=true +type="Text" +[[novalnet.metadata.google_pay]] +name="merchant_id" +label="Google Pay Merchant Id" +placeholder="Enter Google Pay Merchant Id" +required=true +type="Text" +[[novalnet.metadata.google_pay]] +name="gateway_merchant_id" +label="Google Pay Merchant Key" +placeholder="Enter Google Pay Merchant Key" +required=true +type="Text" + +[[novalnet.metadata.apple_pay]] +name="certificate" +label="Merchant Certificate (Base64 Encoded)" +placeholder="Enter Merchant Certificate (Base64 Encoded)" +required=true +type="Text" +[[novalnet.metadata.apple_pay]] +name="certificate_keys" +label="Merchant PrivateKey (Base64 Encoded)" +placeholder="Enter Merchant PrivateKey (Base64 Encoded)" +required=true +type="Text" +[[novalnet.metadata.apple_pay]] +name="merchant_identifier" +label="Apple Merchant Identifier" +placeholder="Enter Apple Merchant Identifier" +required=true +type="Text" +[[novalnet.metadata.apple_pay]] +name="display_name" +label="Display Name" +placeholder="Enter Display Name" +required=true +type="Text" +[[novalnet.metadata.apple_pay]] +name="initiative" +label="Domain" +placeholder="Enter Domain" +required=true +type="Select" +options=["web","ios"] +[[novalnet.metadata.apple_pay]] +name="initiative_context" +label="Domain Name" +placeholder="Enter Domain Name" +required=true +type="Text" +[[novalnet.metadata.apple_pay]] +name="merchant_business_country" +label="Merchant Business Country" +placeholder="Enter Merchant Business Country" +required=true +type="Select" +options=[] +[[novalnet.metadata.apple_pay]] +name="payment_processing_details_at" +label="Payment Processing Details At" +placeholder="Enter Payment Processing Details At" +required=true +type="Radio" +options=["Connector"] [nuvei] [[nuvei.credit]] @@ -2054,7 +2130,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 +2435,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" @@ -2473,6 +2549,12 @@ merchant_secret="Source verification key" api_key="Username" key1="Password" api_secret="Merchant Identifier" +[worldpay.metadata.merchant_name] +name="merchant_name" +label="Name of the merchant to de displayed during 3DS challenge" +placeholder="Enter Name of the merchant" +required=true +type="Text" [[worldpay.metadata.apple_pay]] name="certificate" @@ -2523,7 +2605,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" @@ -3185,7 +3267,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 a1d81f27231c..d767417a043c 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" @@ -2256,12 +2256,88 @@ type="Text" payment_method_type = "CartesBancaires" [[novalnet.debit]] payment_method_type = "UnionPay" +[[novalnet.wallet]] + payment_method_type = "google_pay" +[[novalnet.wallet]] + payment_method_type = "paypal" +[[novalnet.wallet]] + payment_method_type = "apple_pay" [novalnet.connector_auth.SignatureKey] api_key="Product Activation Key" key1="Payment Access Key" api_secret="Tariff ID" [novalnet.connector_webhook_details] merchant_secret="Source verification key" +[[novalnet.metadata.google_pay]] +name="merchant_name" +label="Google Pay Merchant Name" +placeholder="Enter Google Pay Merchant Name" +required=true +type="Text" +[[novalnet.metadata.google_pay]] +name="merchant_id" +label="Google Pay Merchant Id" +placeholder="Enter Google Pay Merchant Id" +required=true +type="Text" +[[novalnet.metadata.google_pay]] +name="gateway_merchant_id" +label="Google Pay Merchant Key" +placeholder="Enter Google Pay Merchant Key" +required=true +type="Text" + +[[novalnet.metadata.apple_pay]] +name="certificate" +label="Merchant Certificate (Base64 Encoded)" +placeholder="Enter Merchant Certificate (Base64 Encoded)" +required=true +type="Text" +[[novalnet.metadata.apple_pay]] +name="certificate_keys" +label="Merchant PrivateKey (Base64 Encoded)" +placeholder="Enter Merchant PrivateKey (Base64 Encoded)" +required=true +type="Text" +[[novalnet.metadata.apple_pay]] +name="merchant_identifier" +label="Apple Merchant Identifier" +placeholder="Enter Apple Merchant Identifier" +required=true +type="Text" +[[novalnet.metadata.apple_pay]] +name="display_name" +label="Display Name" +placeholder="Enter Display Name" +required=true +type="Text" +[[novalnet.metadata.apple_pay]] +name="initiative" +label="Domain" +placeholder="Enter Domain" +required=true +type="Select" +options=["web","ios"] +[[novalnet.metadata.apple_pay]] +name="initiative_context" +label="Domain Name" +placeholder="Enter Domain Name" +required=true +type="Text" +[[novalnet.metadata.apple_pay]] +name="merchant_business_country" +label="Merchant Business Country" +placeholder="Enter Merchant Business Country" +required=true +type="Select" +options=[] +[[novalnet.metadata.apple_pay]] +name="payment_processing_details_at" +label="Payment Processing Details At" +placeholder="Enter Payment Processing Details At" +required=true +type="Radio" +options=["Connector"] [nuvei] [[nuvei.credit]] @@ -2374,7 +2450,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 +2908,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 +3311,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" @@ -3406,6 +3482,12 @@ key1="Password" api_secret="Merchant Identifier" [worldpay.connector_webhook_details] merchant_secret="Source verification key" +[worldpay.metadata.merchant_name] +name="merchant_name" +label="Name of the merchant to de displayed during 3DS challenge" +placeholder="Enter Name of the merchant" +required=true +type="Text" [[worldpay.metadata.apple_pay]] name="certificate" @@ -3456,7 +3538,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" @@ -4184,7 +4266,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/diesel_models/Cargo.toml b/crates/diesel_models/Cargo.toml index 02d917f3b17b..120a606d58b5 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/address.rs b/crates/diesel_models/src/address.rs index a1cfb668716b..06b82cb2c204 100644 --- a/crates/diesel_models/src/address.rs +++ b/crates/diesel_models/src/address.rs @@ -1,12 +1,5 @@ -use common_utils::{ - crypto::{self, Encryptable}, - encryption::Encryption, - pii::EmailStrategy, - types::keymanager::ToEncryptable, -}; +use common_utils::{crypto, encryption::Encryption}; use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable}; -use masking::{Secret, SwitchStrategy}; -use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; @@ -74,48 +67,6 @@ pub struct EncryptableAddress { pub email: crypto::OptionalEncryptableEmail, } -impl ToEncryptable, Encryption> for Address { - fn to_encryptable(self) -> FxHashMap { - let mut map = FxHashMap::with_capacity_and_hasher(9, Default::default()); - self.line1.map(|x| map.insert("line1".to_string(), x)); - self.line2.map(|x| map.insert("line2".to_string(), x)); - self.line3.map(|x| map.insert("line3".to_string(), x)); - self.zip.map(|x| map.insert("zip".to_string(), x)); - self.state.map(|x| map.insert("state".to_string(), x)); - self.first_name - .map(|x| map.insert("first_name".to_string(), x)); - self.last_name - .map(|x| map.insert("last_name".to_string(), x)); - self.phone_number - .map(|x| map.insert("phone_number".to_string(), x)); - self.email.map(|x| map.insert("email".to_string(), x)); - map - } - - fn from_encryptable( - mut hashmap: FxHashMap>>, - ) -> common_utils::errors::CustomResult - { - Ok(EncryptableAddress { - line1: hashmap.remove("line1"), - line2: hashmap.remove("line2"), - line3: hashmap.remove("line3"), - zip: hashmap.remove("zip"), - state: hashmap.remove("state"), - first_name: hashmap.remove("first_name"), - last_name: hashmap.remove("last_name"), - phone_number: hashmap.remove("phone_number"), - email: hashmap.remove("email").map(|email| { - let encryptable: Encryptable> = Encryptable::new( - email.clone().into_inner().switch_strategy(), - email.into_encrypted(), - ); - encryptable - }), - }) - } -} - #[derive(Clone, Debug, AsChangeset, router_derive::DebugAsDisplay, Serialize, Deserialize)] #[diesel(table_name = address)] pub struct AddressUpdateInternal { diff --git a/crates/diesel_models/src/api_keys.rs b/crates/diesel_models/src/api_keys.rs index 1781e65cded4..7076bf597e0e 100644 --- a/crates/diesel_models/src/api_keys.rs +++ b/crates/diesel_models/src/api_keys.rs @@ -9,7 +9,7 @@ use crate::schema::api_keys; )] #[diesel(table_name = api_keys, primary_key(key_id), check_for_backend(diesel::pg::Pg))] pub struct ApiKey { - pub key_id: String, + pub key_id: common_utils::id_type::ApiKeyId, pub merchant_id: common_utils::id_type::MerchantId, pub name: String, pub description: Option, @@ -23,7 +23,7 @@ pub struct ApiKey { #[derive(Debug, Insertable)] #[diesel(table_name = api_keys)] pub struct ApiKeyNew { - pub key_id: String, + pub key_id: common_utils::id_type::ApiKeyId, pub merchant_id: common_utils::id_type::MerchantId, pub name: String, pub description: Option, @@ -141,7 +141,7 @@ mod diesel_impl { // Tracking data by process_tracker #[derive(Default, Debug, Deserialize, Serialize, Clone)] pub struct ApiKeyExpiryTrackingData { - pub key_id: String, + pub key_id: common_utils::id_type::ApiKeyId, pub merchant_id: common_utils::id_type::MerchantId, pub api_key_name: String, pub prefix: String, diff --git a/crates/diesel_models/src/events.rs b/crates/diesel_models/src/events.rs index b6c5efe0fd1a..82b2b58f80bf 100644 --- a/crates/diesel_models/src/events.rs +++ b/crates/diesel_models/src/events.rs @@ -1,11 +1,7 @@ -use common_utils::{ - crypto::OptionalEncryptableSecretString, custom_serde, encryption::Encryption, - types::keymanager::ToEncryptable, -}; +use common_utils::{custom_serde, encryption::Encryption}; use diesel::{ expression::AsExpression, AsChangeset, Identifiable, Insertable, Queryable, Selectable, }; -use masking::Secret; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; @@ -63,38 +59,6 @@ pub struct Event { pub metadata: Option, } -pub struct EventWithEncryption { - pub request: Option, - pub response: Option, -} - -pub struct EncryptableEvent { - pub request: OptionalEncryptableSecretString, - pub response: OptionalEncryptableSecretString, -} - -impl ToEncryptable, Encryption> for EventWithEncryption { - fn to_encryptable(self) -> rustc_hash::FxHashMap { - let mut map = rustc_hash::FxHashMap::default(); - self.request.map(|x| map.insert("request".to_string(), x)); - self.response.map(|x| map.insert("response".to_string(), x)); - map - } - - fn from_encryptable( - mut hashmap: rustc_hash::FxHashMap< - String, - common_utils::crypto::Encryptable>, - >, - ) -> common_utils::errors::CustomResult - { - Ok(EncryptableEvent { - request: hashmap.remove("request"), - response: hashmap.remove("response"), - }) - } -} - #[derive(Clone, Debug, Deserialize, Serialize, AsExpression, diesel::FromSqlRow)] #[diesel(sql_type = diesel::sql_types::Jsonb)] pub enum EventMetadata { diff --git a/crates/diesel_models/src/kv.rs b/crates/diesel_models/src/kv.rs index d91e57a2b5d6..0bfa1434f69a 100644 --- a/crates/diesel_models/src/kv.rs +++ b/crates/diesel_models/src/kv.rs @@ -20,8 +20,8 @@ use crate::{ #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "snake_case", tag = "db_op", content = "data")] pub enum DBOperation { - Insert { insertable: Insertable }, - Update { updatable: Updateable }, + Insert { insertable: Box }, + Update { updatable: Box }, } impl DBOperation { @@ -33,7 +33,7 @@ impl DBOperation { } pub fn table<'a>(&self) -> &'a str { match self { - Self::Insert { insertable } => match insertable { + Self::Insert { insertable } => match **insertable { Insertable::PaymentIntent(_) => "payment_intent", Insertable::PaymentAttempt(_) => "payment_attempt", Insertable::Refund(_) => "refund", @@ -45,7 +45,7 @@ impl DBOperation { Insertable::PaymentMethod(_) => "payment_method", Insertable::Mandate(_) => "mandate", }, - Self::Update { updatable } => match updatable { + Self::Update { updatable } => match **updatable { Updateable::PaymentIntentUpdate(_) => "payment_intent", Updateable::PaymentAttemptUpdate(_) => "payment_attempt", Updateable::RefundUpdate(_) => "refund", @@ -83,7 +83,7 @@ pub struct TypedSql { impl DBOperation { pub async fn execute(self, conn: &PgPooledConn) -> crate::StorageResult { Ok(match self { - Self::Insert { insertable } => match insertable { + Self::Insert { insertable } => match *insertable { Insertable::PaymentIntent(a) => { DBResult::PaymentIntent(Box::new(a.insert(conn).await?)) } @@ -107,7 +107,7 @@ impl DBOperation { } Insertable::Mandate(m) => DBResult::Mandate(Box::new(m.insert(conn).await?)), }, - Self::Update { updatable } => match updatable { + Self::Update { updatable } => match *updatable { Updateable::PaymentIntentUpdate(a) => { DBResult::PaymentIntent(Box::new(a.orig.update(conn, a.update_data).await?)) } @@ -201,8 +201,8 @@ impl TypedSql { #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "snake_case", tag = "table", content = "data")] pub enum Insertable { - PaymentIntent(PaymentIntentNew), - PaymentAttempt(PaymentAttemptNew), + PaymentIntent(Box), + PaymentAttempt(Box), Refund(RefundNew), Address(Box), Customer(CustomerNew), @@ -216,14 +216,14 @@ pub enum Insertable { #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "snake_case", tag = "table", content = "data")] pub enum Updateable { - PaymentIntentUpdate(PaymentIntentUpdateMems), - PaymentAttemptUpdate(PaymentAttemptUpdateMems), + PaymentIntentUpdate(Box), + PaymentAttemptUpdate(Box), RefundUpdate(RefundUpdateMems), CustomerUpdate(CustomerUpdateMems), AddressUpdate(Box), PayoutsUpdate(PayoutsUpdateMems), PayoutAttemptUpdate(PayoutAttemptUpdateMems), - PaymentMethodUpdate(PaymentMethodUpdateMems), + PaymentMethodUpdate(Box), MandateUpdate(MandateUpdateMems), } diff --git a/crates/diesel_models/src/merchant_account.rs b/crates/diesel_models/src/merchant_account.rs index b1dcc1d3476a..12d51311e874 100644 --- a/crates/diesel_models/src/merchant_account.rs +++ b/crates/diesel_models/src/merchant_account.rs @@ -260,6 +260,36 @@ pub struct MerchantAccountUpdateInternal { pub recon_status: Option, } +#[cfg(feature = "v2")] +impl MerchantAccountUpdateInternal { + pub fn apply_changeset(self, source: MerchantAccount) -> MerchantAccount { + let Self { + merchant_name, + merchant_details, + publishable_key, + storage_scheme, + metadata, + modified_at, + organization_id, + recon_status, + } = self; + + MerchantAccount { + merchant_name: merchant_name.or(source.merchant_name), + merchant_details: merchant_details.or(source.merchant_details), + publishable_key: publishable_key.or(source.publishable_key), + storage_scheme: storage_scheme.unwrap_or(source.storage_scheme), + metadata: metadata.or(source.metadata), + created_at: source.created_at, + modified_at, + organization_id: organization_id.unwrap_or(source.organization_id), + recon_status: recon_status.unwrap_or(source.recon_status), + version: source.version, + id: source.id, + } + } +} + #[cfg(feature = "v1")] #[derive(Clone, Debug, AsChangeset, router_derive::DebugAsDisplay)] #[diesel(table_name = merchant_account)] @@ -290,3 +320,71 @@ pub struct MerchantAccountUpdateInternal { pub payment_link_config: Option, pub pm_collect_link_config: Option, } + +#[cfg(feature = "v1")] +impl MerchantAccountUpdateInternal { + pub fn apply_changeset(self, source: MerchantAccount) -> MerchantAccount { + let Self { + merchant_name, + merchant_details, + return_url, + webhook_details, + sub_merchants_enabled, + parent_merchant_id, + enable_payment_response_hash, + payment_response_hash_key, + redirect_to_merchant_with_http_post, + publishable_key, + storage_scheme, + locker_id, + metadata, + routing_algorithm, + primary_business_details, + modified_at, + intent_fulfillment_time, + frm_routing_algorithm, + payout_routing_algorithm, + organization_id, + is_recon_enabled, + default_profile, + recon_status, + payment_link_config, + pm_collect_link_config, + } = self; + + MerchantAccount { + merchant_id: source.merchant_id, + return_url: return_url.or(source.return_url), + enable_payment_response_hash: enable_payment_response_hash + .unwrap_or(source.enable_payment_response_hash), + payment_response_hash_key: payment_response_hash_key + .or(source.payment_response_hash_key), + redirect_to_merchant_with_http_post: redirect_to_merchant_with_http_post + .unwrap_or(source.redirect_to_merchant_with_http_post), + merchant_name: merchant_name.or(source.merchant_name), + merchant_details: merchant_details.or(source.merchant_details), + webhook_details: webhook_details.or(source.webhook_details), + sub_merchants_enabled: sub_merchants_enabled.or(source.sub_merchants_enabled), + parent_merchant_id: parent_merchant_id.or(source.parent_merchant_id), + publishable_key: publishable_key.or(source.publishable_key), + storage_scheme: storage_scheme.unwrap_or(source.storage_scheme), + locker_id: locker_id.or(source.locker_id), + metadata: metadata.or(source.metadata), + routing_algorithm: routing_algorithm.or(source.routing_algorithm), + primary_business_details: primary_business_details + .unwrap_or(source.primary_business_details), + intent_fulfillment_time: intent_fulfillment_time.or(source.intent_fulfillment_time), + created_at: source.created_at, + modified_at, + frm_routing_algorithm: frm_routing_algorithm.or(source.frm_routing_algorithm), + payout_routing_algorithm: payout_routing_algorithm.or(source.payout_routing_algorithm), + organization_id: organization_id.unwrap_or(source.organization_id), + is_recon_enabled: is_recon_enabled.unwrap_or(source.is_recon_enabled), + default_profile: default_profile.unwrap_or(source.default_profile), + recon_status: recon_status.unwrap_or(source.recon_status), + payment_link_config: payment_link_config.or(source.payment_link_config), + pm_collect_link_config: pm_collect_link_config.or(source.pm_collect_link_config), + version: source.version, + } + } +} diff --git a/crates/diesel_models/src/payment_attempt.rs b/crates/diesel_models/src/payment_attempt.rs index ae98b8a04815..f8654d3cd963 100644 --- a/crates/diesel_models/src/payment_attempt.rs +++ b/crates/diesel_models/src/payment_attempt.rs @@ -21,7 +21,15 @@ pub struct ConnectorMandateReferenceId { pub connector_mandate_id: Option, pub payment_method_id: Option, pub mandate_metadata: Option, + pub connector_mandate_request_reference_id: Option, } + +impl ConnectorMandateReferenceId { + pub fn get_connector_mandate_request_reference_id(&self) -> Option { + self.connector_mandate_request_reference_id.clone() + } +} + #[cfg(feature = "v2")] #[derive( Clone, Debug, Eq, PartialEq, Identifiable, Queryable, Serialize, Deserialize, Selectable, @@ -34,9 +42,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 +52,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 +65,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 +81,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 +232,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 +242,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 +255,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 +274,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, } @@ -413,6 +422,7 @@ pub enum PaymentAttemptUpdate { customer_acceptance: Option, shipping_cost: Option, order_tax_amount: Option, + connector_mandate_detail: Option, }, VoidUpdate { status: storage_enums::AttemptStatus, @@ -731,48 +741,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 +842,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 { @@ -2164,6 +2167,7 @@ impl From for PaymentAttemptUpdateInternal { customer_acceptance, shipping_cost, order_tax_amount, + connector_mandate_detail, } => Self { amount: Some(amount), currency: Some(currency), @@ -2215,7 +2219,7 @@ impl From for PaymentAttemptUpdateInternal { shipping_cost, order_tax_amount, connector_transaction_data: None, - connector_mandate_detail: None, + connector_mandate_detail, }, PaymentAttemptUpdate::VoidUpdate { status, diff --git a/crates/diesel_models/src/payment_intent.rs b/crates/diesel_models/src/payment_intent.rs index f53594075af1..210b12b7aadc 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/api_keys.rs b/crates/diesel_models/src/query/api_keys.rs index 5dd145010258..479e226c1d37 100644 --- a/crates/diesel_models/src/query/api_keys.rs +++ b/crates/diesel_models/src/query/api_keys.rs @@ -18,7 +18,7 @@ impl ApiKey { pub async fn update_by_merchant_id_key_id( conn: &PgPooledConn, merchant_id: common_utils::id_type::MerchantId, - key_id: String, + key_id: common_utils::id_type::ApiKeyId, api_key_update: ApiKeyUpdate, ) -> StorageResult { match generics::generic_update_with_unique_predicate_get_result::< @@ -57,7 +57,7 @@ impl ApiKey { pub async fn revoke_by_merchant_id_key_id( conn: &PgPooledConn, merchant_id: &common_utils::id_type::MerchantId, - key_id: &str, + key_id: &common_utils::id_type::ApiKeyId, ) -> StorageResult { generics::generic_delete::<::Table, _>( conn, @@ -71,7 +71,7 @@ impl ApiKey { pub async fn find_optional_by_merchant_id_key_id( conn: &PgPooledConn, merchant_id: &common_utils::id_type::MerchantId, - key_id: &str, + key_id: &common_utils::id_type::ApiKeyId, ) -> StorageResult> { generics::generic_find_one_optional::<::Table, _, _>( conn, diff --git a/crates/diesel_models/src/query/payment_attempt.rs b/crates/diesel_models/src/query/payment_attempt.rs index 85c698248924..7141675c880a 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() { @@ -171,11 +167,23 @@ impl PaymentAttempt { merchant_id: &common_utils::id_type::MerchantId, connector_txn_id: &str, ) -> StorageResult { + let (txn_id, txn_data) = common_utils::types::ConnectorTransactionId::form_id_and_data( + connector_txn_id.to_string(), + ); + let connector_transaction_id = txn_id + .get_txn_id(txn_data.as_ref()) + .change_context(DatabaseError::Others) + .attach_printable_lazy(|| { + format!( + "Failed to retrieve txn_id for ({:?}, {:?})", + txn_id, txn_data + ) + })?; generics::generic_find_one::<::Table, _, _>( conn, dsl::merchant_id .eq(merchant_id.to_owned()) - .and(dsl::connector_transaction_id.eq(connector_txn_id.to_owned())), + .and(dsl::connector_transaction_id.eq(connector_transaction_id.to_owned())), ) .await } @@ -370,6 +378,7 @@ impl PaymentAttempt { payment_method_type: Option>, authentication_type: Option>, merchant_connector_id: Option>, + card_network: Option>, ) -> StorageResult { let mut filter = ::table() .count() @@ -393,6 +402,9 @@ impl PaymentAttempt { if let Some(merchant_connector_id) = merchant_connector_id { filter = filter.filter(dsl::merchant_connector_id.eq_any(merchant_connector_id)) } + if let Some(card_network) = card_network { + filter = filter.filter(dsl::card_network.eq_any(card_network)) + } router_env::logger::debug!(query = %debug_query::(&filter).to_string()); diff --git a/crates/diesel_models/src/query/user/sample_data.rs b/crates/diesel_models/src/query/user/sample_data.rs index 27e674f7d7b1..b97ea39b82d9 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/refund.rs b/crates/diesel_models/src/refund.rs index 9e850bc9f1f4..42a22b91396c 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/diesel_models/src/role.rs b/crates/diesel_models/src/role.rs index 3fb64e645d60..8199bd3979ce 100644 --- a/crates/diesel_models/src/role.rs +++ b/crates/diesel_models/src/role.rs @@ -18,7 +18,7 @@ pub struct Role { pub created_by: String, pub last_modified_at: PrimitiveDateTime, pub last_modified_by: String, - pub entity_type: Option, + pub entity_type: enums::EntityType, } #[derive(router_derive::Setter, Clone, Debug, Insertable, router_derive::DebugAsDisplay)] @@ -35,7 +35,7 @@ pub struct RoleNew { pub created_by: String, pub last_modified_at: PrimitiveDateTime, pub last_modified_by: String, - pub entity_type: Option, + pub entity_type: enums::EntityType, } #[derive(Clone, Debug, AsChangeset, router_derive::DebugAsDisplay)] diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs index 8d2dfc47b623..e2ab676b2d30 100644 --- a/crates/diesel_models/src/schema.rs +++ b/crates/diesel_models/src/schema.rs @@ -1235,7 +1235,7 @@ diesel::table! { #[max_length = 64] last_modified_by -> Varchar, #[max_length = 64] - entity_type -> Nullable, + entity_type -> Varchar, } } diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs index 45a4ce03e55b..5651bf95dd9d 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] @@ -1183,7 +1181,7 @@ diesel::table! { #[max_length = 64] last_modified_by -> Varchar, #[max_length = 64] - entity_type -> Nullable, + entity_type -> Varchar, } } diff --git a/crates/diesel_models/src/user/sample_data.rs b/crates/diesel_models/src/user/sample_data.rs index 88617afb3925..cfc9e1c4c8ed 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 5cb01dc8fb63..ce7301a03059 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/drainer/src/settings.rs b/crates/drainer/src/settings.rs index 052267395041..5b391b492e09 100644 --- a/crates/drainer/src/settings.rs +++ b/crates/drainer/src/settings.rs @@ -125,21 +125,56 @@ impl Multitenancy { pub fn get_tenants(&self) -> &HashMap { &self.tenants.0 } - pub fn get_tenant_names(&self) -> Vec { - self.tenants.0.keys().cloned().collect() + pub fn get_tenant_ids(&self) -> Vec { + self.tenants + .0 + .values() + .map(|tenant| tenant.tenant_id.clone()) + .collect() } pub fn get_tenant(&self, tenant_id: &str) -> Option<&Tenant> { self.tenants.0.get(tenant_id) } } -#[derive(Debug, Deserialize, Clone, Default)] -#[serde(transparent)] +#[derive(Debug, Clone, Default)] pub struct TenantConfig(pub HashMap); +impl<'de> Deserialize<'de> for TenantConfig { + fn deserialize>(deserializer: D) -> Result { + #[derive(Deserialize)] + struct Inner { + base_url: String, + schema: String, + redis_key_prefix: String, + clickhouse_database: String, + } + + let hashmap = >::deserialize(deserializer)?; + + Ok(Self( + hashmap + .into_iter() + .map(|(key, value)| { + ( + key.clone(), + Tenant { + tenant_id: key, + base_url: value.base_url, + schema: value.schema, + redis_key_prefix: value.redis_key_prefix, + clickhouse_database: value.clickhouse_database, + }, + ) + }) + .collect(), + )) + } +} + #[derive(Debug, Deserialize, Clone, Default)] pub struct Tenant { - pub name: String, + pub tenant_id: String, pub base_url: String, pub schema: String, pub redis_key_prefix: String, diff --git a/crates/external_services/Cargo.toml b/crates/external_services/Cargo.toml index fd7391c13bca..12b9dd3b0f35 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", "dep:hyper-util", "dep:http-body-util"] [dependencies] async-trait = "0.1.79" @@ -34,10 +34,12 @@ 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 } +hyper-util = { version = "0.1.9", optional = true } +http-body-util = { version = "0.1.2", optional = true } # First party crates @@ -49,7 +51,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/external_services/src/grpc_client/dynamic_routing.rs b/crates/external_services/src/grpc_client/dynamic_routing.rs index 9308bbe6bf60..68f873462ff9 100644 --- a/crates/external_services/src/grpc_client/dynamic_routing.rs +++ b/crates/external_services/src/grpc_client/dynamic_routing.rs @@ -6,6 +6,9 @@ use api_models::routing::{ }; use common_utils::{errors::CustomResult, ext_traits::OptionExt, transformers::ForeignTryFrom}; use error_stack::ResultExt; +use http_body_util::combinators::UnsyncBoxBody; +use hyper::body::Bytes; +use hyper_util::client::legacy::connect::HttpConnector; use serde; use success_rate::{ success_rate_calculator_client::SuccessRateCalculatorClient, CalSuccessRateConfig, @@ -13,7 +16,7 @@ use success_rate::{ CurrentBlockThreshold as DynamicCurrentThreshold, LabelWithStatus, UpdateSuccessRateWindowConfig, UpdateSuccessRateWindowRequest, UpdateSuccessRateWindowResponse, }; -use tonic::transport::Channel; +use tonic::Status; #[allow( missing_docs, unused_qualifications, @@ -40,11 +43,13 @@ pub enum DynamicRoutingError { SuccessRateBasedRoutingFailure(String), } +type Client = hyper_util::client::legacy::Client>; + /// Type that consists of all the services provided by the client #[derive(Debug, Clone)] pub struct RoutingStrategy { /// success rate service for Dynamic Routing - pub success_rate_client: Option>, + pub success_rate_client: Option>, } /// Contains the Dynamic Routing Client Config @@ -70,11 +75,14 @@ impl DynamicRoutingClientConfig { pub async fn get_dynamic_routing_connection( self, ) -> Result> { + let client = + hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()) + .http2_only(true) + .build_http(); let success_rate_client = match self { - Self::Enabled { host, port, .. } => { - let uri = format!("http://{}:{}", host, port); - let channel = tonic::transport::Endpoint::new(uri)?.connect().await?; - Some(SuccessRateCalculatorClient::new(channel)) + Self::Enabled { host, port } => { + let uri = format!("http://{}:{}", host, port).parse::()?; + Some(SuccessRateCalculatorClient::with_origin(client, uri)) } Self::Disabled => None, }; @@ -104,7 +112,7 @@ pub trait SuccessBasedDynamicRouting: dyn_clone::DynClone + Send + Sync { } #[async_trait::async_trait] -impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient { +impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient { async fn calculate_success_rate( &self, id: String, diff --git a/crates/hyperswitch_connectors/Cargo.toml b/crates/hyperswitch_connectors/Cargo.toml index 2676f6372230..ca9d338920f8 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" @@ -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" @@ -29,9 +30,11 @@ ring = "0.17.8" serde = { version = "1.0.197", features = ["derive"] } serde_json = "1.0.115" serde_urlencoded = "0.7.1" +serde_with = "3.7.0" strum = { version = "0.26", features = ["derive"] } time = "0.3.35" url = "2.5.0" +urlencoding = "2.1.3" uuid = { version = "1.8.0", features = ["v4"] } # First party crates diff --git a/crates/hyperswitch_connectors/src/connectors.rs b/crates/hyperswitch_connectors/src/connectors.rs index ddd9fa861a61..fb29417eaa08 100644 --- a/crates/hyperswitch_connectors/src/connectors.rs +++ b/crates/hyperswitch_connectors/src/connectors.rs @@ -1,3 +1,4 @@ +pub mod airwallex; pub mod bambora; pub mod billwerk; pub mod bitpay; @@ -7,15 +8,24 @@ pub mod cryptopay; pub mod deutschebank; pub mod digitalvirgo; pub mod dlocal; +pub mod elavon; pub mod fiserv; pub mod fiservemea; pub mod fiuu; +pub mod forte; pub mod globepay; pub mod helcim; +pub mod jpmorgan; pub mod mollie; +pub mod multisafepay; +pub mod nexinets; pub mod nexixpay; pub mod novalnet; +pub mod payeezy; +pub mod payu; pub mod powertranz; +pub mod razorpay; +pub mod shift4; pub mod square; pub mod stax; pub mod taxjar; @@ -23,12 +33,17 @@ pub mod thunes; pub mod tsys; pub mod volt; pub mod worldline; +pub mod worldpay; +pub mod zen; +pub mod zsl; 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, + airwallex::Airwallex, bambora::Bambora, billwerk::Billwerk, bitpay::Bitpay, + cashtocode::Cashtocode, coinbase::Coinbase, cryptopay::Cryptopay, deutschebank::Deutschebank, + digitalvirgo::Digitalvirgo, dlocal::Dlocal, elavon::Elavon, fiserv::Fiserv, + fiservemea::Fiservemea, fiuu::Fiuu, forte::Forte, globepay::Globepay, helcim::Helcim, + jpmorgan::Jpmorgan, mollie::Mollie, multisafepay::Multisafepay, nexinets::Nexinets, + nexixpay::Nexixpay, novalnet::Novalnet, payeezy::Payeezy, payu::Payu, powertranz::Powertranz, + razorpay::Razorpay, shift4::Shift4, square::Square, stax::Stax, taxjar::Taxjar, thunes::Thunes, + tsys::Tsys, volt::Volt, worldline::Worldline, worldpay::Worldpay, zen::Zen, zsl::Zsl, }; diff --git a/crates/router/src/connector/airwallex.rs b/crates/hyperswitch_connectors/src/connectors/airwallex.rs similarity index 73% rename from crates/router/src/connector/airwallex.rs rename to crates/hyperswitch_connectors/src/connectors/airwallex.rs index e6b0113e98cb..26bfcd1e07e3 100644 --- a/crates/router/src/connector/airwallex.rs +++ b/crates/hyperswitch_connectors/src/connectors/airwallex.rs @@ -1,35 +1,56 @@ pub mod transformers; + use std::fmt::Debug; +use api_models::webhooks::IncomingWebhookEvent; +use common_enums::{enums, CallConnectorAction, PaymentAction}; use common_utils::{ - ext_traits::{ByteSliceExt, ValueExt}, - request::RequestContent, + crypto, + errors::CustomResult, + ext_traits::{ByteSliceExt, BytesExt, ValueExt}, + request::{Method, Request, RequestBuilder, RequestContent}, }; -use diesel_models::enums; use error_stack::{report, ResultExt}; -use masking::PeekInterface; -use transformers as airwallex; - -use super::utils::{self as connector_utils, AccessTokenRequestInfo, RefundsRequestData}; -use crate::{ - configs::settings, - core::{ - errors::{self, CustomResult}, - payments, +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}, + CompleteAuthorize, PreProcessing, }, - events::connector_api_logs::ConnectorEvent, - headers, logger, - services::{ - self, - request::{self, Mask}, - ConnectorIntegration, ConnectorValidation, + router_request_types::{ + AccessTokenRequestData, CompleteAuthorizeData, PaymentMethodTokenizationData, + PaymentsAuthorizeData, PaymentsCancelData, PaymentsCaptureData, PaymentsPreProcessingData, + PaymentsSessionData, PaymentsSyncData, RefundsData, SetupMandateRequestData, }, + router_response_types::{PaymentsResponseData, RefundsResponseData}, types::{ - self, - api::{self, ConnectorCommon, ConnectorCommonExt}, - ErrorResponse, Response, RouterData, + PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData, + PaymentsCompleteAuthorizeRouterData, PaymentsPreProcessingRouterData, + PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData, SetupMandateRouterData, + }, +}; +use hyperswitch_interfaces::{ + api::{ + self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorRedirectResponse, + ConnectorValidation, }, - utils::{crypto, BytesExt}, + configs::Connectors, + disputes::DisputePayload, + errors, + events::connector_api_logs::ConnectorEvent, + types::{self, Response}, + webhooks::{IncomingWebhook, IncomingWebhookRequestDetails}, +}; +use masking::{Mask, PeekInterface}; +use router_env::logger; +use transformers as airwallex; + +use crate::{ + constants::headers, + types::{RefreshTokenRouterData, ResponseRouterData}, + utils::{construct_not_supported_error_report, AccessTokenRequestInfo, RefundsRequestData}, }; #[derive(Debug, Clone)] @@ -42,8 +63,8 @@ where fn build_headers( &self, req: &RouterData, - _connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + _connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { let mut headers = vec![( headers::CONTENT_TYPE.to_string(), self.get_content_type().to_string().into(), @@ -76,7 +97,7 @@ impl ConnectorCommon for Airwallex { "application/json" } - fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { + fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str { connectors.airwallex.base_url.as_ref() } @@ -115,7 +136,7 @@ impl ConnectorValidation for Airwallex { 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()), ), } } @@ -125,18 +146,14 @@ impl api::Payment for Airwallex {} impl api::PaymentsPreProcessing for Airwallex {} impl api::PaymentsCompleteAuthorize for Airwallex {} impl api::MandateSetup for Airwallex {} -impl - ConnectorIntegration< - api::SetupMandate, - types::SetupMandateRequestData, - types::PaymentsResponseData, - > for Airwallex +impl ConnectorIntegration + for Airwallex { fn build_request( &self, - _req: &types::SetupMandateRouterData, - _connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + _req: &SetupMandateRouterData, + _connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Err( errors::ConnectorError::NotImplemented("Setup Mandate flow for Airwallex".to_string()) .into(), @@ -146,25 +163,19 @@ impl impl api::PaymentToken for Airwallex {} -impl - ConnectorIntegration< - api::PaymentMethodToken, - types::PaymentMethodTokenizationData, - types::PaymentsResponseData, - > for Airwallex +impl ConnectorIntegration + for Airwallex { // Not Implemented (R) } impl api::ConnectorAccessToken for Airwallex {} -impl ConnectorIntegration - for Airwallex -{ +impl ConnectorIntegration for Airwallex { fn get_url( &self, - _req: &types::RefreshTokenRouterData, - connectors: &settings::Connectors, + _req: &RefreshTokenRouterData, + connectors: &Connectors, ) -> CustomResult { Ok(format!( "{}{}", @@ -175,9 +186,9 @@ impl ConnectorIntegration CustomResult)>, errors::ConnectorError> { + req: &RefreshTokenRouterData, + _connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { let headers = vec![ ( headers::X_API_KEY.to_string(), @@ -194,12 +205,12 @@ 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)?) @@ -210,10 +221,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { logger::debug!(access_token_response=?res); let response: airwallex::AirwallexAuthUpdateResponse = res .response @@ -223,7 +234,7 @@ impl ConnectorIntegration for Airwallex +impl ConnectorIntegration + for Airwallex { fn get_headers( &self, - req: &types::PaymentsPreProcessingRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsPreProcessingRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -261,8 +268,8 @@ impl fn get_url( &self, - _req: &types::PaymentsPreProcessingRouterData, - connectors: &settings::Connectors, + _req: &PaymentsPreProcessingRouterData, + connectors: &Connectors, ) -> CustomResult { Ok(format!( "{}{}", @@ -273,8 +280,8 @@ impl fn get_request_body( &self, - req: &types::PaymentsPreProcessingRouterData, - _connectors: &settings::Connectors, + req: &PaymentsPreProcessingRouterData, + _connectors: &Connectors, ) -> CustomResult { let req_obj = airwallex::AirwallexIntentRequest::try_from(req)?; Ok(RequestContent::Json(Box::new(req_obj))) @@ -282,12 +289,12 @@ impl fn build_request( &self, - req: &types::PaymentsPreProcessingRouterData, - connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + req: &PaymentsPreProcessingRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsPreProcessingType::get_url( self, req, connectors, )?) @@ -304,10 +311,10 @@ impl fn handle_response( &self, - data: &types::PaymentsPreProcessingRouterData, + data: &PaymentsPreProcessingRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: airwallex::AirwallexPaymentsResponse = res .response .parse_struct("airwallex AirwallexPaymentsResponse") @@ -316,7 +323,7 @@ impl event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -336,14 +343,12 @@ impl impl api::PaymentAuthorize for Airwallex {} #[async_trait::async_trait] -impl ConnectorIntegration - for Airwallex -{ +impl ConnectorIntegration for Airwallex { 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) } @@ -353,8 +358,8 @@ impl ConnectorIntegration CustomResult { Ok(format!( "{}{}{}{}", @@ -369,8 +374,8 @@ impl ConnectorIntegration CustomResult { let connector_router_data = airwallex::AirwallexRouterData::try_from(( &self.get_currency_unit(), @@ -384,12 +389,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, )?) @@ -406,17 +411,17 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: airwallex::AirwallexPaymentsResponse = res .response .parse_struct("AirwallexPaymentsResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -434,14 +439,12 @@ impl ConnectorIntegration - for Airwallex -{ +impl ConnectorIntegration for Airwallex { 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) } @@ -451,8 +454,8 @@ impl ConnectorIntegration CustomResult { let connector_payment_id = req .request @@ -469,12 +472,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)?) @@ -484,10 +487,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { logger::debug!(payment_sync_response=?res); let response: airwallex::AirwallexPaymentsSyncResponse = res .response @@ -497,7 +500,7 @@ impl ConnectorIntegration for Airwallex +impl ConnectorIntegration + for Airwallex { fn get_headers( &self, - req: &types::PaymentsCompleteAuthorizeRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsCompleteAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } fn get_content_type(&self) -> &'static str { @@ -533,8 +532,8 @@ impl } fn get_url( &self, - req: &types::PaymentsCompleteAuthorizeRouterData, - connectors: &settings::Connectors, + req: &PaymentsCompleteAuthorizeRouterData, + connectors: &Connectors, ) -> CustomResult { let connector_payment_id = req .request @@ -549,8 +548,8 @@ impl } fn get_request_body( &self, - req: &types::PaymentsCompleteAuthorizeRouterData, - _connectors: &settings::Connectors, + req: &PaymentsCompleteAuthorizeRouterData, + _connectors: &Connectors, ) -> CustomResult { let req_obj = airwallex::AirwallexCompleteRequest::try_from(req)?; @@ -558,12 +557,12 @@ impl } fn build_request( &self, - req: &types::PaymentsCompleteAuthorizeRouterData, - connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + req: &PaymentsCompleteAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsCompleteAuthorizeType::get_url( self, req, connectors, )?) @@ -578,17 +577,17 @@ impl } fn handle_response( &self, - data: &types::PaymentsCompleteAuthorizeRouterData, + data: &PaymentsCompleteAuthorizeRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: airwallex::AirwallexPaymentsResponse = res .response .parse_struct("AirwallexPaymentsResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -606,14 +605,12 @@ impl } impl api::PaymentCapture for Airwallex {} -impl ConnectorIntegration - for Airwallex -{ +impl ConnectorIntegration for Airwallex { 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) } @@ -623,8 +620,8 @@ impl ConnectorIntegration CustomResult { Ok(format!( "{}{}{}{}", @@ -637,8 +634,8 @@ impl ConnectorIntegration CustomResult { let connector_req = airwallex::AirwallexPaymentsCaptureRequest::try_from(req)?; @@ -647,12 +644,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::PaymentsCaptureType::get_headers( @@ -667,17 +664,17 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: airwallex::AirwallexPaymentsResponse = res .response .parse_struct("Airwallex PaymentsResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -696,22 +693,18 @@ impl ConnectorIntegration - for Airwallex -{ +impl ConnectorIntegration for Airwallex { //TODO: implement sessions flow } impl api::PaymentVoid for Airwallex {} -impl ConnectorIntegration - for Airwallex -{ +impl ConnectorIntegration for Airwallex { 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) } @@ -721,8 +714,8 @@ impl ConnectorIntegration CustomResult { Ok(format!( "{}{}{}{}", @@ -734,8 +727,8 @@ impl ConnectorIntegration CustomResult { let connector_req = airwallex::AirwallexPaymentsCancelRequest::try_from(req)?; @@ -743,17 +736,17 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: airwallex::AirwallexPaymentsResponse = res .response .parse_struct("Airwallex PaymentsResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -763,12 +756,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsCancelRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsVoidType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::PaymentsVoidType::get_headers(self, req, connectors)?) @@ -792,14 +785,12 @@ impl api::Refund for Airwallex {} impl api::RefundExecute for Airwallex {} impl api::RefundSync for Airwallex {} -impl ConnectorIntegration - for Airwallex -{ +impl ConnectorIntegration for Airwallex { 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) } @@ -809,8 +800,8 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, + _req: &RefundsRouterData, + connectors: &Connectors, ) -> CustomResult { Ok(format!( "{}{}", @@ -821,8 +812,8 @@ impl ConnectorIntegration, - _connectors: &settings::Connectors, + req: &RefundsRouterData, + _connectors: &Connectors, ) -> CustomResult { let connector_router_data = airwallex::AirwallexRouterData::try_from(( &self.get_currency_unit(), @@ -836,11 +827,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( @@ -855,10 +846,10 @@ impl ConnectorIntegration, + data: &RefundsRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult, errors::ConnectorError> { + ) -> CustomResult, errors::ConnectorError> { logger::debug!(target: "router::connector::airwallex", response=?res); let response: airwallex::RefundResponse = res .response @@ -866,7 +857,7 @@ impl ConnectorIntegration - for Airwallex -{ +impl ConnectorIntegration for Airwallex { 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) } @@ -900,8 +889,8 @@ impl ConnectorIntegration CustomResult { Ok(format!( "{}{}{}", @@ -913,12 +902,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)?) @@ -928,10 +917,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { logger::debug!(target: "router::connector::airwallex", response=?res); let response: airwallex::RefundResponse = res .response @@ -939,7 +928,7 @@ impl ConnectorIntegration, + _request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { Ok(Box::new(crypto::HmacSha256)) } fn get_webhook_source_verification_signature( &self, - request: &api::IncomingWebhookRequestDetails<'_>, + request: &IncomingWebhookRequestDetails<'_>, _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets, ) -> CustomResult, errors::ConnectorError> { let security_header = request @@ -987,7 +976,7 @@ impl api::IncomingWebhook for Airwallex { 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> { @@ -1007,7 +996,7 @@ impl api::IncomingWebhook for Airwallex { fn get_webhook_object_reference_id( &self, - request: &api::IncomingWebhookRequestDetails<'_>, + request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult { let details: airwallex::AirwallexWebhookData = request .body @@ -1049,18 +1038,18 @@ impl api::IncomingWebhook for Airwallex { fn get_webhook_event_type( &self, - request: &api::IncomingWebhookRequestDetails<'_>, - ) -> CustomResult { + request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { let details: airwallex::AirwallexWebhookData = request .body .parse_struct("airwallexWebhookData") .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?; - Ok(api::IncomingWebhookEvent::try_from(details.name)?) + Ok(IncomingWebhookEvent::try_from(details.name)?) } fn get_webhook_resource_object( &self, - request: &api::IncomingWebhookRequestDetails<'_>, + request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { let details: airwallex::AirwallexWebhookObjectResource = request .body @@ -1072,8 +1061,8 @@ impl api::IncomingWebhook for Airwallex { fn get_dispute_details( &self, - request: &api::IncomingWebhookRequestDetails<'_>, - ) -> CustomResult { + request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { let details: airwallex::AirwallexWebhookData = request .body .parse_struct("airwallexWebhookData") @@ -1083,7 +1072,7 @@ impl api::IncomingWebhook for Airwallex { .object .parse_value("AirwallexDisputeObject") .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?; - Ok(api::disputes::DisputePayload { + Ok(DisputePayload { amount: dispute_details.dispute_amount.to_string(), currency: dispute_details.dispute_currency, dispute_stage: api_models::enums::DisputeStage::from(dispute_details.stage.clone()), @@ -1098,18 +1087,18 @@ impl api::IncomingWebhook for Airwallex { } } -impl services::ConnectorRedirectResponse for Airwallex { +impl ConnectorRedirectResponse for Airwallex { 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/airwallex/transformers.rs b/crates/hyperswitch_connectors/src/connectors/airwallex/transformers.rs similarity index 84% rename from crates/router/src/connector/airwallex/transformers.rs rename to crates/hyperswitch_connectors/src/connectors/airwallex/transformers.rs index e38999d495b4..5345c550cd18 100644 --- a/crates/router/src/connector/airwallex/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/airwallex/transformers.rs @@ -1,16 +1,27 @@ +use common_enums::enums; +use common_utils::{errors::ParsingError, request::Method}; use error_stack::ResultExt; -use masking::{ExposeInterface, PeekInterface}; +use hyperswitch_domain_models::{ + payment_method_data::{PaymentMethodData, WalletData}, + router_data::{AccessToken, ConnectorAuthType, RouterData}, + router_flow_types::{ + refunds::{Execute, RSync}, + PSync, + }, + router_request_types::{PaymentsSyncData, ResponseId}, + router_response_types::{PaymentsResponseData, RedirectForm, RefundsResponseData}, + types, +}; +use hyperswitch_interfaces::{api, errors}; +use masking::{ExposeInterface, PeekInterface, Secret}; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; use url::Url; use uuid::Uuid; use crate::{ - connector::utils::{self, CardData}, - core::errors, - pii::Secret, - services, - types::{self, api, domain, storage::enums, PaymentsSyncData}, + types::{RefundsResponseRouterData, ResponseRouterData}, + utils::{self, CardData as _}, }; pub struct AirwallexAuthType { @@ -18,11 +29,11 @@ pub struct AirwallexAuthType { pub x_client_id: Secret, } -impl TryFrom<&types::ConnectorAuthType> for AirwallexAuthType { +impl TryFrom<&ConnectorAuthType> for AirwallexAuthType { type Error = error_stack::Report; - fn try_from(auth_type: &types::ConnectorAuthType) -> Result { - if let types::ConnectorAuthType::BodyKey { api_key, key1 } = auth_type { + fn try_from(auth_type: &ConnectorAuthType) -> Result { + if let ConnectorAuthType::BodyKey { api_key, key1 } = auth_type { Ok(Self { x_api_key: api_key.clone(), x_client_id: key1.clone(), @@ -104,7 +115,7 @@ pub struct AirwallexPaymentsRequest { #[serde(untagged)] pub enum AirwallexPaymentMethod { Card(AirwallexCard), - Wallets(WalletData), + Wallets(AirwallexWalletData), } #[derive(Debug, Serialize)] @@ -123,7 +134,7 @@ pub struct AirwallexCardDetails { #[derive(Debug, Serialize)] #[serde(untagged)] -pub enum WalletData { +pub enum AirwallexWalletData { GooglePay(GooglePayData), } @@ -173,7 +184,7 @@ impl TryFrom<&AirwallexRouterData<&types::PaymentsAuthorizeRouterData>> let mut payment_method_options = None; let request = &item.router_data.request; let payment_method = match request.payment_method_data.clone() { - domain::PaymentMethodData::Card(ccard) => { + PaymentMethodData::Card(ccard) => { payment_method_options = Some(AirwallexPaymentOptions::Card(AirwallexCardPaymentOptions { auto_capture: matches!( @@ -191,23 +202,23 @@ impl TryFrom<&AirwallexRouterData<&types::PaymentsAuthorizeRouterData>> payment_method_type: AirwallexPaymentType::Card, })) } - domain::PaymentMethodData::Wallet(ref wallet_data) => get_wallet_details(wallet_data), - domain::PaymentMethodData::PayLater(_) - | domain::PaymentMethodData::BankRedirect(_) - | domain::PaymentMethodData::BankDebit(_) - | domain::PaymentMethodData::BankTransfer(_) - | domain::PaymentMethodData::CardRedirect(_) - | 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::Wallet(ref wallet_data) => get_wallet_details(wallet_data), + PaymentMethodData::PayLater(_) + | PaymentMethodData::BankRedirect(_) + | PaymentMethodData::BankDebit(_) + | PaymentMethodData::BankTransfer(_) + | PaymentMethodData::CardRedirect(_) + | 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("airwallex"), )) @@ -224,11 +235,11 @@ impl TryFrom<&AirwallexRouterData<&types::PaymentsAuthorizeRouterData>> } fn get_wallet_details( - wallet_data: &domain::WalletData, + wallet_data: &WalletData, ) -> Result { let wallet_details: AirwallexPaymentMethod = match wallet_data { - domain::WalletData::GooglePay(gpay_details) => { - AirwallexPaymentMethod::Wallets(WalletData::GooglePay(GooglePayData { + WalletData::GooglePay(gpay_details) => { + AirwallexPaymentMethod::Wallets(AirwallexWalletData::GooglePay(GooglePayData { googlepay: GooglePayDetails { encrypted_payment_token: Secret::new( gpay_details.tokenization_data.token.clone(), @@ -238,33 +249,33 @@ fn get_wallet_details( payment_method_type: AirwallexPaymentType::Googlepay, })) } - domain::WalletData::AliPayQr(_) - | domain::WalletData::AliPayRedirect(_) - | domain::WalletData::AliPayHkRedirect(_) - | domain::WalletData::MomoRedirect(_) - | domain::WalletData::KakaoPayRedirect(_) - | domain::WalletData::GoPayRedirect(_) - | domain::WalletData::GcashRedirect(_) - | domain::WalletData::ApplePay(_) - | domain::WalletData::ApplePayRedirect(_) - | domain::WalletData::ApplePayThirdPartySdk(_) - | domain::WalletData::DanaRedirect {} - | domain::WalletData::GooglePayRedirect(_) - | domain::WalletData::GooglePayThirdPartySdk(_) - | domain::WalletData::MbWayRedirect(_) - | domain::WalletData::MobilePayRedirect(_) - | domain::WalletData::PaypalRedirect(_) - | 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::ApplePay(_) + | WalletData::ApplePayRedirect(_) + | WalletData::ApplePayThirdPartySdk(_) + | WalletData::DanaRedirect {} + | WalletData::GooglePayRedirect(_) + | WalletData::GooglePayThirdPartySdk(_) + | WalletData::MbWayRedirect(_) + | WalletData::MobilePayRedirect(_) + | WalletData::PaypalRedirect(_) + | 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("airwallex"), ))?, }; @@ -278,16 +289,16 @@ pub struct AirwallexAuthUpdateResponse { token: Secret, } -impl TryFrom> - for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData, + item: ResponseRouterData, ) -> Result { let expires = (item.response.expires_at - common_utils::date_time::now()).whole_seconds(); Ok(Self { - response: Ok(types::AccessToken { + response: Ok(AccessToken { token: item.response.token, expires, }), @@ -438,7 +449,7 @@ pub struct AirwallexRedirectFormData { #[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] pub struct AirwallexPaymentsNextAction { url: Url, - method: services::Method, + method: Method, data: AirwallexRedirectFormData, stage: AirwallexNextActionStage, } @@ -465,10 +476,8 @@ pub struct AirwallexPaymentsSyncResponse { next_action: Option, } -fn get_redirection_form( - response_url_data: AirwallexPaymentsNextAction, -) -> Option { - Some(services::RedirectForm::Form { +fn get_redirection_form(response_url_data: AirwallexPaymentsNextAction) -> Option { + Some(RedirectForm::Form { endpoint: response_url_data.url.to_string(), method: response_url_data.method, form_fields: std::collections::HashMap::from([ @@ -509,18 +518,12 @@ fn get_redirection_form( }) } -impl - TryFrom> - for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData< - F, - AirwallexPaymentsResponse, - T, - types::PaymentsResponseData, - >, + item: ResponseRouterData, ) -> Result { let (status, redirection_data) = item.response.next_action.clone().map_or( // If no next action is there, map the status and set redirection form as None @@ -568,13 +571,13 @@ impl Ok(Self { status, reference_id: Some(item.response.id.clone()), - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), - redirection_data, - mandate_reference: None, + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(item.response.id.clone()), + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, - connector_response_reference_id: None, + connector_response_reference_id: Some(item.response.id), incremental_authorization_allowed: None, charge_id: None, }), @@ -585,21 +588,21 @@ impl impl TryFrom< - types::ResponseRouterData< - api::PSync, + ResponseRouterData< + PSync, AirwallexPaymentsSyncResponse, PaymentsSyncData, - types::PaymentsResponseData, + PaymentsResponseData, >, > for types::PaymentsSyncRouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData< - api::PSync, + item: ResponseRouterData< + PSync, AirwallexPaymentsSyncResponse, PaymentsSyncData, - types::PaymentsResponseData, + PaymentsResponseData, >, ) -> Result { let status = get_payment_status(&item.response.status, &item.response.next_action); @@ -611,13 +614,13 @@ impl Ok(Self { status, reference_id: Some(item.response.id.clone()), - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), - redirection_data, - mandate_reference: None, + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(item.response.id.clone()), + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, - connector_response_reference_id: None, + connector_response_reference_id: Some(item.response.id), incremental_authorization_allowed: None, charge_id: None, }), @@ -682,16 +685,16 @@ pub struct RefundResponse { status: RefundStatus, } -impl TryFrom> - for types::RefundsRouterData +impl TryFrom> + for types::RefundsRouterData { - type Error = error_stack::Report; + 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, }), @@ -700,16 +703,14 @@ impl TryFrom> } } -impl TryFrom> - for types::RefundsRouterData -{ - type Error = error_stack::Report; +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/connectors/bambora/transformers.rs b/crates/hyperswitch_connectors/src/connectors/bambora/transformers.rs index 4212f7168db3..567f519d7944 100644 --- a/crates/hyperswitch_connectors/src/connectors/bambora/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/bambora/transformers.rs @@ -471,8 +471,8 @@ impl TryFrom TryFrom }, response: Ok(PaymentsResponseData::TransactionResponse { resource_id: ResponseId::ConnectorTransactionId(item.response.id.to_string()), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.order_number.to_string()), @@ -586,8 +586,8 @@ impl }, response: Ok(PaymentsResponseData::TransactionResponse { resource_id: ResponseId::ConnectorTransactionId(item.response.id.to_string()), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.order_number.to_string()), @@ -621,8 +621,8 @@ impl }, response: Ok(PaymentsResponseData::TransactionResponse { resource_id: ResponseId::ConnectorTransactionId(item.response.id.to_string()), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.order_number.to_string()), @@ -656,8 +656,8 @@ impl }, response: Ok(PaymentsResponseData::TransactionResponse { resource_id: ResponseId::ConnectorTransactionId(item.response.id.to_string()), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.order_number.to_string()), diff --git a/crates/hyperswitch_connectors/src/connectors/billwerk/transformers.rs b/crates/hyperswitch_connectors/src/connectors/billwerk/transformers.rs index cc63e1ad7cc1..798f28d1f0a4 100644 --- a/crates/hyperswitch_connectors/src/connectors/billwerk/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/billwerk/transformers.rs @@ -284,8 +284,8 @@ impl TryFrom TryFrom resource_id: ResponseId::ConnectorTransactionId( item.data.attempt_id.clone(), ), - redirection_data: Some(redirection_data), - mandate_reference: None, + redirection_data: Box::new(Some(redirection_data)), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -302,8 +302,8 @@ impl TryFrom TryFrom .map(|x| RedirectForm::from((x, common_utils::request::Method::Get))); Ok(PaymentsResponseData::TransactionResponse { resource_id: ResponseId::ConnectorTransactionId(item.response.data.id.clone()), - redirection_data, - mandate_reference: None, + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: item diff --git a/crates/hyperswitch_connectors/src/connectors/deutschebank/transformers.rs b/crates/hyperswitch_connectors/src/connectors/deutschebank/transformers.rs index e4b011f62045..9dd842768f19 100644 --- a/crates/hyperswitch_connectors/src/connectors/deutschebank/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/deutschebank/transformers.rs @@ -176,7 +176,7 @@ impl TryFrom<&DeutschebankRouterData<&PaymentsAuthorizeRouterData>> } Some(api_models::payments::MandateReferenceId::ConnectorMandateId(mandate_data)) => { let mandate_metadata: DeutschebankMandateMetadata = mandate_data - .mandate_metadata + .get_mandate_metadata() .ok_or(errors::ConnectorError::MissingConnectorMandateMetadata)? .clone() .parse_value("DeutschebankMandateMetadata") @@ -298,16 +298,16 @@ impl }, response: Ok(PaymentsResponseData::TransactionResponse { resource_id: ResponseId::NoResponseId, - redirection_data: Some(RedirectForm::Form { + redirection_data: Box::new(Some(RedirectForm::Form { endpoint: item.data.request.get_complete_authorize_url()?, method: common_utils::request::Method::Get, form_fields: HashMap::from([ ("reference".to_string(), reference.clone()), ("signed_on".to_string(), signed_on.clone()), ]), - }), + })), mandate_reference: if item.data.request.is_mandate_payment() { - Some(MandateReference { + Box::new(Some(MandateReference { connector_mandate_id: item.response.mandate_id, payment_method_id: None, mandate_metadata: Some(serde_json::json!(DeutschebankMandateMetadata { @@ -325,9 +325,10 @@ impl reference: Secret::from(reference.clone()), signed_on, })), - }) + connector_mandate_request_reference_id: None, + })) } else { - None + Box::new(None) }, connector_metadata: None, network_txn_id: None, @@ -375,8 +376,8 @@ impl }, response: Ok(PaymentsResponseData::TransactionResponse { resource_id: ResponseId::ConnectorTransactionId(item.response.tx_id), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -578,8 +579,8 @@ impl }, response: Ok(PaymentsResponseData::TransactionResponse { resource_id: ResponseId::ConnectorTransactionId(item.response.tx_id), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -637,8 +638,8 @@ impl Ok(Self { response: Ok(PaymentsResponseData::TransactionResponse { resource_id: ResponseId::ConnectorTransactionId(item.response.tx_id), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, diff --git a/crates/hyperswitch_connectors/src/connectors/digitalvirgo/transformers.rs b/crates/hyperswitch_connectors/src/connectors/digitalvirgo/transformers.rs index 722c78442da2..856736842f90 100644 --- a/crates/hyperswitch_connectors/src/connectors/digitalvirgo/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/digitalvirgo/transformers.rs @@ -124,8 +124,8 @@ impl TryFrom TryFrom TryFrom TryFrom TryFrom + Sync), +} + +impl Elavon { + pub fn new() -> &'static Self { + &Self { + amount_converter: &StringMinorUnitForConnector, + } + } +} + +impl api::Payment for Elavon {} +impl api::PaymentSession for Elavon {} +impl api::ConnectorAccessToken for Elavon {} +impl api::MandateSetup for Elavon {} +impl api::PaymentAuthorize for Elavon {} +impl api::PaymentSync for Elavon {} +impl api::PaymentCapture for Elavon {} +impl api::PaymentVoid for Elavon {} +impl api::Refund for Elavon {} +impl api::RefundExecute for Elavon {} +impl api::RefundSync for Elavon {} +impl api::PaymentToken for Elavon {} + +impl ConnectorIntegration + for Elavon +{ + // Not Implemented (R) +} + +impl ConnectorCommonExt for Elavon +where + Self: ConnectorIntegration, +{ + fn build_headers( + &self, + req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { + let mut header = vec![( + headers::CONTENT_TYPE.to_string(), + self.get_content_type().to_string().into(), + )]; + let mut api_key = self.get_auth_header(&req.connector_auth_type)?; + header.append(&mut api_key); + Ok(header) + } +} + +impl ConnectorCommon for Elavon { + fn id(&self) -> &'static str { + "elavon" + } + + fn get_currency_unit(&self) -> api::CurrencyUnit { + api::CurrencyUnit::Base + // TODO! Check connector documentation, on which unit they are processing the currency. + // If the connector accepts amount in lower unit ( i.e cents for USD) then return api::CurrencyUnit::Minor, + // if connector accepts amount in base unit (i.e dollars for USD) then return api::CurrencyUnit::Base + } + + fn common_get_content_type(&self) -> &'static str { + "application/json" + } + + fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str { + connectors.elavon.base_url.as_ref() + } + + fn get_auth_header( + &self, + auth_type: &ConnectorAuthType, + ) -> CustomResult)>, errors::ConnectorError> { + let auth = elavon::ElavonAuthType::try_from(auth_type) + .change_context(errors::ConnectorError::FailedToObtainAuthType)?; + Ok(vec![( + headers::AUTHORIZATION.to_string(), + auth.api_key.expose().into_masked(), + )]) + } + + fn build_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + let response: elavon::ElavonErrorResponse = res + .response + .parse_struct("ElavonErrorResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + + event_builder.map(|i| i.set_response_body(&response)); + router_env::logger::info!(connector_response=?response); + + Ok(ErrorResponse { + status_code: res.status_code, + code: response.code, + message: response.message, + reason: response.reason, + attempt_status: None, + connector_transaction_id: None, + }) + } +} + +impl ConnectorValidation for Elavon { + //TODO: implement functions when support enabled +} + +impl ConnectorIntegration for Elavon { + //TODO: implement sessions flow +} + +impl ConnectorIntegration for Elavon {} + +impl ConnectorIntegration for Elavon {} + +impl ConnectorIntegration for Elavon { + fn get_headers( + &self, + req: &PaymentsAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { + self.build_headers(req, connectors) + } + + fn get_content_type(&self) -> &'static str { + self.common_get_content_type() + } + + fn get_url( + &self, + _req: &PaymentsAuthorizeRouterData, + _connectors: &Connectors, + ) -> CustomResult { + Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + } + + fn get_request_body( + &self, + req: &PaymentsAuthorizeRouterData, + _connectors: &Connectors, + ) -> CustomResult { + let amount = utils::convert_amount( + self.amount_converter, + req.request.minor_amount, + req.request.currency, + )?; + + let connector_router_data = elavon::ElavonRouterData::from((amount, req)); + let connector_req = elavon::ElavonPaymentsRequest::try_from(&connector_router_data)?; + Ok(RequestContent::Json(Box::new(connector_req))) + } + + fn build_request( + &self, + req: &PaymentsAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + Ok(Some( + RequestBuilder::new() + .method(Method::Post) + .url(&types::PaymentsAuthorizeType::get_url( + self, req, connectors, + )?) + .attach_default_headers() + .headers(types::PaymentsAuthorizeType::get_headers( + self, req, connectors, + )?) + .set_body(types::PaymentsAuthorizeType::get_request_body( + self, req, connectors, + )?) + .build(), + )) + } + + fn handle_response( + &self, + data: &PaymentsAuthorizeRouterData, + event_builder: Option<&mut ConnectorEvent>, + res: Response, + ) -> CustomResult { + let response: elavon::ElavonPaymentsResponse = res + .response + .parse_struct("Elavon PaymentsAuthorizeResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + event_builder.map(|i| i.set_response_body(&response)); + router_env::logger::info!(connector_response=?response); + RouterData::try_from(ResponseRouterData { + response, + data: data.clone(), + http_code: res.status_code, + }) + } + + fn get_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + self.build_error_response(res, event_builder) + } +} + +impl ConnectorIntegration for Elavon { + fn get_headers( + &self, + req: &PaymentsSyncRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { + self.build_headers(req, connectors) + } + + fn get_content_type(&self) -> &'static str { + self.common_get_content_type() + } + + fn get_url( + &self, + _req: &PaymentsSyncRouterData, + _connectors: &Connectors, + ) -> CustomResult { + Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + } + + fn build_request( + &self, + req: &PaymentsSyncRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + Ok(Some( + RequestBuilder::new() + .method(Method::Get) + .url(&types::PaymentsSyncType::get_url(self, req, connectors)?) + .attach_default_headers() + .headers(types::PaymentsSyncType::get_headers(self, req, connectors)?) + .build(), + )) + } + + fn handle_response( + &self, + data: &PaymentsSyncRouterData, + event_builder: Option<&mut ConnectorEvent>, + res: Response, + ) -> CustomResult { + let response: elavon::ElavonPaymentsResponse = res + .response + .parse_struct("elavon PaymentsSyncResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + event_builder.map(|i| i.set_response_body(&response)); + router_env::logger::info!(connector_response=?response); + RouterData::try_from(ResponseRouterData { + response, + data: data.clone(), + http_code: res.status_code, + }) + } + + fn get_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + self.build_error_response(res, event_builder) + } +} + +impl ConnectorIntegration for Elavon { + fn get_headers( + &self, + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { + self.build_headers(req, connectors) + } + + fn get_content_type(&self) -> &'static str { + self.common_get_content_type() + } + + fn get_url( + &self, + _req: &PaymentsCaptureRouterData, + _connectors: &Connectors, + ) -> CustomResult { + Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + } + + fn get_request_body( + &self, + _req: &PaymentsCaptureRouterData, + _connectors: &Connectors, + ) -> CustomResult { + Err(errors::ConnectorError::NotImplemented("get_request_body method".to_string()).into()) + } + + fn build_request( + &self, + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + Ok(Some( + RequestBuilder::new() + .method(Method::Post) + .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?) + .attach_default_headers() + .headers(types::PaymentsCaptureType::get_headers( + self, req, connectors, + )?) + .set_body(types::PaymentsCaptureType::get_request_body( + self, req, connectors, + )?) + .build(), + )) + } + + fn handle_response( + &self, + data: &PaymentsCaptureRouterData, + event_builder: Option<&mut ConnectorEvent>, + res: Response, + ) -> CustomResult { + let response: elavon::ElavonPaymentsResponse = res + .response + .parse_struct("Elavon PaymentsCaptureResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + event_builder.map(|i| i.set_response_body(&response)); + router_env::logger::info!(connector_response=?response); + RouterData::try_from(ResponseRouterData { + response, + data: data.clone(), + http_code: res.status_code, + }) + } + + fn get_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + self.build_error_response(res, event_builder) + } +} + +impl ConnectorIntegration for Elavon {} + +impl ConnectorIntegration for Elavon { + fn get_headers( + &self, + req: &RefundsRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { + self.build_headers(req, connectors) + } + + fn get_content_type(&self) -> &'static str { + self.common_get_content_type() + } + + fn get_url( + &self, + _req: &RefundsRouterData, + _connectors: &Connectors, + ) -> CustomResult { + Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + } + + fn get_request_body( + &self, + req: &RefundsRouterData, + _connectors: &Connectors, + ) -> CustomResult { + let refund_amount = utils::convert_amount( + self.amount_converter, + req.request.minor_refund_amount, + req.request.currency, + )?; + + let connector_router_data = elavon::ElavonRouterData::from((refund_amount, req)); + let connector_req = elavon::ElavonRefundRequest::try_from(&connector_router_data)?; + Ok(RequestContent::Json(Box::new(connector_req))) + } + + fn build_request( + &self, + 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( + self, req, connectors, + )?) + .set_body(types::RefundExecuteType::get_request_body( + self, req, connectors, + )?) + .build(); + Ok(Some(request)) + } + + fn handle_response( + &self, + data: &RefundsRouterData, + event_builder: Option<&mut ConnectorEvent>, + res: Response, + ) -> CustomResult, errors::ConnectorError> { + let response: elavon::RefundResponse = + res.response + .parse_struct("elavon RefundResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + event_builder.map(|i| i.set_response_body(&response)); + router_env::logger::info!(connector_response=?response); + RouterData::try_from(ResponseRouterData { + response, + data: data.clone(), + http_code: res.status_code, + }) + } + + fn get_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + self.build_error_response(res, event_builder) + } +} + +impl ConnectorIntegration for Elavon { + fn get_headers( + &self, + req: &RefundSyncRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { + self.build_headers(req, connectors) + } + + fn get_content_type(&self) -> &'static str { + self.common_get_content_type() + } + + fn get_url( + &self, + _req: &RefundSyncRouterData, + _connectors: &Connectors, + ) -> CustomResult { + Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + } + + fn build_request( + &self, + req: &RefundSyncRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + Ok(Some( + RequestBuilder::new() + .method(Method::Get) + .url(&types::RefundSyncType::get_url(self, req, connectors)?) + .attach_default_headers() + .headers(types::RefundSyncType::get_headers(self, req, connectors)?) + .set_body(types::RefundSyncType::get_request_body( + self, req, connectors, + )?) + .build(), + )) + } + + fn handle_response( + &self, + data: &RefundSyncRouterData, + event_builder: Option<&mut ConnectorEvent>, + res: Response, + ) -> CustomResult { + let response: elavon::RefundResponse = res + .response + .parse_struct("elavon RefundSyncResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + event_builder.map(|i| i.set_response_body(&response)); + router_env::logger::info!(connector_response=?response); + RouterData::try_from(ResponseRouterData { + response, + data: data.clone(), + http_code: res.status_code, + }) + } + + fn get_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + self.build_error_response(res, event_builder) + } +} + +#[async_trait::async_trait] +impl webhooks::IncomingWebhook for Elavon { + fn get_webhook_object_reference_id( + &self, + _request: &webhooks::IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { + Err(report!(errors::ConnectorError::WebhooksNotImplemented)) + } + + fn get_webhook_event_type( + &self, + _request: &webhooks::IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { + Err(report!(errors::ConnectorError::WebhooksNotImplemented)) + } + + fn get_webhook_resource_object( + &self, + _request: &webhooks::IncomingWebhookRequestDetails<'_>, + ) -> CustomResult, errors::ConnectorError> { + Err(report!(errors::ConnectorError::WebhooksNotImplemented)) + } +} diff --git a/crates/hyperswitch_connectors/src/connectors/elavon/transformers.rs b/crates/hyperswitch_connectors/src/connectors/elavon/transformers.rs new file mode 100644 index 000000000000..1dbf03ea2757 --- /dev/null +++ b/crates/hyperswitch_connectors/src/connectors/elavon/transformers.rs @@ -0,0 +1,228 @@ +use common_enums::enums; +use common_utils::types::StringMinorUnit; +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::{PaymentsAuthorizeRouterData, RefundsRouterData}, +}; +use hyperswitch_interfaces::errors; +use masking::Secret; +use serde::{Deserialize, Serialize}; + +use crate::{ + types::{RefundsResponseRouterData, ResponseRouterData}, + utils::PaymentsAuthorizeRequestData, +}; + +//TODO: Fill the struct with respective fields +pub struct ElavonRouterData { + pub amount: StringMinorUnit, // The type of amount that a connector accepts, for example, String, i64, f64, etc. + pub router_data: T, +} + +impl From<(StringMinorUnit, T)> for ElavonRouterData { + fn from((amount, item): (StringMinorUnit, T)) -> Self { + //Todo : use utils to convert the amount to the type of amount that a connector accepts + Self { + amount, + router_data: item, + } + } +} + +//TODO: Fill the struct with respective fields +#[derive(Default, Debug, Serialize, PartialEq)] +pub struct ElavonPaymentsRequest { + amount: StringMinorUnit, + card: ElavonCard, +} + +#[derive(Default, Debug, Serialize, Eq, PartialEq)] +pub struct ElavonCard { + number: cards::CardNumber, + expiry_month: Secret, + expiry_year: Secret, + cvc: Secret, + complete: bool, +} + +impl TryFrom<&ElavonRouterData<&PaymentsAuthorizeRouterData>> for ElavonPaymentsRequest { + type Error = error_stack::Report; + fn try_from( + item: &ElavonRouterData<&PaymentsAuthorizeRouterData>, + ) -> Result { + match item.router_data.request.payment_method_data.clone() { + PaymentMethodData::Card(req_card) => { + let card = ElavonCard { + number: req_card.card_number, + expiry_month: req_card.card_exp_month, + expiry_year: req_card.card_exp_year, + cvc: req_card.card_cvc, + complete: item.router_data.request.is_auto_capture()?, + }; + Ok(Self { + amount: item.amount.clone(), + card, + }) + } + _ => Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()), + } + } +} + +//TODO: Fill the struct with respective fields +// Auth Struct +pub struct ElavonAuthType { + pub(super) api_key: Secret, +} + +impl TryFrom<&ConnectorAuthType> for ElavonAuthType { + type Error = error_stack::Report; + fn try_from(auth_type: &ConnectorAuthType) -> Result { + match auth_type { + ConnectorAuthType::HeaderKey { api_key } => Ok(Self { + api_key: api_key.to_owned(), + }), + _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()), + } + } +} +// PaymentsResponse +//TODO: Append the remaining status flags +#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum ElavonPaymentStatus { + Succeeded, + Failed, + #[default] + Processing, +} + +impl From for common_enums::AttemptStatus { + fn from(item: ElavonPaymentStatus) -> Self { + match item { + ElavonPaymentStatus::Succeeded => Self::Charged, + ElavonPaymentStatus::Failed => Self::Failure, + ElavonPaymentStatus::Processing => Self::Authorizing, + } + } +} + +//TODO: Fill the struct with respective fields +#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct ElavonPaymentsResponse { + status: ElavonPaymentStatus, + id: String, +} + +impl TryFrom> + for RouterData +{ + type Error = error_stack::Report; + fn try_from( + item: ResponseRouterData, + ) -> Result { + Ok(Self { + status: common_enums::AttemptStatus::from(item.response.status), + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(item.response.id), + redirection_data: Box::new(None), + mandate_reference: Box::new(None), + connector_metadata: None, + network_txn_id: None, + connector_response_reference_id: None, + incremental_authorization_allowed: None, + charge_id: None, + }), + ..item.data + }) + } +} + +//TODO: Fill the struct with respective fields +// REFUND : +// Type definition for RefundRequest +#[derive(Default, Debug, Serialize)] +pub struct ElavonRefundRequest { + pub amount: StringMinorUnit, +} + +impl TryFrom<&ElavonRouterData<&RefundsRouterData>> for ElavonRefundRequest { + type Error = error_stack::Report; + fn try_from(item: &ElavonRouterData<&RefundsRouterData>) -> Result { + Ok(Self { + amount: item.amount.to_owned(), + }) + } +} + +// Type definition for Refund Response + +#[allow(dead_code)] +#[derive(Debug, Serialize, Default, Deserialize, Clone)] +pub enum RefundStatus { + Succeeded, + Failed, + #[default] + Processing, +} + +impl From for enums::RefundStatus { + fn from(item: RefundStatus) -> Self { + match item { + RefundStatus::Succeeded => Self::Success, + RefundStatus::Failed => Self::Failure, + RefundStatus::Processing => Self::Pending, + //TODO: Review mapping + } + } +} + +//TODO: Fill the struct with respective fields +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +pub struct RefundResponse { + id: String, + status: RefundStatus, +} + +impl TryFrom> for RefundsRouterData { + type Error = error_stack::Report; + fn try_from( + item: RefundsResponseRouterData, + ) -> Result { + Ok(Self { + response: Ok(RefundsResponseData { + connector_refund_id: item.response.id.to_string(), + refund_status: enums::RefundStatus::from(item.response.status), + }), + ..item.data + }) + } +} + +impl TryFrom> for RefundsRouterData { + type Error = error_stack::Report; + fn try_from( + item: RefundsResponseRouterData, + ) -> Result { + Ok(Self { + response: Ok(RefundsResponseData { + connector_refund_id: item.response.id.to_string(), + refund_status: enums::RefundStatus::from(item.response.status), + }), + ..item.data + }) + } +} + +//TODO: Fill the struct with respective fields +#[derive(Default, Debug, Serialize, Deserialize, PartialEq)] +pub struct ElavonErrorResponse { + pub status_code: u16, + pub code: String, + pub message: String, + pub reason: Option, +} diff --git a/crates/hyperswitch_connectors/src/connectors/fiserv/transformers.rs b/crates/hyperswitch_connectors/src/connectors/fiserv/transformers.rs index cdcd82f5b4f0..6f4f303ae8ec 100644 --- a/crates/hyperswitch_connectors/src/connectors/fiserv/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/fiserv/transformers.rs @@ -374,8 +374,8 @@ impl TryFrom TryFrom TryFrom(data: &[u8]) -> Result where @@ -210,6 +215,15 @@ impl ConnectorValidation for Fiuu { ), } } + fn validate_mandate_payment( + &self, + pm_type: Option, + pm_data: PaymentMethodData, + ) -> CustomResult<(), errors::ConnectorError> { + let mandate_supported_pmd: HashSet = + HashSet::from([PaymentMethodDataType::Card]); + utils::is_mandate_supported(pm_data, pm_type, mandate_supported_pmd, self.id()) + } } impl ConnectorIntegration for Fiuu { @@ -231,13 +245,21 @@ impl ConnectorIntegration CustomResult { - Ok(format!( - "{}RMS/API/Direct/1.4.0/index.php", - self.base_url(connectors) - )) + let url = if req.request.off_session == Some(true) { + format!( + "{}/RMS/API/Recurring/input_v7.php", + self.base_url(connectors) + ) + } else { + format!( + "{}RMS/API/Direct/1.4.0/index.php", + self.base_url(connectors) + ) + }; + Ok(url) } fn get_request_body( @@ -252,9 +274,15 @@ impl ConnectorIntegration for FPXTxnChannel { } } +#[derive(Serialize, Debug, Clone)] +pub struct FiuuMandateRequest { + #[serde(rename = "0")] + mandate_request: Secret, +} + +#[derive(Serialize, Debug, Clone)] +pub struct FiuuRecurringRequest { + record_type: FiuuRecordType, + merchant_id: Secret, + token: Secret, + order_id: String, + currency: Currency, + amount: StringMajorUnit, + billing_name: Secret, + email: Email, + verify_key: Secret, +} + +#[derive(Serialize, Debug, Clone, strum::Display)] +pub enum FiuuRecordType { + T, +} + +impl TryFrom<&FiuuRouterData<&PaymentsAuthorizeRouterData>> for FiuuMandateRequest { + type Error = Report; + fn try_from(item: &FiuuRouterData<&PaymentsAuthorizeRouterData>) -> Result { + let auth: FiuuAuthType = FiuuAuthType::try_from(&item.router_data.connector_auth_type)?; + let record_type = FiuuRecordType::T; + let merchant_id = auth.merchant_id; + let order_id = item.router_data.connector_request_reference_id.clone(); + let currency = item.router_data.request.currency; + let amount = item.amount.clone(); + let billing_name = item.router_data.get_billing_full_name()?; + let email = item.router_data.request.get_email()?; + let token = Secret::new(item.router_data.request.get_connector_mandate_id()?); + let verify_key = auth.verify_key; + let recurring_request = FiuuRecurringRequest { + record_type: record_type.clone(), + merchant_id: merchant_id.clone(), + token: token.clone(), + order_id: order_id.clone(), + currency, + amount: amount.clone(), + billing_name: billing_name.clone(), + email: email.clone(), + verify_key: verify_key.clone(), + }; + let check_sum = calculate_check_sum(recurring_request)?; + let mandate_request = format!( + "{}|{}||{}|{}|{}|{}|{}|{}|||{}", + record_type, + merchant_id.peek(), + token.peek(), + order_id, + currency, + amount.get_amount_as_string(), + billing_name.peek(), + email.peek(), + check_sum.peek() + ); + Ok(Self { + mandate_request: mandate_request.into(), + }) + } +} + +pub fn calculate_check_sum( + req: FiuuRecurringRequest, +) -> CustomResult, errors::ConnectorError> { + let formatted_string = format!( + "{}{}{}{}{}{}{}", + req.record_type, + req.merchant_id.peek(), + req.token.peek(), + req.order_id, + req.currency, + req.amount.get_amount_as_string(), + req.verify_key.peek() + ); + Ok(Secret::new(hex::encode( + crypto::Md5 + .generate_digest(formatted_string.as_bytes()) + .change_context(errors::ConnectorError::RequestEncodingFailed)?, + ))) +} + #[derive(Serialize, Debug, Clone)] #[serde(rename_all = "PascalCase")] pub struct FiuuPaymentRequest { @@ -181,6 +271,8 @@ pub struct FiuuPaymentRequest { signature: Secret, #[serde(rename = "ReturnURL")] return_url: Option, + #[serde(rename = "NotificationURL")] + notification_url: Option, #[serde(flatten)] payment_method_data: FiuuPaymentMethodData, } @@ -219,6 +311,12 @@ pub struct FiuuCardData { cc_cvv2: Secret, cc_month: Secret, cc_year: Secret, + #[serde(rename = "mpstokenstatus")] + mps_token_status: Option, + #[serde(rename = "CustName")] + customer_name: Option>, + #[serde(rename = "CustEmail")] + customer_email: Option, } #[derive(Serialize, Debug, Clone)] @@ -278,7 +376,7 @@ pub fn calculate_signature( ) -> Result, Report> { let message = signature_data.as_bytes(); let encoded_data = hex::encode( - common_utils::crypto::Md5 + crypto::Md5 .generate_digest(message) .change_context(errors::ConnectorError::RequestEncodingFailed)?, ); @@ -307,8 +405,14 @@ impl TryFrom<&FiuuRouterData<&PaymentsAuthorizeRouterData>> for FiuuPaymentReque false => 1, true => 0, }; + let notification_url = Some( + Url::parse(&item.router_data.request.get_webhook_url()?) + .change_context(errors::ConnectorError::RequestEncodingFailed)?, + ); let payment_method_data = match item.router_data.request.payment_method_data { - PaymentMethodData::Card(ref card) => FiuuPaymentMethodData::try_from((card, &non_3ds)), + PaymentMethodData::Card(ref card) => { + FiuuPaymentMethodData::try_from((card, item.router_data)) + } PaymentMethodData::RealTimePayment(ref real_time_payment_data) => { match *real_time_payment_data.clone() { RealTimePaymentData::DuitNow {} => { @@ -434,20 +538,40 @@ impl TryFrom<&FiuuRouterData<&PaymentsAuthorizeRouterData>> for FiuuPaymentReque return_url, payment_method_data, signature, + notification_url, }) } } -impl TryFrom<(&Card, &i32)> for FiuuPaymentMethodData { +impl TryFrom<(&Card, &PaymentsAuthorizeRouterData)> for FiuuPaymentMethodData { type Error = Report; - fn try_from((req_card, non_3ds): (&Card, &i32)) -> Result { + fn try_from( + (req_card, item): (&Card, &PaymentsAuthorizeRouterData), + ) -> Result { + let (mps_token_status, customer_name, customer_email) = + if item.request.is_customer_initiated_mandate_payment() { + ( + Some(1), + Some(item.request.get_customer_name()?), + Some(item.request.get_email()?), + ) + } else { + (None, None, None) + }; + let non_3ds = match item.is_three_ds() { + false => 1, + true => 0, + }; Ok(Self::FiuuCardData(Box::new(FiuuCardData { txn_channel: TxnChannel::Creditan, - non_3ds: *non_3ds, + non_3ds, cc_pan: req_card.card_number.clone(), cc_cvv2: req_card.card_cvc.clone(), cc_month: req_card.card_exp_month.clone(), cc_year: req_card.card_exp_year.clone(), + mps_token_status, + customer_name, + customer_email, }))) } } @@ -543,6 +667,23 @@ pub enum FiuuPaymentsResponse { PaymentResponse(Box), QRPaymentResponse(Box), Error(FiuuErrorResponse), + RecurringResponse(Vec>), +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct FiuuRecurringResponse { + status: FiuuRecurringStautus, + #[serde(rename = "orderid")] + order_id: String, + #[serde(rename = "tranID")] + tran_id: Option, + reason: Option, +} +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "snake_case")] +pub enum FiuuRecurringStautus { + Accepted, + Failed, } #[derive(Debug, Serialize, Deserialize)] @@ -581,10 +722,17 @@ pub struct NonThreeDSResponseData { #[serde(rename = "tranID")] pub tran_id: String, pub status: String, + #[serde(rename = "extraP")] + pub extra_parameters: Option, pub error_code: Option, pub error_desc: Option, } +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct ExtraParameters { + token: Option>, +} + impl TryFrom< ResponseRouterData, @@ -604,8 +752,8 @@ impl status: enums::AttemptStatus::AuthenticationPending, response: Ok(PaymentsResponseData::TransactionResponse { resource_id: ResponseId::ConnectorTransactionId(response.txn_id.clone()), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: get_qr_metadata(response)?, network_txn_id: None, connector_response_reference_id: None, @@ -640,8 +788,8 @@ impl status: enums::AttemptStatus::AuthenticationPending, response: Ok(PaymentsResponseData::TransactionResponse { resource_id: ResponseId::ConnectorTransactionId(data.txn_id), - redirection_data, - mandate_reference: None, + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -652,6 +800,18 @@ impl }) } RequestData::NonThreeDS(non_threeds_data) => { + let mandate_reference = + non_threeds_data + .extra_parameters + .as_ref() + .and_then(|extra_p| { + extra_p.token.as_ref().map(|token| MandateReference { + connector_mandate_id: Some(token.clone().expose()), + payment_method_id: None, + mandate_metadata: None, + connector_mandate_request_reference_id: None, + }) + }); let status = match non_threeds_data.status.as_str() { "00" => { if item.data.request.is_auto_capture()? { @@ -684,8 +844,8 @@ impl } else { Ok(PaymentsResponseData::TransactionResponse { resource_id: ResponseId::ConnectorTransactionId(data.txn_id), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(mandate_reference), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -700,6 +860,80 @@ impl }) } }, + FiuuPaymentsResponse::RecurringResponse(ref recurring_response_vec) => { + let recurring_response_item = recurring_response_vec.first(); + let router_data_response = match recurring_response_item { + Some(recurring_response) => { + let status = + common_enums::AttemptStatus::from(recurring_response.status.clone()); + let connector_transaction_id = recurring_response + .tran_id + .as_ref() + .map_or(ResponseId::NoResponseId, |tran_id| { + ResponseId::ConnectorTransactionId(tran_id.clone()) + }); + let response = if status == common_enums::AttemptStatus::Failure { + Err(ErrorResponse { + code: recurring_response + .reason + .clone() + .unwrap_or_else(|| "NO_ERROR_CODE".to_string()), + message: recurring_response + .reason + .clone() + .unwrap_or_else(|| "NO_ERROR_MESSAGE".to_string()), + reason: recurring_response.reason.clone(), + status_code: item.http_code, + attempt_status: None, + connector_transaction_id: recurring_response.tran_id.clone(), + }) + } else { + Ok(PaymentsResponseData::TransactionResponse { + resource_id: connector_transaction_id, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), + connector_metadata: None, + network_txn_id: None, + connector_response_reference_id: None, + incremental_authorization_allowed: None, + charge_id: None, + }) + }; + Self { + status, + response, + ..item.data + } + } + None => { + // It is not expected to get empty response from the connnector, if we get we are not updating the payment response since we don't have any info in the authorize response. + let response = Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::NoResponseId, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), + connector_metadata: None, + network_txn_id: None, + connector_response_reference_id: None, + incremental_authorization_allowed: None, + charge_id: None, + }); + Self { + response, + ..item.data + } + } + }; + Ok(router_data_response) + } + } + } +} + +impl From for common_enums::AttemptStatus { + fn from(status: FiuuRecurringStautus) -> Self { + match status { + FiuuRecurringStautus::Accepted => Self::Charged, + FiuuRecurringStautus::Failed => Self::Failure, } } } @@ -924,8 +1158,8 @@ impl TryFrom> for PaymentsSy }; let payments_response_data = PaymentsResponseData::TransactionResponse { resource_id: item.data.request.connector_transaction_id.clone(), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -943,6 +1177,28 @@ impl TryFrom> for PaymentsSy capture_method: item.data.request.capture_method, status: response.status, })?; + let mandate_reference = response.extra_parameters.as_ref().and_then(|extra_p| { + let mandate_token: Result = serde_json::from_str(extra_p); + match mandate_token { + Ok(token) => { + token.token.as_ref().map(|token| MandateReference { + connector_mandate_id: Some(token.clone().expose()), + payment_method_id: None, + mandate_metadata: None, + connector_mandate_request_reference_id:None + }) + } + Err(err) => { + router_env::logger::warn!( + "Failed to convert 'extraP' from fiuu webhook response to fiuu::ExtraParameters. \ + Input: '{}', Error: {}", + extra_p, + err + ); + None + } + } + }); let error_response = if status == enums::AttemptStatus::Failure { Some(ErrorResponse { status_code: item.http_code, @@ -963,8 +1219,8 @@ impl TryFrom> for PaymentsSy }; let payments_response_data = PaymentsResponseData::TransactionResponse { resource_id: item.data.request.connector_transaction_id.clone(), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(mandate_reference), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -1130,8 +1386,8 @@ impl TryFrom> }; let payments_response_data = PaymentsResponseData::TransactionResponse { resource_id: ResponseId::ConnectorTransactionId(item.response.tran_id.to_string()), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -1241,8 +1497,8 @@ impl TryFrom> }; let payments_response_data = PaymentsResponseData::TransactionResponse { resource_id: ResponseId::ConnectorTransactionId(item.response.tran_id.to_string()), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -1417,6 +1673,8 @@ pub struct FiuuWebhooksPaymentResponse { pub channel: String, pub error_desc: Option, pub error_code: Option, + #[serde(rename = "extraP")] + pub extra_parameters: Option, } #[derive(Debug, Deserialize, Serialize, Clone)] 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 5ffa3a589c31..fd5c7792887c 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 77% rename from crates/router/src/connector/forte/transformers.rs rename to crates/hyperswitch_connectors/src/connectors/forte/transformers.rs index 79b90d685eef..6e67409238d8 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,23 +285,22 @@ 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()), - redirection_data: None, - mandate_reference: None, + status: get_status(response_code, action), + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(transaction_id.to_string()), + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: Some(serde_json::json!(ForteMeta { auth_id: item.response.authorization_code, })), @@ -323,26 +330,20 @@ 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()), - redirection_data: None, - mandate_reference: None, + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(transaction_id.to_string()), + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: Some(serde_json::json!(ForteMeta { auth_id: item.response.authorization_code, })), @@ -398,20 +399,20 @@ 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()), - redirection_data: None, - mandate_reference: None, + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(transaction_id.clone()), + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: Some(serde_json::json!(ForteMeta { auth_id: item.response.authorization_code, })), @@ -466,21 +467,20 @@ 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()), - redirection_data: None, - mandate_reference: None, + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(transaction_id.to_string()), + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: Some(serde_json::json!(ForteMeta { auth_id: item.response.authorization_code, })), @@ -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/hyperswitch_connectors/src/connectors/globepay/transformers.rs b/crates/hyperswitch_connectors/src/connectors/globepay/transformers.rs index 2e3919cfc484..66525d49c633 100644 --- a/crates/hyperswitch_connectors/src/connectors/globepay/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/globepay/transformers.rs @@ -213,8 +213,8 @@ impl TryFrom TryFrom, + 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/helcim/transformers.rs b/crates/hyperswitch_connectors/src/connectors/helcim/transformers.rs index a01e2cf918d6..427fef3836ce 100644 --- a/crates/hyperswitch_connectors/src/connectors/helcim/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/helcim/transformers.rs @@ -379,8 +379,8 @@ impl resource_id: ResponseId::ConnectorTransactionId( item.response.transaction_id.to_string(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: item.response.invoice_number.clone(), @@ -430,8 +430,8 @@ impl Ok(Self { response: Ok(PaymentsResponseData::TransactionResponse { resource_id, - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata, network_txn_id: None, connector_response_reference_id: item.response.invoice_number.clone(), @@ -479,8 +479,8 @@ impl resource_id: ResponseId::ConnectorTransactionId( item.response.transaction_id.to_string(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: item.response.invoice_number.clone(), @@ -559,8 +559,8 @@ impl resource_id: ResponseId::ConnectorTransactionId( item.response.transaction_id.to_string(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: item.response.invoice_number.clone(), @@ -616,8 +616,8 @@ impl resource_id: ResponseId::ConnectorTransactionId( item.response.transaction_id.to_string(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: item.response.invoice_number.clone(), diff --git a/crates/hyperswitch_connectors/src/connectors/jpmorgan.rs b/crates/hyperswitch_connectors/src/connectors/jpmorgan.rs new file mode 100644 index 000000000000..6095a53ad00b --- /dev/null +++ b/crates/hyperswitch_connectors/src/connectors/jpmorgan.rs @@ -0,0 +1,568 @@ +pub mod transformers; + +use common_utils::{ + errors::CustomResult, + ext_traits::BytesExt, + request::{Method, Request, RequestBuilder, RequestContent}, + types::{AmountConvertor, StringMinorUnit, StringMinorUnitForConnector}, +}; +use error_stack::{report, ResultExt}; +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::{ + PaymentsAuthorizeRouterData, PaymentsCaptureRouterData, PaymentsSyncRouterData, + RefundSyncRouterData, RefundsRouterData, + }, +}; +// +use hyperswitch_interfaces::{ + api::{self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorValidation}, + configs::Connectors, + errors, + events::connector_api_logs::ConnectorEvent, + types::{self, Response}, + webhooks, +}; +use masking::{ExposeInterface, Mask}; +use transformers as jpmorgan; + +use crate::{constants::headers, types::ResponseRouterData, utils}; + +#[derive(Clone)] +pub struct Jpmorgan { + amount_converter: &'static (dyn AmountConvertor + Sync), +} + +impl Jpmorgan { + pub fn new() -> &'static Self { + &Self { + amount_converter: &StringMinorUnitForConnector, + } + } +} + +impl api::Payment for Jpmorgan {} +impl api::PaymentSession for Jpmorgan {} +impl api::ConnectorAccessToken for Jpmorgan {} +impl api::MandateSetup for Jpmorgan {} +impl api::PaymentAuthorize for Jpmorgan {} +impl api::PaymentSync for Jpmorgan {} +impl api::PaymentCapture for Jpmorgan {} +impl api::PaymentVoid for Jpmorgan {} +impl api::Refund for Jpmorgan {} +impl api::RefundExecute for Jpmorgan {} +impl api::RefundSync for Jpmorgan {} +impl api::PaymentToken for Jpmorgan {} + +impl ConnectorIntegration + for Jpmorgan +{ + // Not Implemented (R) +} + +impl ConnectorCommonExt for Jpmorgan +where + Self: ConnectorIntegration, +{ + fn build_headers( + &self, + req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { + let mut header = vec![( + headers::CONTENT_TYPE.to_string(), + self.get_content_type().to_string().into(), + )]; + let mut api_key = self.get_auth_header(&req.connector_auth_type)?; + header.append(&mut api_key); + Ok(header) + } +} + +impl ConnectorCommon for Jpmorgan { + fn id(&self) -> &'static str { + "jpmorgan" + } + + fn get_currency_unit(&self) -> api::CurrencyUnit { + api::CurrencyUnit::Base + //todo!() + // TODO! Check connector documentation, on which unit they are processing the currency. + // If the connector accepts amount in lower unit ( i.e cents for USD) then return api::CurrencyUnit::Minor, + // if connector accepts amount in base unit (i.e dollars for USD) then return api::CurrencyUnit::Base + } + + fn common_get_content_type(&self) -> &'static str { + "application/json" + } + + fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str { + connectors.jpmorgan.base_url.as_ref() + } + + fn get_auth_header( + &self, + auth_type: &ConnectorAuthType, + ) -> CustomResult)>, errors::ConnectorError> { + let auth = jpmorgan::JpmorganAuthType::try_from(auth_type) + .change_context(errors::ConnectorError::FailedToObtainAuthType)?; + Ok(vec![( + headers::AUTHORIZATION.to_string(), + auth.api_key.expose().into_masked(), + )]) + } + + fn build_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + let response: jpmorgan::JpmorganErrorResponse = res + .response + .parse_struct("JpmorganErrorResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + + event_builder.map(|i| i.set_response_body(&response)); + router_env::logger::info!(connector_response=?response); + + Ok(ErrorResponse { + status_code: res.status_code, + code: response.code, + message: response.message, + reason: response.reason, + attempt_status: None, + connector_transaction_id: None, + }) + } +} + +impl ConnectorValidation for Jpmorgan { + //TODO: implement functions when support enabled +} + +impl ConnectorIntegration for Jpmorgan { + //TODO: implement sessions flow +} + +impl ConnectorIntegration for Jpmorgan {} + +impl ConnectorIntegration + for Jpmorgan +{ +} + +impl ConnectorIntegration for Jpmorgan { + fn get_headers( + &self, + req: &PaymentsAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { + self.build_headers(req, connectors) + } + + fn get_content_type(&self) -> &'static str { + self.common_get_content_type() + } + + fn get_url( + &self, + _req: &PaymentsAuthorizeRouterData, + _connectors: &Connectors, + ) -> CustomResult { + Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + } + + fn get_request_body( + &self, + req: &PaymentsAuthorizeRouterData, + _connectors: &Connectors, + ) -> CustomResult { + let amount = utils::convert_amount( + self.amount_converter, + req.request.minor_amount, + req.request.currency, + )?; + + let connector_router_data = jpmorgan::JpmorganRouterData::from((amount, req)); + let connector_req = jpmorgan::JpmorganPaymentsRequest::try_from(&connector_router_data)?; + Ok(RequestContent::Json(Box::new(connector_req))) + } + + fn build_request( + &self, + req: &PaymentsAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + Ok(Some( + RequestBuilder::new() + .method(Method::Post) + .url(&types::PaymentsAuthorizeType::get_url( + self, req, connectors, + )?) + .attach_default_headers() + .headers(types::PaymentsAuthorizeType::get_headers( + self, req, connectors, + )?) + .set_body(types::PaymentsAuthorizeType::get_request_body( + self, req, connectors, + )?) + .build(), + )) + } + + fn handle_response( + &self, + data: &PaymentsAuthorizeRouterData, + event_builder: Option<&mut ConnectorEvent>, + res: Response, + ) -> CustomResult { + let response: jpmorgan::JpmorganPaymentsResponse = res + .response + .parse_struct("Jpmorgan PaymentsAuthorizeResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + event_builder.map(|i| i.set_response_body(&response)); + router_env::logger::info!(connector_response=?response); + RouterData::try_from(ResponseRouterData { + response, + data: data.clone(), + http_code: res.status_code, + }) + } + + fn get_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + self.build_error_response(res, event_builder) + } +} + +impl ConnectorIntegration for Jpmorgan { + fn get_headers( + &self, + req: &PaymentsSyncRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { + self.build_headers(req, connectors) + } + + fn get_content_type(&self) -> &'static str { + self.common_get_content_type() + } + + fn get_url( + &self, + _req: &PaymentsSyncRouterData, + _connectors: &Connectors, + ) -> CustomResult { + Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + } + + fn build_request( + &self, + req: &PaymentsSyncRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + Ok(Some( + RequestBuilder::new() + .method(Method::Get) + .url(&types::PaymentsSyncType::get_url(self, req, connectors)?) + .attach_default_headers() + .headers(types::PaymentsSyncType::get_headers(self, req, connectors)?) + .build(), + )) + } + + fn handle_response( + &self, + data: &PaymentsSyncRouterData, + event_builder: Option<&mut ConnectorEvent>, + res: Response, + ) -> CustomResult { + let response: jpmorgan::JpmorganPaymentsResponse = res + .response + .parse_struct("jpmorgan PaymentsSyncResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + event_builder.map(|i| i.set_response_body(&response)); + router_env::logger::info!(connector_response=?response); + RouterData::try_from(ResponseRouterData { + response, + data: data.clone(), + http_code: res.status_code, + }) + } + + fn get_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + self.build_error_response(res, event_builder) + } +} + +impl ConnectorIntegration for Jpmorgan { + fn get_headers( + &self, + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { + self.build_headers(req, connectors) + } + + fn get_content_type(&self) -> &'static str { + self.common_get_content_type() + } + + fn get_url( + &self, + _req: &PaymentsCaptureRouterData, + _connectors: &Connectors, + ) -> CustomResult { + Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + } + + fn get_request_body( + &self, + _req: &PaymentsCaptureRouterData, + _connectors: &Connectors, + ) -> CustomResult { + Err(errors::ConnectorError::NotImplemented("get_request_body method".to_string()).into()) + } + + fn build_request( + &self, + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + Ok(Some( + RequestBuilder::new() + .method(Method::Post) + .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?) + .attach_default_headers() + .headers(types::PaymentsCaptureType::get_headers( + self, req, connectors, + )?) + .set_body(types::PaymentsCaptureType::get_request_body( + self, req, connectors, + )?) + .build(), + )) + } + + fn handle_response( + &self, + data: &PaymentsCaptureRouterData, + event_builder: Option<&mut ConnectorEvent>, + res: Response, + ) -> CustomResult { + let response: jpmorgan::JpmorganPaymentsResponse = res + .response + .parse_struct("Jpmorgan PaymentsCaptureResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + event_builder.map(|i| i.set_response_body(&response)); + router_env::logger::info!(connector_response=?response); + RouterData::try_from(ResponseRouterData { + response, + data: data.clone(), + http_code: res.status_code, + }) + } + + fn get_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + self.build_error_response(res, event_builder) + } +} + +impl ConnectorIntegration for Jpmorgan {} + +impl ConnectorIntegration for Jpmorgan { + fn get_headers( + &self, + req: &RefundsRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { + self.build_headers(req, connectors) + } + + fn get_content_type(&self) -> &'static str { + self.common_get_content_type() + } + + fn get_url( + &self, + _req: &RefundsRouterData, + _connectors: &Connectors, + ) -> CustomResult { + Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + } + + fn get_request_body( + &self, + req: &RefundsRouterData, + _connectors: &Connectors, + ) -> CustomResult { + let refund_amount = utils::convert_amount( + self.amount_converter, + req.request.minor_refund_amount, + req.request.currency, + )?; + + let connector_router_data = jpmorgan::JpmorganRouterData::from((refund_amount, req)); + let connector_req = jpmorgan::JpmorganRefundRequest::try_from(&connector_router_data)?; + Ok(RequestContent::Json(Box::new(connector_req))) + } + + fn build_request( + &self, + 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( + self, req, connectors, + )?) + .set_body(types::RefundExecuteType::get_request_body( + self, req, connectors, + )?) + .build(); + Ok(Some(request)) + } + + fn handle_response( + &self, + data: &RefundsRouterData, + event_builder: Option<&mut ConnectorEvent>, + res: Response, + ) -> CustomResult, errors::ConnectorError> { + let response: jpmorgan::RefundResponse = res + .response + .parse_struct("jpmorgan RefundResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + event_builder.map(|i| i.set_response_body(&response)); + router_env::logger::info!(connector_response=?response); + RouterData::try_from(ResponseRouterData { + response, + data: data.clone(), + http_code: res.status_code, + }) + } + + fn get_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + self.build_error_response(res, event_builder) + } +} + +impl ConnectorIntegration for Jpmorgan { + fn get_headers( + &self, + req: &RefundSyncRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { + self.build_headers(req, connectors) + } + + fn get_content_type(&self) -> &'static str { + self.common_get_content_type() + } + + fn get_url( + &self, + _req: &RefundSyncRouterData, + _connectors: &Connectors, + ) -> CustomResult { + Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + } + + fn build_request( + &self, + req: &RefundSyncRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + Ok(Some( + RequestBuilder::new() + .method(Method::Get) + .url(&types::RefundSyncType::get_url(self, req, connectors)?) + .attach_default_headers() + .headers(types::RefundSyncType::get_headers(self, req, connectors)?) + .set_body(types::RefundSyncType::get_request_body( + self, req, connectors, + )?) + .build(), + )) + } + + fn handle_response( + &self, + data: &RefundSyncRouterData, + event_builder: Option<&mut ConnectorEvent>, + res: Response, + ) -> CustomResult { + let response: jpmorgan::RefundResponse = res + .response + .parse_struct("jpmorgan RefundSyncResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + event_builder.map(|i| i.set_response_body(&response)); + router_env::logger::info!(connector_response=?response); + RouterData::try_from(ResponseRouterData { + response, + data: data.clone(), + http_code: res.status_code, + }) + } + + fn get_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + self.build_error_response(res, event_builder) + } +} + +#[async_trait::async_trait] +impl webhooks::IncomingWebhook for Jpmorgan { + fn get_webhook_object_reference_id( + &self, + _request: &webhooks::IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { + Err(report!(errors::ConnectorError::WebhooksNotImplemented)) + } + + fn get_webhook_event_type( + &self, + _request: &webhooks::IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { + Err(report!(errors::ConnectorError::WebhooksNotImplemented)) + } + + fn get_webhook_resource_object( + &self, + _request: &webhooks::IncomingWebhookRequestDetails<'_>, + ) -> CustomResult, errors::ConnectorError> { + Err(report!(errors::ConnectorError::WebhooksNotImplemented)) + } +} diff --git a/crates/hyperswitch_connectors/src/connectors/jpmorgan/transformers.rs b/crates/hyperswitch_connectors/src/connectors/jpmorgan/transformers.rs new file mode 100644 index 000000000000..90b058697051 --- /dev/null +++ b/crates/hyperswitch_connectors/src/connectors/jpmorgan/transformers.rs @@ -0,0 +1,228 @@ +use common_enums::enums; +use common_utils::types::StringMinorUnit; +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::{PaymentsAuthorizeRouterData, RefundsRouterData}, +}; +use hyperswitch_interfaces::errors; +use masking::Secret; +use serde::{Deserialize, Serialize}; + +use crate::{ + types::{RefundsResponseRouterData, ResponseRouterData}, + utils::PaymentsAuthorizeRequestData, +}; + +//TODO: Fill the struct with respective fields +pub struct JpmorganRouterData { + pub amount: StringMinorUnit, // The type of amount that a connector accepts, for example, String, i64, f64, etc. + pub router_data: T, +} + +impl From<(StringMinorUnit, T)> for JpmorganRouterData { + fn from((amount, item): (StringMinorUnit, T)) -> Self { + //Todo : use utils to convert the amount to the type of amount that a connector accepts + Self { + amount, + router_data: item, + } + } +} + +//TODO: Fill the struct with respective fields +#[derive(Default, Debug, Serialize, PartialEq)] +pub struct JpmorganPaymentsRequest { + amount: StringMinorUnit, + card: JpmorganCard, +} + +#[derive(Default, Debug, Serialize, Eq, PartialEq)] +pub struct JpmorganCard { + number: cards::CardNumber, + expiry_month: Secret, + expiry_year: Secret, + cvc: Secret, + complete: bool, +} + +impl TryFrom<&JpmorganRouterData<&PaymentsAuthorizeRouterData>> for JpmorganPaymentsRequest { + type Error = error_stack::Report; + fn try_from( + item: &JpmorganRouterData<&PaymentsAuthorizeRouterData>, + ) -> Result { + match item.router_data.request.payment_method_data.clone() { + PaymentMethodData::Card(req_card) => { + let card = JpmorganCard { + number: req_card.card_number, + expiry_month: req_card.card_exp_month, + expiry_year: req_card.card_exp_year, + cvc: req_card.card_cvc, + complete: item.router_data.request.is_auto_capture()?, + }; + Ok(Self { + amount: item.amount.clone(), + card, + }) + } + _ => Err(errors::ConnectorError::NotImplemented("Payment method".to_string()).into()), + } + } +} + +//TODO: Fill the struct with respective fields +// Auth Struct +pub struct JpmorganAuthType { + pub(super) api_key: Secret, +} + +impl TryFrom<&ConnectorAuthType> for JpmorganAuthType { + type Error = error_stack::Report; + fn try_from(auth_type: &ConnectorAuthType) -> Result { + match auth_type { + ConnectorAuthType::HeaderKey { api_key } => Ok(Self { + api_key: api_key.to_owned(), + }), + _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()), + } + } +} +// PaymentsResponse +//TODO: Append the remaining status flags +#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum JpmorganPaymentStatus { + Succeeded, + Failed, + #[default] + Processing, +} + +impl From for common_enums::AttemptStatus { + fn from(item: JpmorganPaymentStatus) -> Self { + match item { + JpmorganPaymentStatus::Succeeded => Self::Charged, + JpmorganPaymentStatus::Failed => Self::Failure, + JpmorganPaymentStatus::Processing => Self::Authorizing, + } + } +} + +//TODO: Fill the struct with respective fields +#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct JpmorganPaymentsResponse { + status: JpmorganPaymentStatus, + id: String, +} + +impl TryFrom> + for RouterData +{ + type Error = error_stack::Report; + fn try_from( + item: ResponseRouterData, + ) -> Result { + Ok(Self { + status: common_enums::AttemptStatus::from(item.response.status), + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(item.response.id), + redirection_data: Box::new(None), + mandate_reference: Box::new(None), + connector_metadata: None, + network_txn_id: None, + connector_response_reference_id: None, + incremental_authorization_allowed: None, + charge_id: None, + }), + ..item.data + }) + } +} + +//TODO: Fill the struct with respective fields +// REFUND : +// Type definition for RefundRequest +#[derive(Default, Debug, Serialize)] +pub struct JpmorganRefundRequest { + pub amount: StringMinorUnit, +} + +impl TryFrom<&JpmorganRouterData<&RefundsRouterData>> for JpmorganRefundRequest { + type Error = error_stack::Report; + fn try_from(item: &JpmorganRouterData<&RefundsRouterData>) -> Result { + Ok(Self { + amount: item.amount.to_owned(), + }) + } +} + +// Type definition for Refund Response + +#[allow(dead_code)] +#[derive(Debug, Serialize, Default, Deserialize, Clone)] +pub enum RefundStatus { + Succeeded, + Failed, + #[default] + Processing, +} + +impl From for enums::RefundStatus { + fn from(item: RefundStatus) -> Self { + match item { + RefundStatus::Succeeded => Self::Success, + RefundStatus::Failed => Self::Failure, + RefundStatus::Processing => Self::Pending, + //TODO: Review mapping + } + } +} + +//TODO: Fill the struct with respective fields +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +pub struct RefundResponse { + id: String, + status: RefundStatus, +} + +impl TryFrom> for RefundsRouterData { + type Error = error_stack::Report; + fn try_from( + item: RefundsResponseRouterData, + ) -> Result { + Ok(Self { + response: Ok(RefundsResponseData { + connector_refund_id: item.response.id.to_string(), + refund_status: enums::RefundStatus::from(item.response.status), + }), + ..item.data + }) + } +} + +impl TryFrom> for RefundsRouterData { + type Error = error_stack::Report; + fn try_from( + item: RefundsResponseRouterData, + ) -> Result { + Ok(Self { + response: Ok(RefundsResponseData { + connector_refund_id: item.response.id.to_string(), + refund_status: enums::RefundStatus::from(item.response.status), + }), + ..item.data + }) + } +} + +//TODO: Fill the struct with respective fields +#[derive(Default, Debug, Serialize, Deserialize, PartialEq)] +pub struct JpmorganErrorResponse { + pub status_code: u16, + pub code: String, + pub message: String, + pub reason: Option, +} diff --git a/crates/hyperswitch_connectors/src/connectors/mollie/transformers.rs b/crates/hyperswitch_connectors/src/connectors/mollie/transformers.rs index dc5f64bee184..cef3d684e7b0 100644 --- a/crates/hyperswitch_connectors/src/connectors/mollie/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/mollie/transformers.rs @@ -507,8 +507,8 @@ impl TryFrom, - _connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + _req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { Ok(vec![]) } } @@ -70,14 +84,14 @@ impl ConnectorCommon for Multisafepay { "application/json" } - fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { + fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str { connectors.multisafepay.base_url.as_ref() } fn get_auth_header( &self, - auth_type: &types::ConnectorAuthType, - ) -> CustomResult)>, errors::ConnectorError> { + auth_type: &ConnectorAuthType, + ) -> CustomResult)>, errors::ConnectorError> { let auth = multisafepay::MultisafepayAuthType::try_from(auth_type) .change_context(errors::ConnectorError::FailedToObtainAuthType)?; Ok(vec![( @@ -101,14 +115,14 @@ impl ConnectorCommon for Multisafepay { let attempt_status = Option::::from(response.clone()); - Ok(ErrorResponse::foreign_from(( + Ok(multisafepay::populate_error_reason( Some(response.error_code.to_string()), Some(response.error_info.clone()), Some(response.error_info), res.status_code, attempt_status, None, - ))) + )) } } @@ -133,7 +147,7 @@ impl ConnectorValidation for Multisafepay { 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, @@ -147,33 +161,21 @@ impl api::Payment for Multisafepay {} impl api::PaymentToken for Multisafepay {} -impl - ConnectorIntegration< - api::PaymentMethodToken, - types::PaymentMethodTokenizationData, - types::PaymentsResponseData, - > for Multisafepay +impl ConnectorIntegration + for Multisafepay { // Not Implemented (R) } impl api::MandateSetup for Multisafepay {} -impl - ConnectorIntegration< - api::SetupMandate, - types::SetupMandateRequestData, - types::PaymentsResponseData, - > for Multisafepay +impl ConnectorIntegration + for Multisafepay { 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 Multisafepay".to_string(), ) @@ -183,27 +185,19 @@ impl impl api::PaymentVoid for Multisafepay {} -impl ConnectorIntegration - for Multisafepay -{ -} +impl ConnectorIntegration for Multisafepay {} impl api::ConnectorAccessToken for Multisafepay {} -impl ConnectorIntegration - for Multisafepay -{ -} +impl ConnectorIntegration for Multisafepay {} impl api::PaymentSync for Multisafepay {} -impl ConnectorIntegration - for Multisafepay -{ +impl ConnectorIntegration for Multisafepay { 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) } @@ -213,8 +207,8 @@ impl ConnectorIntegration CustomResult { let url = self.base_url(connectors); let api_key = multisafepay::MultisafepayAuthType::try_from(&req.connector_auth_type) @@ -227,12 +221,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)?) @@ -250,10 +244,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: multisafepay::MultisafepayAuthResponse = res .response .parse_struct("multisafepay PaymentsResponse") @@ -262,7 +256,7 @@ impl ConnectorIntegration - for Multisafepay -{ -} +impl ConnectorIntegration for Multisafepay {} impl api::PaymentSession for Multisafepay {} -impl ConnectorIntegration - for Multisafepay -{ +impl ConnectorIntegration for Multisafepay { //TODO: implement sessions flow } impl api::PaymentAuthorize for Multisafepay {} -impl ConnectorIntegration - for Multisafepay -{ +impl ConnectorIntegration for Multisafepay { 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) } @@ -304,8 +291,8 @@ impl ConnectorIntegration CustomResult { let url = self.base_url(connectors); let api_key = multisafepay::MultisafepayAuthType::try_from(&req.connector_auth_type) @@ -317,10 +304,10 @@ impl ConnectorIntegration CustomResult { - let amount = connector_utils::convert_amount( + let amount = convert_amount( self.amount_converter, req.request.minor_amount, req.request.currency, @@ -333,12 +320,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, )?) @@ -355,10 +342,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: multisafepay::MultisafepayAuthResponse = res .response .parse_struct("MultisafepayPaymentsResponse") @@ -367,7 +354,7 @@ impl ConnectorIntegration - for Multisafepay -{ +impl ConnectorIntegration for Multisafepay { 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) } @@ -405,8 +390,8 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, + req: &RefundsRouterData, + connectors: &Connectors, ) -> CustomResult { let url = self.base_url(connectors); let api_key = multisafepay::MultisafepayAuthType::try_from(&req.connector_auth_type) @@ -421,10 +406,10 @@ impl ConnectorIntegration, - _connectors: &settings::Connectors, + req: &RefundsRouterData, + _connectors: &Connectors, ) -> CustomResult { - let amount = connector_utils::convert_amount( + let amount = convert_amount( self.amount_converter, req.request.minor_refund_amount, req.request.currency, @@ -438,11 +423,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( @@ -457,17 +442,17 @@ impl ConnectorIntegration, + data: &RefundsRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult, errors::ConnectorError> { + ) -> CustomResult, errors::ConnectorError> { let response: multisafepay::MultisafepayRefundResponse = res .response .parse_struct("multisafepay 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, @@ -484,14 +469,12 @@ impl ConnectorIntegration - for Multisafepay -{ +impl ConnectorIntegration for Multisafepay { 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) } @@ -501,8 +484,8 @@ impl ConnectorIntegration CustomResult { let url = self.base_url(connectors); let api_key = multisafepay::MultisafepayAuthType::try_from(&req.connector_auth_type) @@ -517,12 +500,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)?) @@ -532,17 +515,17 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: multisafepay::MultisafepayRefundResponse = res .response .parse_struct("multisafepay 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, @@ -560,24 +543,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/multisafepay/transformers.rs b/crates/hyperswitch_connectors/src/connectors/multisafepay/transformers.rs similarity index 67% rename from crates/router/src/connector/multisafepay/transformers.rs rename to crates/hyperswitch_connectors/src/connectors/multisafepay/transformers.rs index 9db1cb3701a1..3048a203d1b1 100644 --- a/crates/router/src/connector/multisafepay/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/multisafepay/transformers.rs @@ -1,21 +1,33 @@ -use api_models::enums::BankNames; -use common_enums::AttemptStatus; +use common_enums::{enums, AttemptStatus, BankNames}; use common_utils::{ + errors::ParsingError, pii::{Email, IpAddress}, + request::Method, types::{FloatMajorUnit, MinorUnit}, }; -use masking::ExposeInterface; +use hyperswitch_domain_models::{ + payment_method_data::{BankRedirectData, PayLaterData, PaymentMethodData, WalletData}, + router_data::{ConnectorAuthType, ErrorResponse, RouterData}, + router_flow_types::refunds::{Execute, RSync}, + router_request_types::ResponseId, + router_response_types::{ + MandateReference, PaymentsResponseData, RedirectForm, RefundsResponseData, + }, + types::{self}, +}; +use hyperswitch_interfaces::{ + consts::{NO_ERROR_CODE, NO_ERROR_MESSAGE}, + errors, +}; +use masking::{ExposeInterface, Secret}; use serde::{Deserialize, Serialize}; use url::Url; use crate::{ - connector::utils::{ - self, AddressDetailsData, CardData, PaymentsAuthorizeRequestData, RouterData, + types::{RefundsResponseRouterData, ResponseRouterData}, + utils::{ + self, AddressDetailsData, CardData as _, PaymentsAuthorizeRequestData, RouterData as _, }, - core::errors, - pii::Secret, - services, - types::{self, api, domain, storage::enums, transformers::ForeignFrom}, }; #[derive(Debug, Serialize)] @@ -472,146 +484,144 @@ impl TryFrom<&MultisafepayRouterData<&types::PaymentsAuthorizeRouterData>> item: &MultisafepayRouterData<&types::PaymentsAuthorizeRouterData>, ) -> Result { let payment_type = match item.router_data.request.payment_method_data { - domain::PaymentMethodData::Card(ref _ccard) => Type::Direct, - domain::PaymentMethodData::MandatePayment => Type::Direct, - domain::PaymentMethodData::Wallet(ref wallet_data) => match wallet_data { - domain::WalletData::GooglePay(_) => Type::Direct, - domain::WalletData::PaypalRedirect(_) => Type::Redirect, - domain::WalletData::AliPayQr(_) - | domain::WalletData::AliPayRedirect(_) - | domain::WalletData::AliPayHkRedirect(_) - | domain::WalletData::MomoRedirect(_) - | domain::WalletData::KakaoPayRedirect(_) - | domain::WalletData::GoPayRedirect(_) - | domain::WalletData::GcashRedirect(_) - | domain::WalletData::ApplePay(_) - | domain::WalletData::ApplePayRedirect(_) - | domain::WalletData::ApplePayThirdPartySdk(_) - | domain::WalletData::DanaRedirect {} - | 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( + PaymentMethodData::Card(ref _ccard) => Type::Direct, + PaymentMethodData::MandatePayment => Type::Direct, + PaymentMethodData::Wallet(ref wallet_data) => match wallet_data { + WalletData::GooglePay(_) => Type::Direct, + WalletData::PaypalRedirect(_) => Type::Redirect, + WalletData::AliPayQr(_) + | WalletData::AliPayRedirect(_) + | WalletData::AliPayHkRedirect(_) + | WalletData::MomoRedirect(_) + | WalletData::KakaoPayRedirect(_) + | WalletData::GoPayRedirect(_) + | WalletData::GcashRedirect(_) + | WalletData::ApplePay(_) + | WalletData::ApplePayRedirect(_) + | WalletData::ApplePayThirdPartySdk(_) + | WalletData::DanaRedirect {} + | 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("multisafepay"), ))?, }, - domain::PaymentMethodData::BankRedirect(ref bank_data) => match bank_data { - domain::BankRedirectData::Giropay { .. } => Type::Redirect, - domain::BankRedirectData::Ideal { .. } => Type::Direct, - domain::BankRedirectData::BancontactCard { .. } - | domain::BankRedirectData::Bizum { .. } - | domain::BankRedirectData::Blik { .. } - | domain::BankRedirectData::Eps { .. } - | domain::BankRedirectData::Interac { .. } - | domain::BankRedirectData::OnlineBankingCzechRepublic { .. } - | domain::BankRedirectData::OnlineBankingFinland { .. } - | domain::BankRedirectData::OnlineBankingPoland { .. } - | domain::BankRedirectData::OnlineBankingSlovakia { .. } - | domain::BankRedirectData::OpenBankingUk { .. } - | domain::BankRedirectData::Przelewy24 { .. } - | domain::BankRedirectData::Sofort { .. } - | domain::BankRedirectData::Trustly { .. } - | domain::BankRedirectData::OnlineBankingFpx { .. } - | domain::BankRedirectData::OnlineBankingThailand { .. } - | domain::BankRedirectData::LocalBankRedirect {} => { + PaymentMethodData::BankRedirect(ref bank_data) => match bank_data { + BankRedirectData::Giropay { .. } => Type::Redirect, + BankRedirectData::Ideal { .. } => Type::Direct, + BankRedirectData::BancontactCard { .. } + | BankRedirectData::Bizum { .. } + | BankRedirectData::Blik { .. } + | BankRedirectData::Eps { .. } + | BankRedirectData::Interac { .. } + | BankRedirectData::OnlineBankingCzechRepublic { .. } + | BankRedirectData::OnlineBankingFinland { .. } + | BankRedirectData::OnlineBankingPoland { .. } + | BankRedirectData::OnlineBankingSlovakia { .. } + | BankRedirectData::OpenBankingUk { .. } + | BankRedirectData::Przelewy24 { .. } + | BankRedirectData::Sofort { .. } + | BankRedirectData::Trustly { .. } + | BankRedirectData::OnlineBankingFpx { .. } + | BankRedirectData::OnlineBankingThailand { .. } + | BankRedirectData::LocalBankRedirect {} => { Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("multisafepay"), ))? } }, - domain::PaymentMethodData::PayLater(ref _paylater) => Type::Redirect, + PaymentMethodData::PayLater(ref _paylater) => Type::Redirect, _ => Type::Redirect, }; let gateway = match item.router_data.request.payment_method_data { - domain::PaymentMethodData::Card(ref ccard) => { + PaymentMethodData::Card(ref ccard) => { Some(Gateway::try_from(ccard.get_card_issuer()?)?) } - domain::PaymentMethodData::Wallet(ref wallet_data) => Some(match wallet_data { - domain::WalletData::GooglePay(_) => Gateway::Googlepay, - domain::WalletData::PaypalRedirect(_) => Gateway::Paypal, - domain::WalletData::AliPayQr(_) - | domain::WalletData::AliPayRedirect(_) - | domain::WalletData::AliPayHkRedirect(_) - | domain::WalletData::MomoRedirect(_) - | domain::WalletData::KakaoPayRedirect(_) - | domain::WalletData::GoPayRedirect(_) - | domain::WalletData::GcashRedirect(_) - | domain::WalletData::ApplePay(_) - | domain::WalletData::ApplePayRedirect(_) - | domain::WalletData::ApplePayThirdPartySdk(_) - | domain::WalletData::DanaRedirect {} - | 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( + PaymentMethodData::Wallet(ref wallet_data) => Some(match wallet_data { + WalletData::GooglePay(_) => Gateway::Googlepay, + WalletData::PaypalRedirect(_) => Gateway::Paypal, + WalletData::AliPayQr(_) + | WalletData::AliPayRedirect(_) + | WalletData::AliPayHkRedirect(_) + | WalletData::MomoRedirect(_) + | WalletData::KakaoPayRedirect(_) + | WalletData::GoPayRedirect(_) + | WalletData::GcashRedirect(_) + | WalletData::ApplePay(_) + | WalletData::ApplePayRedirect(_) + | WalletData::ApplePayThirdPartySdk(_) + | WalletData::DanaRedirect {} + | 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("multisafepay"), ))?, }), - domain::PaymentMethodData::BankRedirect(ref bank_data) => Some(match bank_data { - domain::BankRedirectData::Giropay { .. } => Gateway::Giropay, - domain::BankRedirectData::Ideal { .. } => Gateway::Ideal, - domain::BankRedirectData::BancontactCard { .. } - | domain::BankRedirectData::Bizum { .. } - | domain::BankRedirectData::Blik { .. } - | domain::BankRedirectData::Eps { .. } - | domain::BankRedirectData::Interac { .. } - | domain::BankRedirectData::OnlineBankingCzechRepublic { .. } - | domain::BankRedirectData::OnlineBankingFinland { .. } - | domain::BankRedirectData::OnlineBankingPoland { .. } - | domain::BankRedirectData::OnlineBankingSlovakia { .. } - | domain::BankRedirectData::OpenBankingUk { .. } - | domain::BankRedirectData::Przelewy24 { .. } - | domain::BankRedirectData::Sofort { .. } - | domain::BankRedirectData::Trustly { .. } - | domain::BankRedirectData::OnlineBankingFpx { .. } - | domain::BankRedirectData::OnlineBankingThailand { .. } - | domain::BankRedirectData::LocalBankRedirect {} => { + PaymentMethodData::BankRedirect(ref bank_data) => Some(match bank_data { + BankRedirectData::Giropay { .. } => Gateway::Giropay, + BankRedirectData::Ideal { .. } => Gateway::Ideal, + BankRedirectData::BancontactCard { .. } + | BankRedirectData::Bizum { .. } + | BankRedirectData::Blik { .. } + | BankRedirectData::Eps { .. } + | BankRedirectData::Interac { .. } + | BankRedirectData::OnlineBankingCzechRepublic { .. } + | BankRedirectData::OnlineBankingFinland { .. } + | BankRedirectData::OnlineBankingPoland { .. } + | BankRedirectData::OnlineBankingSlovakia { .. } + | BankRedirectData::OpenBankingUk { .. } + | BankRedirectData::Przelewy24 { .. } + | BankRedirectData::Sofort { .. } + | BankRedirectData::Trustly { .. } + | BankRedirectData::OnlineBankingFpx { .. } + | BankRedirectData::OnlineBankingThailand { .. } + | BankRedirectData::LocalBankRedirect {} => { Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("multisafepay"), ))? } }), - domain::PaymentMethodData::PayLater(domain::PayLaterData::KlarnaRedirect {}) => { - Some(Gateway::Klarna) - } - domain::PaymentMethodData::MandatePayment => None, - domain::PaymentMethodData::CardRedirect(_) - | domain::PaymentMethodData::PayLater(_) - | domain::PaymentMethodData::BankDebit(_) - | domain::PaymentMethodData::BankTransfer(_) - | domain::PaymentMethodData::Crypto(_) - | 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::PayLater(PayLaterData::KlarnaRedirect {}) => Some(Gateway::Klarna), + PaymentMethodData::MandatePayment => None, + PaymentMethodData::CardRedirect(_) + | PaymentMethodData::PayLater(_) + | PaymentMethodData::BankDebit(_) + | PaymentMethodData::BankTransfer(_) + | PaymentMethodData::Crypto(_) + | 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("multisafepay"), ))? @@ -673,7 +683,7 @@ impl TryFrom<&MultisafepayRouterData<&types::PaymentsAuthorizeRouterData>> }; let gateway_info = match item.router_data.request.payment_method_data { - domain::PaymentMethodData::Card(ref ccard) => Some(GatewayInfo::Card(CardInfo { + PaymentMethodData::Card(ref ccard) => Some(GatewayInfo::Card(CardInfo { card_number: Some(ccard.card_number.clone()), card_expiry_date: Some(Secret::new( (format!( @@ -690,8 +700,8 @@ impl TryFrom<&MultisafepayRouterData<&types::PaymentsAuthorizeRouterData>> moto: None, term_url: None, })), - domain::PaymentMethodData::Wallet(ref wallet_data) => match wallet_data { - domain::WalletData::GooglePay(ref google_pay) => { + PaymentMethodData::Wallet(ref wallet_data) => match wallet_data { + WalletData::GooglePay(ref google_pay) => { Some(GatewayInfo::Wallet(WalletInfo::GooglePay({ GpayInfo { payment_token: Some(Secret::new( @@ -700,49 +710,47 @@ impl TryFrom<&MultisafepayRouterData<&types::PaymentsAuthorizeRouterData>> } }))) } - domain::WalletData::PaypalRedirect(_) => None, - domain::WalletData::AliPayQr(_) - | domain::WalletData::AliPayRedirect(_) - | domain::WalletData::AliPayHkRedirect(_) - | domain::WalletData::MomoRedirect(_) - | domain::WalletData::KakaoPayRedirect(_) - | domain::WalletData::GoPayRedirect(_) - | domain::WalletData::GcashRedirect(_) - | domain::WalletData::ApplePay(_) - | domain::WalletData::ApplePayRedirect(_) - | domain::WalletData::ApplePayThirdPartySdk(_) - | domain::WalletData::DanaRedirect {} - | 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::PaypalRedirect(_) => None, + WalletData::AliPayQr(_) + | WalletData::AliPayRedirect(_) + | WalletData::AliPayHkRedirect(_) + | WalletData::MomoRedirect(_) + | WalletData::KakaoPayRedirect(_) + | WalletData::GoPayRedirect(_) + | WalletData::GcashRedirect(_) + | WalletData::ApplePay(_) + | WalletData::ApplePayRedirect(_) + | WalletData::ApplePayThirdPartySdk(_) + | WalletData::DanaRedirect {} + | 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("multisafepay"), ))?, }, - domain::PaymentMethodData::PayLater(ref paylater) => { + PaymentMethodData::PayLater(ref paylater) => { Some(GatewayInfo::PayLater(PayLaterInfo { email: Some(match paylater { - domain::PayLaterData::KlarnaRedirect {} => { - item.router_data.get_billing_email()? - } - domain::PayLaterData::KlarnaSdk { token: _ } - | domain::PayLaterData::AffirmRedirect {} - | domain::PayLaterData::AfterpayClearpayRedirect {} - | domain::PayLaterData::PayBrightRedirect {} - | domain::PayLaterData::WalleyRedirect {} - | domain::PayLaterData::AlmaRedirect {} - | domain::PayLaterData::AtomeRedirect {} => { + PayLaterData::KlarnaRedirect {} => item.router_data.get_billing_email()?, + PayLaterData::KlarnaSdk { token: _ } + | PayLaterData::AffirmRedirect {} + | PayLaterData::AfterpayClearpayRedirect {} + | PayLaterData::PayBrightRedirect {} + | PayLaterData::WalleyRedirect {} + | PayLaterData::AlmaRedirect {} + | PayLaterData::AtomeRedirect {} => { Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message( "multisafepay", @@ -752,50 +760,48 @@ impl TryFrom<&MultisafepayRouterData<&types::PaymentsAuthorizeRouterData>> }), })) } - domain::PaymentMethodData::BankRedirect(ref bank_redirect_data) => { - match bank_redirect_data { - domain::BankRedirectData::Ideal { bank_name, .. } => Some( - GatewayInfo::BankRedirect(BankRedirectInfo::Ideal(IdealInfo { - issuer_id: MultisafepayBankNames::try_from(&bank_name.ok_or( - errors::ConnectorError::MissingRequiredField { - field_name: "ideal.bank_name", - }, - )?)?, - })), - ), - domain::BankRedirectData::BancontactCard { .. } - | domain::BankRedirectData::Bizum { .. } - | domain::BankRedirectData::Blik { .. } - | domain::BankRedirectData::Eps { .. } - | domain::BankRedirectData::Giropay { .. } - | domain::BankRedirectData::Interac { .. } - | domain::BankRedirectData::OnlineBankingCzechRepublic { .. } - | domain::BankRedirectData::OnlineBankingFinland { .. } - | domain::BankRedirectData::OnlineBankingPoland { .. } - | domain::BankRedirectData::OnlineBankingSlovakia { .. } - | domain::BankRedirectData::OpenBankingUk { .. } - | domain::BankRedirectData::Przelewy24 { .. } - | domain::BankRedirectData::Sofort { .. } - | domain::BankRedirectData::Trustly { .. } - | domain::BankRedirectData::OnlineBankingFpx { .. } - | domain::BankRedirectData::OnlineBankingThailand { .. } - | domain::BankRedirectData::LocalBankRedirect {} => None, - } - } - domain::PaymentMethodData::MandatePayment => None, - domain::PaymentMethodData::CardRedirect(_) - | domain::PaymentMethodData::BankDebit(_) - | domain::PaymentMethodData::BankTransfer(_) - | domain::PaymentMethodData::Crypto(_) - | domain::PaymentMethodData::Reward - | domain::PaymentMethodData::RealTimePayment(_) - | domain::PaymentMethodData::Upi(_) - | domain::PaymentMethodData::Voucher(_) - | domain::PaymentMethodData::GiftCard(_) - | domain::PaymentMethodData::CardToken(_) - | domain::PaymentMethodData::OpenBanking(_) - | domain::PaymentMethodData::NetworkToken(_) - | domain::PaymentMethodData::CardDetailsForNetworkTransactionId(_) => { + PaymentMethodData::BankRedirect(ref bank_redirect_data) => match bank_redirect_data { + BankRedirectData::Ideal { bank_name, .. } => Some(GatewayInfo::BankRedirect( + BankRedirectInfo::Ideal(IdealInfo { + issuer_id: MultisafepayBankNames::try_from(&bank_name.ok_or( + errors::ConnectorError::MissingRequiredField { + field_name: "ideal.bank_name", + }, + )?)?, + }), + )), + BankRedirectData::BancontactCard { .. } + | BankRedirectData::Bizum { .. } + | BankRedirectData::Blik { .. } + | BankRedirectData::Eps { .. } + | BankRedirectData::Giropay { .. } + | BankRedirectData::Interac { .. } + | BankRedirectData::OnlineBankingCzechRepublic { .. } + | BankRedirectData::OnlineBankingFinland { .. } + | BankRedirectData::OnlineBankingPoland { .. } + | BankRedirectData::OnlineBankingSlovakia { .. } + | BankRedirectData::OpenBankingUk { .. } + | BankRedirectData::Przelewy24 { .. } + | BankRedirectData::Sofort { .. } + | BankRedirectData::Trustly { .. } + | BankRedirectData::OnlineBankingFpx { .. } + | BankRedirectData::OnlineBankingThailand { .. } + | BankRedirectData::LocalBankRedirect {} => None, + }, + PaymentMethodData::MandatePayment => None, + PaymentMethodData::CardRedirect(_) + | PaymentMethodData::BankDebit(_) + | PaymentMethodData::BankTransfer(_) + | PaymentMethodData::Crypto(_) + | PaymentMethodData::Reward + | PaymentMethodData::RealTimePayment(_) + | PaymentMethodData::Upi(_) + | PaymentMethodData::Voucher(_) + | PaymentMethodData::GiftCard(_) + | PaymentMethodData::CardToken(_) + | PaymentMethodData::OpenBanking(_) + | PaymentMethodData::NetworkToken(_) + | PaymentMethodData::CardDetailsForNetworkTransactionId(_) => { Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("multisafepay"), ))? @@ -830,7 +836,9 @@ impl TryFrom<&MultisafepayRouterData<&types::PaymentsAuthorizeRouterData>> .and_then(|mandate_ids| match mandate_ids.mandate_reference_id { Some(api_models::payments::MandateReferenceId::ConnectorMandateId( connector_mandate_ids, - )) => connector_mandate_ids.connector_mandate_id.map(Secret::new), + )) => connector_mandate_ids + .get_connector_mandate_id() + .map(Secret::new), _ => None, }), days_active: Some(30), @@ -847,10 +855,10 @@ pub struct MultisafepayAuthType { pub(super) api_key: Secret, } -impl TryFrom<&types::ConnectorAuthType> for MultisafepayAuthType { +impl TryFrom<&ConnectorAuthType> for MultisafepayAuthType { 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(), }) @@ -930,21 +938,15 @@ pub struct MultisafepayPaymentsResponse { #[serde(untagged)] pub enum MultisafepayAuthResponse { ErrorResponse(MultisafepayErrorResponse), - PaymentResponse(MultisafepayPaymentsResponse), + PaymentResponse(Box), } -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< - F, - MultisafepayAuthResponse, - T, - types::PaymentsResponseData, - >, + item: ResponseRouterData, ) -> Result { match item.response { MultisafepayAuthResponse::PaymentResponse(payment_response) => { @@ -952,7 +954,7 @@ impl .data .payment_url .clone() - .map(|url| services::RedirectForm::from((url, services::Method::Get))); + .map(|url| RedirectForm::from((url, Method::Get))); let default_status = if payment_response.success { MultisafepayPaymentStatus::Initialized @@ -966,29 +968,32 @@ impl Ok(Self { status, response: if utils::is_payment_failure(status) { - Err(types::ErrorResponse::foreign_from(( + Err(populate_error_reason( payment_response.data.reason_code, payment_response.data.reason.clone(), payment_response.data.reason, item.http_code, Some(status), Some(payment_response.data.order_id), - ))) + )) } else { - Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId( + Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId( payment_response.data.order_id.clone(), ), - redirection_data, - mandate_reference: payment_response - .data - .payment_details - .and_then(|payment_details| payment_details.recurring_id) - .map(|id| types::MandateReference { - connector_mandate_id: Some(id.expose()), - payment_method_id: None, - mandate_metadata: None, - }), + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new( + payment_response + .data + .payment_details + .and_then(|payment_details| payment_details.recurring_id) + .map(|id| MandateReference { + connector_mandate_id: Some(id.expose()), + payment_method_id: None, + mandate_metadata: None, + connector_mandate_request_reference_id: None, + }), + ), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some( @@ -1004,26 +1009,42 @@ impl MultisafepayAuthResponse::ErrorResponse(error_response) => { let attempt_status = Option::::from(error_response.clone()); Ok(Self { - response: Err(types::ErrorResponse::foreign_from(( + response: Err(populate_error_reason( Some(error_response.error_code.to_string()), Some(error_response.error_info.clone()), Some(error_response.error_info), item.http_code, attempt_status, None, - ))), + )), ..item.data }) } } } } - +pub fn populate_error_reason( + code: Option, + message: Option, + reason: Option, + http_code: u16, + attempt_status: Option, + connector_transaction_id: Option, +) -> ErrorResponse { + ErrorResponse { + code: code.unwrap_or(NO_ERROR_CODE.to_string()), + message: message.clone().unwrap_or(NO_ERROR_MESSAGE.to_string()), + reason, + status_code: http_code, + attempt_status, + connector_transaction_id, + } +} // REFUND : // Type definition for RefundRequest #[derive(Debug, Serialize)] pub struct MultisafepayRefundRequest { - pub currency: diesel_models::enums::Currency, + pub currency: enums::Currency, pub amount: MinorUnit, pub description: Option, pub refund_order_id: Option, @@ -1089,12 +1110,12 @@ pub enum MultisafepayRefundResponse { RefundResponse(RefundResponse), } -impl TryFrom> - for types::RefundsRouterData +impl TryFrom> + for types::RefundsRouterData { - type Error = error_stack::Report; + type Error = error_stack::Report; fn try_from( - item: types::RefundsResponseRouterData, + item: RefundsResponseRouterData, ) -> Result { match item.response { MultisafepayRefundResponse::RefundResponse(refund_data) => { @@ -1105,7 +1126,7 @@ impl TryFrom { let attempt_status = Option::::from(error_response.clone()); Ok(Self { - response: Err(types::ErrorResponse { + response: Err(ErrorResponse { code: error_response.error_code.to_string(), message: error_response.error_info.clone(), reason: Some(error_response.error_info), @@ -1130,12 +1151,12 @@ impl TryFrom> - for types::RefundsRouterData +impl TryFrom> + for types::RefundsRouterData { - type Error = error_stack::Report; + type Error = error_stack::Report; fn try_from( - item: types::RefundsResponseRouterData, + item: RefundsResponseRouterData, ) -> Result { match item.response { MultisafepayRefundResponse::RefundResponse(refund_data) => { @@ -1146,7 +1167,7 @@ impl TryFrom Ok(Self { - response: Err(types::ErrorResponse::foreign_from(( + response: Err(populate_error_reason( Some(error_response.error_code.to_string()), Some(error_response.error_info.clone()), Some(error_response.error_info), item.http_code, None, None, - ))), + )), ..item.data }), } diff --git a/crates/router/src/connector/nexinets.rs b/crates/hyperswitch_connectors/src/connectors/nexinets.rs similarity index 64% rename from crates/router/src/connector/nexinets.rs rename to crates/hyperswitch_connectors/src/connectors/nexinets.rs index 113b2924fec3..94b24bbe867b 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)] @@ -47,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) } } @@ -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 66% rename from crates/router/src/connector/nexinets/transformers.rs rename to crates/hyperswitch_connectors/src/connectors/nexinets/transformers.rs index 6cf35f5d87df..4149f740e76d 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,20 +356,18 @@ 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, + connector_mandate_request_reference_id: 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, + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(mandate_reference), connector_metadata: Some(connector_metadata), network_txn_id: None, connector_response_reference_id: Some(item.response.order_id), @@ -393,9 +392,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 +402,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 +422,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,19 +438,16 @@ 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, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: Some(connector_metadata), network_txn_id: None, connector_response_reference_id: Some(item.response.order.order_id), @@ -473,9 +468,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 +516,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 +533,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 +566,7 @@ pub struct OrderErrorDetails { } fn get_payment_details_and_product( - item: &types::PaymentsAuthorizeRouterData, + item: &PaymentsAuthorizeRouterData, ) -> Result< (Option, NexinetsProduct), error_stack::Report, @@ -583,9 +578,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 +590,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 +633,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 +661,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 +676,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 +686,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 +702,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/hyperswitch_connectors/src/connectors/nexixpay/transformers.rs b/crates/hyperswitch_connectors/src/connectors/nexixpay/transformers.rs index 1677343fe38a..d593864dbfce 100644 --- a/crates/hyperswitch_connectors/src/connectors/nexixpay/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/nexixpay/transformers.rs @@ -353,8 +353,8 @@ impl resource_id: ResponseId::ConnectorTransactionId( item.response.operation.order_id.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata, network_txn_id: None, connector_response_reference_id: Some(item.response.operation.order_id), @@ -626,8 +626,8 @@ impl resource_id: ResponseId::ConnectorTransactionId( item.response.operation.order_id.clone(), ), - redirection_data: Some(redirection_form.clone()), - mandate_reference: None, + redirection_data: Box::new(Some(redirection_form.clone())), + mandate_reference: Box::new(None), connector_metadata, network_txn_id: None, connector_response_reference_id: Some(item.response.operation.order_id), @@ -744,8 +744,8 @@ impl resource_id: ResponseId::ConnectorTransactionId( item.response.operation.order_id.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata, network_txn_id: None, connector_response_reference_id: Some(item.response.operation.order_id), @@ -867,8 +867,8 @@ impl status: AttemptStatus::from(item.response.operation_result), response: Ok(PaymentsResponseData::TransactionResponse { resource_id: ResponseId::ConnectorTransactionId(item.response.order_id.clone()), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: item.data.request.connector_meta.clone(), network_txn_id: None, connector_response_reference_id: Some(item.response.order_id.clone()), @@ -923,8 +923,8 @@ impl resource_id: ResponseId::ConnectorTransactionId( item.data.request.connector_transaction_id.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata, network_txn_id: None, connector_response_reference_id: Some( @@ -986,8 +986,8 @@ impl resource_id: ResponseId::ConnectorTransactionId( item.data.request.connector_transaction_id.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata, network_txn_id: None, connector_response_reference_id: Some( diff --git a/crates/hyperswitch_connectors/src/connectors/novalnet.rs b/crates/hyperswitch_connectors/src/connectors/novalnet.rs index 36fe04fdab10..7450a48884a7 100644 --- a/crates/hyperswitch_connectors/src/connectors/novalnet.rs +++ b/crates/hyperswitch_connectors/src/connectors/novalnet.rs @@ -195,8 +195,12 @@ impl ConnectorValidation for Novalnet { pm_type: Option, pm_data: PaymentMethodData, ) -> CustomResult<(), errors::ConnectorError> { - let mandate_supported_pmd: HashSet = - HashSet::from([PaymentMethodDataType::Card]); + let mandate_supported_pmd: HashSet = HashSet::from([ + PaymentMethodDataType::Card, + PaymentMethodDataType::GooglePay, + PaymentMethodDataType::PaypalRedirect, + PaymentMethodDataType::ApplePay, + ]); utils::is_mandate_supported(pm_data, pm_type, mandate_supported_pmd, self.id()) } } diff --git a/crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs b/crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs index 3c635f88cd4b..26364d73f4ff 100644 --- a/crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs @@ -12,7 +12,7 @@ use common_utils::{ }; use error_stack::ResultExt; use hyperswitch_domain_models::{ - payment_method_data::PaymentMethodData, + payment_method_data::{PaymentMethodData, WalletData as WalletDataPaymentMethod}, router_data::{ConnectorAuthType, ErrorResponse, RouterData}, router_flow_types::refunds::{Execute, RSync}, router_request_types::{PaymentsCancelData, PaymentsCaptureData, PaymentsSyncData, ResponseId}, @@ -33,8 +33,7 @@ use crate::{ types::{RefundsResponseRouterData, ResponseRouterData}, utils::{ self, BrowserInformationData, PaymentsAuthorizeRequestData, PaymentsCancelRequestData, - PaymentsCaptureRequestData, PaymentsSyncRequestData, RefundsRequestData, - RouterData as OtherRouterData, + PaymentsCaptureRequestData, PaymentsSyncRequestData, RefundsRequestData, RouterData as _, }, }; @@ -55,6 +54,9 @@ impl From<(StringMinorUnit, T)> for NovalnetRouterData { #[derive(Debug, Copy, Serialize, Deserialize, Clone)] pub enum NovalNetPaymentTypes { CREDITCARD, + PAYPAL, + GOOGLEPAY, + APPLEPAY, } #[derive(Default, Debug, Serialize, Clone)] @@ -96,10 +98,22 @@ pub struct NovalnetMandate { token: Secret, } +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +pub struct NovalnetGooglePay { + wallet_data: Secret, +} + +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +pub struct NovalnetApplePay { + wallet_data: Secret, +} + #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(untagged)] pub enum NovalNetPaymentData { - PaymentCard(NovalnetCard), + Card(NovalnetCard), + GooglePay(NovalnetGooglePay), + ApplePay(NovalnetApplePay), MandatePayment(NovalnetMandate), } @@ -115,7 +129,7 @@ pub struct NovalnetPaymentsRequestTransaction { amount: StringMinorUnit, currency: common_enums::Currency, order_no: String, - payment_data: NovalNetPaymentData, + payment_data: Option, hook_url: Option, return_url: Option, error_return_url: Option, @@ -131,6 +145,21 @@ pub struct NovalnetPaymentsRequest { custom: NovalnetCustom, } +impl TryFrom<&api_enums::PaymentMethodType> for NovalNetPaymentTypes { + type Error = error_stack::Report; + fn try_from(item: &api_enums::PaymentMethodType) -> Result { + match item { + api_enums::PaymentMethodType::ApplePay => Ok(Self::APPLEPAY), + api_enums::PaymentMethodType::Credit => Ok(Self::CREDITCARD), + api_enums::PaymentMethodType::GooglePay => Ok(Self::GOOGLEPAY), + api_enums::PaymentMethodType::Paypal => Ok(Self::PAYPAL), + _ => Err(errors::ConnectorError::NotImplemented( + utils::get_unimplemented_payment_method_error_message("Novalnet"), + ))?, + } + } +} + impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaymentsRequest { type Error = error_stack::Report; fn try_from( @@ -182,6 +211,12 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym .unwrap_or(consts::DEFAULT_LOCALE.to_string().to_string()); let custom = NovalnetCustom { lang }; let hook_url = item.router_data.request.get_webhook_url()?; + let return_url = item.router_data.request.get_return_url()?; + let create_token = if item.router_data.request.is_mandate_payment() { + Some(1) + } else { + None + }; match item .router_data @@ -192,19 +227,13 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym { None => match item.router_data.request.payment_method_data { PaymentMethodData::Card(ref req_card) => { - let novalnet_card = NovalNetPaymentData::PaymentCard(NovalnetCard { + let novalnet_card = NovalNetPaymentData::Card(NovalnetCard { card_number: req_card.card_number.clone(), card_expiry_month: req_card.card_exp_month.clone(), card_expiry_year: req_card.card_exp_year.clone(), card_cvc: req_card.card_cvc.clone(), card_holder: item.router_data.get_billing_full_name()?, }); - let create_token = if item.router_data.request.is_mandate_payment() { - Some(1) - } else { - None - }; - let return_url = item.router_data.request.get_return_url()?; let transaction = NovalnetPaymentsRequestTransaction { test_mode, @@ -215,7 +244,7 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym hook_url: Some(hook_url), return_url: Some(return_url.clone()), error_return_url: Some(return_url.clone()), - payment_data: novalnet_card, + payment_data: Some(novalnet_card), enforce_3d, create_token, }; @@ -227,13 +256,125 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym custom, }) } + + PaymentMethodData::Wallet(ref wallet_data) => match wallet_data { + WalletDataPaymentMethod::GooglePay(ref req_wallet) => { + let novalnet_google_pay: NovalNetPaymentData = + NovalNetPaymentData::GooglePay(NovalnetGooglePay { + wallet_data: Secret::new( + req_wallet.tokenization_data.token.clone(), + ), + }); + + let transaction = NovalnetPaymentsRequestTransaction { + test_mode, + payment_type: NovalNetPaymentTypes::GOOGLEPAY, + amount: item.amount.clone(), + currency: item.router_data.request.currency, + order_no: item.router_data.connector_request_reference_id.clone(), + hook_url: Some(hook_url), + return_url: None, + error_return_url: None, + payment_data: Some(novalnet_google_pay), + enforce_3d, + create_token, + }; + + Ok(Self { + merchant, + transaction, + customer, + custom, + }) + } + WalletDataPaymentMethod::ApplePay(payment_method_data) => { + let transaction = NovalnetPaymentsRequestTransaction { + test_mode, + payment_type: NovalNetPaymentTypes::APPLEPAY, + amount: item.amount.clone(), + currency: item.router_data.request.currency, + order_no: item.router_data.connector_request_reference_id.clone(), + hook_url: Some(hook_url), + return_url: None, + error_return_url: None, + payment_data: Some(NovalNetPaymentData::ApplePay(NovalnetApplePay { + wallet_data: Secret::new(payment_method_data.payment_data.clone()), + })), + enforce_3d: None, + create_token, + }; + + Ok(Self { + merchant, + transaction, + customer, + custom, + }) + } + WalletDataPaymentMethod::AliPayQr(_) + | WalletDataPaymentMethod::AliPayRedirect(_) + | WalletDataPaymentMethod::AliPayHkRedirect(_) + | WalletDataPaymentMethod::MomoRedirect(_) + | WalletDataPaymentMethod::KakaoPayRedirect(_) + | WalletDataPaymentMethod::GoPayRedirect(_) + | WalletDataPaymentMethod::GcashRedirect(_) + | WalletDataPaymentMethod::ApplePayRedirect(_) + | WalletDataPaymentMethod::ApplePayThirdPartySdk(_) + | WalletDataPaymentMethod::DanaRedirect {} + | WalletDataPaymentMethod::GooglePayRedirect(_) + | WalletDataPaymentMethod::GooglePayThirdPartySdk(_) + | WalletDataPaymentMethod::MbWayRedirect(_) + | WalletDataPaymentMethod::MobilePayRedirect(_) => { + Err(errors::ConnectorError::NotImplemented( + utils::get_unimplemented_payment_method_error_message("novalnet"), + ) + .into()) + } + WalletDataPaymentMethod::PaypalRedirect(_) => { + let transaction = NovalnetPaymentsRequestTransaction { + test_mode, + payment_type: NovalNetPaymentTypes::PAYPAL, + amount: item.amount.clone(), + currency: item.router_data.request.currency, + order_no: item.router_data.connector_request_reference_id.clone(), + hook_url: Some(hook_url), + return_url: Some(return_url.clone()), + error_return_url: Some(return_url.clone()), + payment_data: None, + enforce_3d: None, + create_token, + }; + Ok(Self { + merchant, + transaction, + customer, + custom, + }) + } + WalletDataPaymentMethod::PaypalSdk(_) + | WalletDataPaymentMethod::Paze(_) + | WalletDataPaymentMethod::SamsungPay(_) + | WalletDataPaymentMethod::TwintRedirect {} + | WalletDataPaymentMethod::VippsRedirect {} + | WalletDataPaymentMethod::TouchNGoRedirect(_) + | WalletDataPaymentMethod::WeChatPayRedirect(_) + | WalletDataPaymentMethod::CashappQr(_) + | WalletDataPaymentMethod::SwishQr(_) + | WalletDataPaymentMethod::WeChatPayQr(_) + | WalletDataPaymentMethod::Mifinity(_) => { + Err(errors::ConnectorError::NotImplemented( + utils::get_unimplemented_payment_method_error_message("novalnet"), + ) + .into()) + } + }, _ => Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("novalnet"), ) .into()), }, Some(api_models::payments::MandateReferenceId::ConnectorMandateId(mandate_data)) => { - let connector_mandate_id = mandate_data.connector_mandate_id.ok_or( + let connector_mandate_id = mandate_data.get_connector_mandate_id().ok_or( errors::ConnectorError::MissingRequiredField { field_name: "connector_mandate_id", }, @@ -243,16 +384,21 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym token: Secret::new(connector_mandate_id), }); + let payment_type = match item.router_data.request.payment_method_type { + Some(pm_type) => NovalNetPaymentTypes::try_from(&pm_type)?, + None => NovalNetPaymentTypes::CREDITCARD, + }; + let transaction = NovalnetPaymentsRequestTransaction { test_mode, - payment_type: NovalNetPaymentTypes::CREDITCARD, + payment_type, amount: item.amount.clone(), currency: item.router_data.request.currency, order_no: item.router_data.connector_request_reference_id.clone(), hook_url: Some(hook_url), return_url: None, error_return_url: None, - payment_data: novalnet_mandate_data, + payment_data: Some(novalnet_mandate_data), enforce_3d, create_token: None, }; @@ -378,6 +524,24 @@ pub fn get_error_response(result: ResultData, status_code: u16) -> ErrorResponse } } +impl NovalnetPaymentsResponseTransactionData { + pub fn get_token(transaction_data: Option<&Self>) -> Option { + if let Some(data) = transaction_data { + match &data.payment_data { + Some(NovalnetResponsePaymentData::Card(card_data)) => { + card_data.token.clone().map(|token| token.expose()) + } + Some(NovalnetResponsePaymentData::Paypal(paypal_data)) => { + paypal_data.token.clone().map(|token| token.expose()) + } + None => None, + } + } else { + None + } + } +} + impl TryFrom> for RouterData { @@ -402,18 +566,23 @@ impl TryFrom TryFrom, pub cc_3d: Option>, pub last_four: Option>, - pub token: Option, + pub token: Option>, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct NovalnetResponsePaypal { + pub paypal_account: Option, + pub paypal_transaction_id: Option>, + pub token: Option>, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -760,11 +944,15 @@ impl TryFrom<&PaymentsSyncRouterData> for NovalnetSyncRequest { impl NovalnetSyncResponseTransactionData { pub fn get_token(transaction_data: Option<&Self>) -> Option { - if let Some(payment_data) = - transaction_data.and_then(|transaction_data| transaction_data.payment_data.clone()) - { - match &payment_data { - NovalnetResponsePaymentData::PaymentCard(card_data) => card_data.token.clone(), + if let Some(data) = transaction_data { + match &data.payment_data { + Some(NovalnetResponsePaymentData::Card(card_data)) => { + card_data.token.clone().map(|token| token.expose()) + } + Some(NovalnetResponsePaymentData::Paypal(paypal_data)) => { + paypal_data.token.clone().map(|token| token.expose()) + } + None => None, } } else { None @@ -805,14 +993,15 @@ impl .clone() .map(ResponseId::ConnectorTransactionId) .unwrap_or(ResponseId::NoResponseId), - redirection_data: None, - mandate_reference: mandate_reference_id.as_ref().map(|id| { + redirection_data: Box::new(None), + mandate_reference: Box::new(mandate_reference_id.as_ref().map(|id| { MandateReference { connector_mandate_id: Some(id.clone()), payment_method_id: None, mandate_metadata: None, + connector_mandate_request_reference_id: None, } - }), + })), connector_metadata: None, network_txn_id: None, connector_response_reference_id: transaction_id.clone(), @@ -895,8 +1084,8 @@ impl .clone() .map(ResponseId::ConnectorTransactionId) .unwrap_or(ResponseId::NoResponseId), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: transaction_id.clone(), @@ -1064,8 +1253,8 @@ impl .clone() .map(ResponseId::ConnectorTransactionId) .unwrap_or(ResponseId::NoResponseId), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: transaction_id.clone(), 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 5783cf1bc14f..cb22d0cb7b03 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 685bf3c0fbb0..707e34a158c5 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,16 +178,14 @@ 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( connector_mandate_ids, - )) => connector_mandate_ids.connector_mandate_id, + )) => connector_mandate_ids.get_connector_mandate_id(), _ => None, } }); @@ -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,43 +398,43 @@ 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, + connector_mandate_request_reference_id: 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, - mandate_reference, + redirection_data: Box::new(None), + mandate_reference: Box::new(mandate_reference), connector_metadata: metadata, network_txn_id: None, connector_response_reference_id: Some( @@ -449,26 +450,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 +485,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 +539,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 60% rename from crates/router/src/connector/payu.rs rename to crates/hyperswitch_connectors/src/connectors/payu.rs index 4ff317d1f713..ad2479f19e4c 100644 --- a/crates/router/src/connector/payu.rs +++ b/crates/hyperswitch_connectors/src/connectors/payu.rs @@ -1,34 +1,65 @@ 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}, + types::{AmountConvertor, MinorUnit, MinorUnitForConnector}, +}; 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::{ + 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}, - ErrorResponse, + PaymentsAuthorizeType, PaymentsCaptureType, PaymentsSyncType, PaymentsVoidType, + RefreshTokenType, RefundExecuteType, RefundSyncType, Response, }, - utils::BytesExt, + webhooks::{IncomingWebhook, IncomingWebhookRequestDetails}, }; +use masking::{Mask, PeekInterface}; +use transformers as payu; -#[derive(Debug, Clone)] -pub struct Payu; +use crate::{ + constants::headers, + types::{RefreshTokenRouterData, ResponseRouterData}, + utils, + utils::construct_not_supported_error_report, +}; + +#[derive(Clone)] +pub struct Payu { + amount_converter: &'static (dyn AmountConvertor + Sync), +} + +impl Payu { + pub fn new() -> &'static Self { + &Self { + amount_converter: &MinorUnitForConnector, + } + } +} impl ConnectorCommonExt for Payu where @@ -36,9 +67,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 +98,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 +116,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 +148,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 +157,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 +172,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 +195,8 @@ impl ConnectorIntegration CustomResult { let connector_payment_id = &req.request.connector_transaction_id; Ok(format!( @@ -193,23 +208,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 +233,7 @@ impl ConnectorIntegration, ) -> CustomResult { self.build_error_response(res, event_builder) @@ -236,13 +251,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 +270,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 +291,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 +308,10 @@ impl ConnectorIntegration, - res: types::Response, - ) -> CustomResult { + res: Response, + ) -> CustomResult { let response: payu::PayuAuthUpdateResponse = res .response .parse_struct("payu PayuAuthUpdateResponse") @@ -311,7 +320,7 @@ impl ConnectorIntegration, ) -> CustomResult { let response: payu::PayuAccessTokenErrorResponse = res @@ -344,14 +353,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 +368,8 @@ impl ConnectorIntegration CustomResult { let connector_payment_id = req .request @@ -379,32 +386,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 +421,7 @@ impl ConnectorIntegration, ) -> CustomResult { self.build_error_response(res, event_builder) @@ -422,14 +429,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 +444,8 @@ impl ConnectorIntegration CustomResult { Ok(format!( "{}{}{}{}", @@ -453,8 +458,8 @@ impl ConnectorIntegration CustomResult { let connector_req = payu::PayuPaymentsCaptureRequest::try_from(req)?; Ok(RequestContent::Json(Box::new(connector_req))) @@ -462,18 +467,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 +485,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 +505,7 @@ impl ConnectorIntegration, ) -> CustomResult { self.build_error_response(res, event_builder) @@ -511,22 +514,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 +535,8 @@ impl ConnectorIntegration CustomResult { Ok(format!( "{}{}", @@ -548,33 +547,33 @@ impl ConnectorIntegration CustomResult { - let connector_req = payu::PayuPaymentsRequest::try_from(req)?; + let amount = utils::convert_amount( + self.amount_converter, + req.request.minor_amount, + req.request.currency, + )?; + + let connector_router_data = payu::PayuRouterData::try_from((amount, req))?; + + let connector_req = payu::PayuPaymentsRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } fn build_request( &self, - req: &types::RouterData< - api::Authorize, - types::PaymentsAuthorizeData, - types::PaymentsResponseData, - >, - 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 +582,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 +602,7 @@ impl ConnectorIntegration, ) -> CustomResult { self.build_error_response(res, event_builder) @@ -614,12 +613,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 +628,8 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, + req: &RefundsRouterData, + connectors: &Connectors, ) -> CustomResult { Ok(format!( "{}{}{}{}", @@ -643,45 +642,48 @@ impl ConnectorIntegration, - _connectors: &settings::Connectors, + req: &RefundsRouterData, + _connectors: &Connectors, ) -> CustomResult { - let connector_req = payu::PayuRefundRequest::try_from(req)?; + let amount = utils::convert_amount( + self.amount_converter, + req.request.minor_refund_amount, + req.request.currency, + )?; + + let connector_router_data = payu::PayuRouterData::try_from((amount, req))?; + let connector_req = payu::PayuRefundRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } fn build_request( &self, - req: &types::RefundsRouterData, - 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 +693,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 +715,8 @@ impl ConnectorIntegration CustomResult { Ok(format!( "{}{}{}{}", @@ -727,32 +729,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 +764,7 @@ impl ConnectorIntegration, ) -> CustomResult { self.build_error_response(res, event_builder) @@ -770,24 +772,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 75% rename from crates/router/src/connector/payu/transformers.rs rename to crates/hyperswitch_connectors/src/connectors/payu/transformers.rs index 5365fc74ef2e..9bdb52de4f0d 100644 --- a/crates/router/src/connector/payu/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/payu/transformers.rs @@ -1,28 +1,57 @@ use base64::Engine; -use common_utils::pii::{Email, IpAddress}; +use common_enums::enums; +use common_utils::{ + consts::BASE64_ENGINE, + pii::{Email, IpAddress}, + types::MinorUnit, +}; 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"; -#[derive(Debug, Serialize, Eq, PartialEq)] +#[derive(Debug, Serialize)] +pub struct PayuRouterData { + pub amount: MinorUnit, + pub router_data: T, +} + +impl TryFrom<(MinorUnit, T)> for PayuRouterData { + type Error = error_stack::Report; + fn try_from((amount, item): (MinorUnit, T)) -> Result { + Ok(Self { + amount, + router_data: item, + }) + } +} + +#[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct PayuPaymentsRequest { customer_ip: Secret, merchant_pos_id: Secret, - total_amount: i64, + total_amount: MinorUnit, currency_code: enums::Currency, description: String, pay_methods: PayuPaymentMethod, continue_url: Option, + ext_order_id: Option, } #[derive(Debug, Eq, PartialEq, Serialize)] @@ -65,12 +94,14 @@ pub enum PayuWalletCode { Jp, } -impl TryFrom<&types::PaymentsAuthorizeRouterData> for PayuPaymentsRequest { +impl TryFrom<&PayuRouterData<&types::PaymentsAuthorizeRouterData>> for PayuPaymentsRequest { type Error = error_stack::Report; - 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 { + fn try_from( + item: &PayuRouterData<&types::PaymentsAuthorizeRouterData>, + ) -> Result { + let auth_type = PayuAuthType::try_from(&item.router_data.connector_auth_type)?; + let payment_method = match item.router_data.request.payment_method_data.clone() { + PaymentMethodData::Card(ccard) => Ok(PayuPaymentMethod { pay_method: PayuPaymentMethodData::Card(PayuCard::Card { number: ccard.card_number, expiration_month: ccard.card_exp_month, @@ -78,19 +109,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, @@ -107,7 +138,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PayuPaymentsRequest { "Unknown payment method".to_string(), )), }?; - let browser_info = item.request.browser_info.clone().ok_or( + let browser_info = item.router_data.request.browser_info.clone().ok_or( errors::ConnectorError::MissingRequiredField { field_name: "browser_info", }, @@ -122,9 +153,10 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PayuPaymentsRequest { .to_string(), ), merchant_pos_id: auth_type.merchant_pos_id, - total_amount: item.request.amount, - currency_code: item.request.currency, - description: item.description.clone().ok_or( + ext_order_id: Some(item.router_data.connector_request_reference_id.clone()), + total_amount: item.amount.to_owned(), + currency_code: item.router_data.request.currency, + description: item.router_data.description.clone().ok_or( errors::ConnectorError::MissingRequiredField { field_name: "item.description", }, @@ -140,11 +172,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,22 +220,19 @@ 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(), - ), - redirection_data: None, - mandate_reference: None, + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(item.response.order_id.clone()), + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: item @@ -241,26 +270,19 @@ 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, - redirection_data: None, - mandate_reference: None, + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::NoResponseId, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -298,15 +320,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,28 +345,19 @@ 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(), - ), - redirection_data: None, - mandate_reference: None, + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(item.response.order_id.clone()), + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: item @@ -457,18 +470,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,10 +483,10 @@ impl }; Ok(Self { status: enums::AttemptStatus::from(order.status.clone()), - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId(order.order_id.clone()), - redirection_data: None, - mandate_reference: None, + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(order.order_id.clone()), + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: order @@ -500,10 +507,10 @@ impl } } -#[derive(Default, Debug, Eq, PartialEq, Serialize)] +#[derive(Default, Debug, Serialize)] pub struct PayuRefundRequestData { description: String, - amount: Option, + amount: Option, } #[derive(Default, Debug, Serialize)] @@ -511,12 +518,12 @@ pub struct PayuRefundRequest { refund: PayuRefundRequestData, } -impl TryFrom<&types::RefundsRouterData> for PayuRefundRequest { +impl TryFrom<&PayuRouterData<&types::RefundsRouterData>> for PayuRefundRequest { type Error = error_stack::Report; - fn try_from(item: &types::RefundsRouterData) -> Result { + fn try_from(item: &PayuRouterData<&types::RefundsRouterData>) -> Result { Ok(Self { refund: PayuRefundRequestData { - description: item.request.reason.clone().ok_or( + description: item.router_data.request.reason.clone().ok_or( errors::ConnectorError::MissingRequiredField { field_name: "item.request.reason", }, @@ -569,16 +576,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 +598,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/hyperswitch_connectors/src/connectors/powertranz/transformers.rs b/crates/hyperswitch_connectors/src/connectors/powertranz/transformers.rs index 770688a34682..93ba34259788 100644 --- a/crates/hyperswitch_connectors/src/connectors/powertranz/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/powertranz/transformers.rs @@ -336,8 +336,8 @@ impl TryFrom for Razorpay +impl ConnectorIntegration + for Razorpay { // Not Implemented (R) } @@ -70,9 +83,9 @@ where { fn build_headers( &self, - _req: &types::RouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + _req: &RouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { let header = vec![ ( headers::CONTENT_TYPE.to_string(), @@ -100,7 +113,7 @@ impl ConnectorCommon for Razorpay { "application/json" } - fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { + fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str { connectors.razorpay.base_url.as_ref() } @@ -144,7 +157,7 @@ impl ConnectorCommon for Razorpay { razorpay::ErrorResponse::RazorpayStringError(error_string) => { Ok(ErrorResponse { status_code: res.status_code, - code: consts::NO_ERROR_CODE.to_string(), + code: NO_ERROR_CODE.to_string(), message: error_string.clone(), reason: Some(error_string.clone()), attempt_status: None, @@ -156,7 +169,7 @@ impl ConnectorCommon for Razorpay { Err(error_msg) => { event_builder.map(|event| event.set_error(serde_json::json!({"error": res.response.escape_ascii().to_string(), "status_code": res.status_code}))); logger::error!(deserialization_error =? error_msg); - crate::utils::handle_json_response_deserialization_failure(res, "razorpay") + handle_json_response_deserialization_failure(res, "razorpay") } } } @@ -166,34 +179,23 @@ impl ConnectorValidation for Razorpay { //TODO: implement functions when support enabled } -impl ConnectorIntegration - for Razorpay -{ +impl ConnectorIntegration for Razorpay { //TODO: implement sessions flow } -impl ConnectorIntegration - for Razorpay -{ -} +impl ConnectorIntegration for Razorpay {} -impl - ConnectorIntegration< - api::SetupMandate, - types::SetupMandateRequestData, - types::PaymentsResponseData, - > for Razorpay +impl ConnectorIntegration + for Razorpay { } -impl ConnectorIntegration - for Razorpay -{ +impl ConnectorIntegration for Razorpay { 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) } @@ -203,8 +205,8 @@ impl ConnectorIntegration CustomResult { Ok(format!( "{}gatewayProxy/txn/sendCollect", @@ -214,10 +216,10 @@ impl ConnectorIntegration CustomResult { - let amount = connector_utils::convert_amount( + let amount = convert_amount( self.amount_converter, req.request.minor_amount, req.request.currency, @@ -230,12 +232,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, )?) @@ -252,17 +254,17 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: razorpay::RazorpayPaymentsResponse = res .response .parse_struct("Razorpay 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, @@ -278,14 +280,12 @@ impl ConnectorIntegration - for Razorpay -{ +impl ConnectorIntegration for Razorpay { 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) } @@ -295,8 +295,8 @@ impl ConnectorIntegration CustomResult { Ok(format!( "{}gatewayProxy/sync/transaction", @@ -306,10 +306,10 @@ impl ConnectorIntegration CustomResult { - let amount = connector_utils::convert_amount( + let amount = convert_amount( self.amount_converter, req.request.amount, req.request.currency, @@ -322,11 +322,11 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { - let request = services::RequestBuilder::new() - .method(services::Method::Post) + req: &PaymentsSyncRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + let request = RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsSyncType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::PaymentsSyncType::get_headers(self, req, connectors)?) @@ -339,17 +339,17 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: razorpay::RazorpaySyncResponse = res .response .parse_struct("razorpay 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, @@ -365,14 +365,12 @@ impl ConnectorIntegration - for Razorpay -{ +impl ConnectorIntegration for Razorpay { 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) } @@ -382,28 +380,28 @@ impl ConnectorIntegration CustomResult { Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) } fn get_request_body( &self, - _req: &types::PaymentsCaptureRouterData, - _connectors: &settings::Connectors, + _req: &PaymentsCaptureRouterData, + _connectors: &Connectors, ) -> CustomResult { Err(errors::ConnectorError::NotImplemented("get_request_body method".to_string()).into()) } fn build_request( &self, - req: &types::PaymentsCaptureRouterData, - connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::PaymentsCaptureType::get_headers( @@ -418,17 +416,17 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: razorpay::RazorpayPaymentsResponse = res .response .parse_struct("Razorpay PaymentsCaptureResponse") .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, @@ -444,19 +442,14 @@ impl ConnectorIntegration - for Razorpay -{ -} +impl ConnectorIntegration for Razorpay {} -impl ConnectorIntegration - for Razorpay -{ +impl ConnectorIntegration for Razorpay { 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) } @@ -466,18 +459,18 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, + _req: &RefundsRouterData, + connectors: &Connectors, ) -> CustomResult { Ok(format!("{}gatewayProxy/refund", self.base_url(connectors))) } fn get_request_body( &self, - req: &types::RefundsRouterData, - connectors: &settings::Connectors, + req: &RefundsRouterData, + connectors: &Connectors, ) -> CustomResult { - let amount = connector_utils::convert_amount( + let amount = convert_amount( self.amount_converter, req.request.minor_refund_amount, req.request.currency, @@ -490,11 +483,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( @@ -509,17 +502,17 @@ impl ConnectorIntegration, + data: &RefundsRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult, errors::ConnectorError> { + ) -> CustomResult, errors::ConnectorError> { let response: razorpay::RefundResponse = res .response .parse_struct("razorpay 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, @@ -535,12 +528,12 @@ impl ConnectorIntegration for Razorpay { +impl ConnectorIntegration for Razorpay { 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) } @@ -550,8 +543,8 @@ impl ConnectorIntegration CustomResult { Ok(format!( "{}gatewayProxy/sync/refund", @@ -561,10 +554,10 @@ impl ConnectorIntegration CustomResult { - let amount = connector_utils::convert_amount( + let amount = convert_amount( self.amount_converter, req.request.minor_refund_amount, req.request.currency, @@ -577,12 +570,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &RefundSyncRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::RefundSyncType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::RefundSyncType::get_headers(self, req, connectors)?) @@ -595,17 +588,17 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: razorpay::RefundResponse = res .response .parse_struct("razorpay RefundSyncResponse") .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, @@ -622,17 +615,17 @@ impl ConnectorIntegration, - ) -> CustomResult { + request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { let webhook_resource_object = get_webhook_object_from_body(request.body)?; match webhook_resource_object.refund { - Some(refund_data) => Ok(api_models::webhooks::ObjectReferenceId::RefundId( - api_models::webhooks::RefundIdType::ConnectorRefundId(refund_data.entity.id), + Some(refund_data) => Ok(webhooks::ObjectReferenceId::RefundId( + webhooks::RefundIdType::ConnectorRefundId(refund_data.entity.id), )), - None => Ok(api_models::webhooks::ObjectReferenceId::PaymentId( + None => Ok(webhooks::ObjectReferenceId::PaymentId( api_models::payments::PaymentIdType::ConnectorTransactionId( webhook_resource_object.payment.entity.id, ), @@ -642,7 +635,7 @@ impl api::IncomingWebhook for Razorpay { 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: common_utils::crypto::Encryptable< @@ -655,17 +648,15 @@ impl api::IncomingWebhook for Razorpay { fn get_webhook_event_type( &self, - request: &api::IncomingWebhookRequestDetails<'_>, - ) -> CustomResult { + request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { let webhook_resource_object = get_webhook_object_from_body(request.body)?; - Ok(api_models::webhooks::IncomingWebhookEvent::try_from( - webhook_resource_object, - )?) + Ok(IncomingWebhookEvent::try_from(webhook_resource_object)?) } fn get_webhook_resource_object( &self, - request: &api::IncomingWebhookRequestDetails<'_>, + request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { let webhook_resource_object = get_webhook_object_from_body(request.body)?; Ok(Box::new(webhook_resource_object)) diff --git a/crates/router/src/connector/razorpay/transformers.rs b/crates/hyperswitch_connectors/src/connectors/razorpay/transformers.rs similarity index 90% rename from crates/router/src/connector/razorpay/transformers.rs rename to crates/hyperswitch_connectors/src/connectors/razorpay/transformers.rs index fde72cac1004..674f652a9336 100644 --- a/crates/router/src/connector/razorpay/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/razorpay/transformers.rs @@ -1,20 +1,28 @@ +use common_enums::enums; use common_utils::{ pii::{self, Email}, types::FloatMajorUnit, }; use error_stack::ResultExt; -use hyperswitch_domain_models::payment_method_data::UpiCollectData; +use hyperswitch_domain_models::{ + payment_method_data::{PaymentMethodData, UpiCollectData, UpiData}, + router_data::{ConnectorAuthType, RouterData}, + router_flow_types::refunds::{Execute, RSync}, + router_request_types::ResponseId, + router_response_types::{PaymentsResponseData, RefundsResponseData}, + types, +}; +use hyperswitch_interfaces::{ + configs::Connectors, + consts::{NO_ERROR_CODE, NO_ERROR_MESSAGE}, + errors, +}; use masking::Secret; use rand::Rng; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; -use crate::{ - configs::settings, - consts, - core::errors, - types::{self, api, domain, storage::enums}, -}; +use crate::types::{RefundsResponseRouterData, ResponseRouterData}; pub struct RazorpayRouterData { pub amount: FloatMajorUnit, @@ -367,41 +375,42 @@ fn generate_12_digit_number() -> u64 { impl TryFrom<( &RazorpayRouterData<&types::PaymentsAuthorizeRouterData>, - &settings::Connectors, + &Connectors, )> for RazorpayPaymentsRequest { type Error = error_stack::Report; fn try_from( (item, data): ( &RazorpayRouterData<&types::PaymentsAuthorizeRouterData>, - &settings::Connectors, + &Connectors, ), ) -> Result { let request = &item.router_data.request; let txn_card_info = match request.payment_method_data.clone() { - domain::PaymentMethodData::Upi(upi_type) => match upi_type { - domain::UpiData::UpiCollect(upi_data) => TxnCardInfo::try_from((item, upi_data)), - hyperswitch_domain_models::payment_method_data::UpiData::UpiIntent(_) => Err( - errors::ConnectorError::NotImplemented("Payment methods".to_string()).into(), - ), + PaymentMethodData::Upi(upi_type) => match upi_type { + UpiData::UpiCollect(upi_data) => TxnCardInfo::try_from((item, upi_data)), + UpiData::UpiIntent(_) => Err(errors::ConnectorError::NotImplemented( + "Payment methods".to_string(), + ) + .into()), }, - domain::PaymentMethodData::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::Voucher(_) - | domain::PaymentMethodData::GiftCard(_) - | domain::PaymentMethodData::OpenBanking(_) - | domain::PaymentMethodData::CardToken(_) - | domain::PaymentMethodData::NetworkToken(_) - | domain::PaymentMethodData::CardDetailsForNetworkTransactionId(_) => { + PaymentMethodData::Card(_) + | PaymentMethodData::CardRedirect(_) + | PaymentMethodData::Wallet(_) + | PaymentMethodData::PayLater(_) + | PaymentMethodData::BankRedirect(_) + | PaymentMethodData::BankDebit(_) + | PaymentMethodData::BankTransfer(_) + | PaymentMethodData::Crypto(_) + | PaymentMethodData::MandatePayment + | PaymentMethodData::Reward + | PaymentMethodData::RealTimePayment(_) + | PaymentMethodData::Voucher(_) + | PaymentMethodData::GiftCard(_) + | PaymentMethodData::OpenBanking(_) + | PaymentMethodData::CardToken(_) + | PaymentMethodData::NetworkToken(_) + | PaymentMethodData::CardDetailsForNetworkTransactionId(_) => { Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()) } }?; @@ -457,7 +466,7 @@ impl TryFrom<&RazorpayRouterData<&types::PaymentsAuthorizeRouterData>> for Secon impl TryFrom<( &RazorpayRouterData<&types::PaymentsAuthorizeRouterData>, - &settings::Connectors, + &Connectors, )> for MerchantAccount { type Error = error_stack::Report; @@ -465,7 +474,7 @@ impl fn try_from( (_item, data): ( &RazorpayRouterData<&types::PaymentsAuthorizeRouterData>, - &settings::Connectors, + &Connectors, ), ) -> Result { let merchant_data = JuspayAuthData::try_from(data)?; @@ -483,7 +492,7 @@ impl impl TryFrom<( &RazorpayRouterData<&types::PaymentsAuthorizeRouterData>, - &settings::Connectors, + &Connectors, )> for OrderReference { type Error = error_stack::Report; @@ -491,7 +500,7 @@ impl fn try_from( (item, data): ( &RazorpayRouterData<&types::PaymentsAuthorizeRouterData>, - &settings::Connectors, + &Connectors, ), ) -> Result { let ref_id = generate_12_digit_number(); @@ -529,7 +538,7 @@ impl let item = payment_data.0; let upi_data = payment_data.1; let ref_id = generate_12_digit_number(); - let pm = common_enums::enums::PaymentMethod::Upi; + let pm = enums::PaymentMethod::Upi; Ok(Self { txn_detail_id: ref_id.to_string(), txn_id: item.router_data.connector_request_reference_id.clone(), @@ -550,7 +559,7 @@ impl impl TryFrom<( &RazorpayRouterData<&types::PaymentsAuthorizeRouterData>, - &settings::Connectors, + &Connectors, )> for TxnDetail { type Error = error_stack::Report; @@ -558,7 +567,7 @@ impl fn try_from( (item, data): ( &RazorpayRouterData<&types::PaymentsAuthorizeRouterData>, - &settings::Connectors, + &Connectors, ), ) -> Result { let ref_id = generate_12_digit_number(); @@ -597,7 +606,7 @@ impl impl TryFrom<( &RazorpayRouterData<&types::PaymentsAuthorizeRouterData>, - &settings::Connectors, + &Connectors, )> for MerchantGatewayAccount { type Error = error_stack::Report; @@ -605,7 +614,7 @@ impl fn try_from( (item, data): ( &RazorpayRouterData<&types::PaymentsAuthorizeRouterData>, - &settings::Connectors, + &Connectors, ), ) -> Result { let ref_id = generate_12_digit_number(); @@ -649,11 +658,11 @@ pub struct RazorpayAuthType { pub(super) razorpay_secret: Secret, } -impl TryFrom<&types::ConnectorAuthType> for RazorpayAuthType { +impl TryFrom<&ConnectorAuthType> for RazorpayAuthType { 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 { razorpay_id: api_key.to_owned(), razorpay_secret: key1.to_owned(), }), @@ -665,11 +674,11 @@ impl TryFrom<&types::ConnectorAuthType> for RazorpayAuthType { pub struct JuspayAuthData { pub(super) merchant_id: Secret, } -impl TryFrom<&settings::Connectors> for JuspayAuthData { +impl TryFrom<&Connectors> for JuspayAuthData { type Error = error_stack::Report; - fn try_from(connector_param: &settings::Connectors) -> Result { - let settings::Connectors { razorpay, .. } = connector_param; + fn try_from(connector_param: &Connectors) -> Result { + let Connectors { razorpay, .. } = connector_param; Ok(Self { merchant_id: razorpay.merchant_id.clone(), }) @@ -767,30 +776,22 @@ impl From for TxnStatus { } } -impl - TryFrom> - for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData< - F, - RazorpayPaymentsResponse, - T, - types::PaymentsResponseData, - >, + item: ResponseRouterData, ) -> Result { let second_factor = item.response.contents.second_factor; let status = enums::AttemptStatus::from(item.response.contents.txn_status); match second_factor { Some(second_factor) => Ok(Self { status, - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId( - second_factor.epg_txn_id, - ), - redirection_data: None, - mandate_reference: None, + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(second_factor.epg_txn_id), + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(second_factor.txn_id), @@ -806,10 +807,10 @@ impl .pgr_info .resp_message .clone() - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()); + .unwrap_or(NO_ERROR_MESSAGE.to_string()); Ok(Self { status, - response: Err(types::ErrorResponse { + response: Err(hyperswitch_domain_models::router_data::ErrorResponse { code: item.response.contents.pgr_info.resp_code.clone(), message: message_code.clone(), reason: Some(message_code.clone()), @@ -859,7 +860,7 @@ pub struct AccountDetails { impl TryFrom<( RazorpayRouterData<&types::PaymentsSyncRouterData>, - &settings::Connectors, + &Connectors, )> for RazorpayCreateSyncRequest { type Error = error_stack::Report; @@ -867,7 +868,7 @@ impl fn try_from( (item, data): ( RazorpayRouterData<&types::PaymentsSyncRouterData>, - &settings::Connectors, + &Connectors, ), ) -> Result { let ref_id = generate_12_digit_number(); @@ -996,22 +997,21 @@ impl From for enums::AttemptStatus { } } -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), - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId( + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId( item.response.second_factor.epg_txn_id, ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.second_factor.txn_id), @@ -1071,14 +1071,14 @@ pub struct PaymentGatewayResponse { impl TryFrom<( &RazorpayRouterData<&types::RefundsRouterData>, - &settings::Connectors, + &Connectors, )> for RazorpayRefundRequest { type Error = error_stack::Report; fn try_from( (item, data): ( &RazorpayRouterData<&types::RefundsRouterData>, - &settings::Connectors, + &Connectors, ), ) -> Result { let ref_id = generate_12_digit_number(); @@ -1166,7 +1166,7 @@ impl let payment_source: Secret = Secret::new("".to_string()); - let pm = common_enums::enums::PaymentMethod::Upi; + let pm = enums::PaymentMethod::Upi; let txn_card_info = TxnCardInfo { txn_detail_id: ref_id.to_string(), @@ -1244,34 +1244,34 @@ pub struct RefundRes { date_created: 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 epg_txn_id = item.response.refund.epg_txn_id.clone(); let refund_status = enums::RefundStatus::from(item.response.refund.status); let response = match epg_txn_id { - Some(epg_txn_id) => Ok(types::RefundsResponseData { + Some(epg_txn_id) => Ok(RefundsResponseData { connector_refund_id: epg_txn_id, refund_status, }), - None => Err(types::ErrorResponse { + None => Err(hyperswitch_domain_models::router_data::ErrorResponse { code: item .response .refund .error_message .clone() - .unwrap_or(consts::NO_ERROR_CODE.to_string()), + .unwrap_or(NO_ERROR_CODE.to_string()), message: item .response .refund .response_code .clone() - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), + .unwrap_or(NO_ERROR_MESSAGE.to_string()), reason: item.response.refund.response_code.clone(), status_code: item.http_code, attempt_status: None, @@ -1285,15 +1285,13 @@ impl TryFrom> } } -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 .data .request diff --git a/crates/router/src/connector/shift4.rs b/crates/hyperswitch_connectors/src/connectors/shift4.rs similarity index 63% rename from crates/router/src/connector/shift4.rs rename to crates/hyperswitch_connectors/src/connectors/shift4.rs index 895487db3ba8..283709798d00 100644 --- a/crates/router/src/connector/shift4.rs +++ b/crates/hyperswitch_connectors/src/connectors/shift4.rs @@ -1,34 +1,65 @@ pub mod transformers; -use std::fmt::Debug; - -use common_utils::{ext_traits::ByteSliceExt, request::RequestContent}; -use diesel_models::enums; +use api_models::webhooks::IncomingWebhookEvent; +use common_enums::enums; +use common_utils::{ + errors::CustomResult, + ext_traits::{ByteSliceExt, BytesExt}, + request::{Method, Request, RequestBuilder, RequestContent}, + types::{AmountConvertor, MinorUnit, MinorUnitForConnector}, +}; use error_stack::{report, ResultExt}; -use transformers as shift4; - -use super::utils::{self as connector_utils, RefundsRequestData}; -use crate::{ - configs::settings, - consts, - core::errors::{self, CustomResult}, - events::connector_api_logs::ConnectorEvent, - headers, - services::{ - self, - request::{self, Mask}, - ConnectorIntegration, ConnectorValidation, +use http::header::ACCEPT; +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}, + CompleteAuthorize, PreProcessing, }, + router_request_types::{ + AccessTokenRequestData, CompleteAuthorizeData, PaymentMethodTokenizationData, + PaymentsAuthorizeData, PaymentsCancelData, PaymentsCaptureData, PaymentsPreProcessingData, + PaymentsSessionData, PaymentsSyncData, RefundsData, SetupMandateRequestData, + }, + router_response_types::{PaymentsResponseData, RefundsResponseData}, types::{ - self, - api::{self, ConnectorCommon, ConnectorCommonExt}, - ErrorResponse, + PaymentsAuthorizeRouterData, PaymentsCaptureRouterData, + PaymentsCompleteAuthorizeRouterData, PaymentsPreProcessingRouterData, + PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData, }, - utils::BytesExt, }; +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; +use transformers::{self as shift4, Shift4PaymentsRequest, Shift4RefundRequest}; -#[derive(Debug, Clone)] -pub struct Shift4; +use crate::{ + constants::headers, + types::ResponseRouterData, + utils::{construct_not_supported_error_report, convert_amount, RefundsRequestData}, +}; + +#[derive(Clone)] +pub struct Shift4 { + amount_converter: &'static (dyn AmountConvertor + Sync), +} + +impl Shift4 { + pub fn new() -> &'static Self { + &Self { + amount_converter: &MinorUnitForConnector, + } + } +} impl ConnectorCommonExt for Shift4 where @@ -36,16 +67,16 @@ 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(), ), ( - headers::ACCEPT.to_string(), + ACCEPT.to_string(), self.get_content_type().to_string().into(), ), ]; @@ -63,14 +94,14 @@ impl ConnectorCommon for Shift4 { "application/json" } - fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { + fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str { connectors.shift4.base_url.as_ref() } fn get_auth_header( &self, - auth_type: &types::ConnectorAuthType, - ) -> CustomResult)>, errors::ConnectorError> { + auth_type: &ConnectorAuthType, + ) -> CustomResult)>, errors::ConnectorError> { let auth = shift4::Shift4AuthType::try_from(auth_type) .change_context(errors::ConnectorError::FailedToObtainAuthType)?; Ok(vec![( @@ -81,7 +112,7 @@ impl ConnectorCommon for Shift4 { fn build_error_response( &self, - res: types::Response, + res: Response, event_builder: Option<&mut ConnectorEvent>, ) -> CustomResult { let response: shift4::ErrorResponse = res @@ -97,7 +128,7 @@ impl ConnectorCommon for Shift4 { code: response .error .code - .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()), + .unwrap_or_else(|| NO_ERROR_CODE.to_string()), message: response.error.message, reason: None, attempt_status: None, @@ -116,7 +147,7 @@ impl ConnectorValidation for Shift4 { 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()), ), } } @@ -135,41 +166,25 @@ impl api::RefundSync for Shift4 {} impl api::PaymentToken for Shift4 {} impl api::PaymentsPreProcessing for Shift4 {} -impl - ConnectorIntegration< - api::PaymentMethodToken, - types::PaymentMethodTokenizationData, - types::PaymentsResponseData, - > for Shift4 +impl ConnectorIntegration + for Shift4 { // Not Implemented (R) } impl api::ConnectorAccessToken for Shift4 {} -impl ConnectorIntegration - for Shift4 -{ +impl ConnectorIntegration for Shift4 { // Not Implemented (R) } impl api::MandateSetup for Shift4 {} -impl - ConnectorIntegration< - api::SetupMandate, - types::SetupMandateRequestData, - types::PaymentsResponseData, - > for Shift4 -{ +impl ConnectorIntegration for Shift4 { 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 Shift4".to_string()) .into(), @@ -178,14 +193,12 @@ impl } #[async_trait::async_trait] -impl ConnectorIntegration - for Shift4 -{ +impl ConnectorIntegration for Shift4 { 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) } @@ -195,29 +208,35 @@ impl ConnectorIntegration CustomResult { Ok(format!("{}charges", self.base_url(connectors))) } fn get_request_body( &self, - req: &types::PaymentsAuthorizeRouterData, - _connectors: &settings::Connectors, + req: &PaymentsAuthorizeRouterData, + _connectors: &Connectors, ) -> CustomResult { - let connector_req = shift4::Shift4PaymentsRequest::try_from(req)?; + let amount = convert_amount( + self.amount_converter, + req.request.minor_amount, + req.request.currency, + )?; + let connector_router_data = shift4::Shift4RouterData::try_from((amount, req))?; + let connector_req = Shift4PaymentsRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } fn build_request( &self, - req: &types::PaymentsAuthorizeRouterData, - connectors: &settings::Connectors, - ) -> 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, )?) @@ -232,10 +251,10 @@ impl ConnectorIntegration, - res: types::Response, - ) -> CustomResult { + res: Response, + ) -> CustomResult { let response: shift4::Shift4NonThreeDsResponse = res .response .parse_struct("Shift4NonThreeDsResponse") @@ -244,7 +263,7 @@ impl ConnectorIntegration, ) -> CustomResult { self.build_error_response(res, event_builder) } } -impl ConnectorIntegration - for Shift4 -{ -} +impl ConnectorIntegration for Shift4 {} -impl ConnectorIntegration - for Shift4 -{ +impl ConnectorIntegration for Shift4 { 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) } @@ -283,8 +297,8 @@ impl ConnectorIntegration CustomResult { let connector_payment_id = req .request @@ -300,12 +314,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)?) @@ -315,7 +329,7 @@ impl ConnectorIntegration, ) -> CustomResult { self.build_error_response(res, event_builder) @@ -323,10 +337,10 @@ impl ConnectorIntegration, - res: types::Response, - ) -> CustomResult { + res: Response, + ) -> CustomResult { let response: shift4::Shift4NonThreeDsResponse = res .response .parse_struct("Shift4NonThreeDsResponse") @@ -335,7 +349,7 @@ impl ConnectorIntegration - for Shift4 -{ +impl ConnectorIntegration for Shift4 { 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) } @@ -361,12 +373,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::PaymentsCaptureType::get_headers( @@ -378,10 +390,10 @@ impl ConnectorIntegration, - res: types::Response, - ) -> CustomResult { + res: Response, + ) -> CustomResult { let response: shift4::Shift4NonThreeDsResponse = res .response .parse_struct("Shift4NonThreeDsResponse") @@ -390,7 +402,7 @@ impl ConnectorIntegration CustomResult { let connector_payment_id = req.request.connector_transaction_id.clone(); Ok(format!( @@ -413,38 +425,32 @@ impl ConnectorIntegration, ) -> CustomResult { self.build_error_response(res, event_builder) } } -impl ConnectorIntegration - for Shift4 -{ +impl ConnectorIntegration for Shift4 { //TODO: implement sessions flow } -impl - ConnectorIntegration< - api::PreProcessing, - types::PaymentsPreProcessingData, - types::PaymentsResponseData, - > for Shift4 +impl ConnectorIntegration + for Shift4 { fn get_headers( &self, - req: &types::PaymentsPreProcessingRouterData, - _connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsPreProcessingRouterData, + _connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { let mut headers = vec![ ( headers::CONTENT_TYPE.to_string(), "application/x-www-form-urlencoded".to_string().into(), ), ( - headers::ACCEPT.to_string(), + ACCEPT.to_string(), self.common_get_content_type().to_string().into(), ), ]; @@ -459,29 +465,43 @@ impl fn get_url( &self, - _req: &types::PaymentsPreProcessingRouterData, - connectors: &settings::Connectors, + _req: &PaymentsPreProcessingRouterData, + connectors: &Connectors, ) -> CustomResult { Ok(format!("{}3d-secure", self.base_url(connectors))) } fn get_request_body( &self, - req: &types::PaymentsPreProcessingRouterData, - _connectors: &settings::Connectors, + req: &PaymentsPreProcessingRouterData, + _connectors: &Connectors, ) -> CustomResult { - let connector_req = shift4::Shift4PaymentsRequest::try_from(req)?; + let amount = convert_amount( + self.amount_converter, + req.request.minor_amount.ok_or_else(|| { + errors::ConnectorError::MissingRequiredField { + field_name: "minor_amount", + } + })?, + req.request + .currency + .ok_or_else(|| errors::ConnectorError::MissingRequiredField { + field_name: "currency", + })?, + )?; + let connector_router_data = shift4::Shift4RouterData::try_from((amount, req))?; + let connector_req = Shift4PaymentsRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } fn build_request( &self, - req: &types::PaymentsPreProcessingRouterData, - connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + req: &PaymentsPreProcessingRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsPreProcessingType::get_url( self, req, connectors, )?) @@ -498,10 +518,10 @@ impl fn handle_response( &self, - data: &types::PaymentsPreProcessingRouterData, + data: &PaymentsPreProcessingRouterData, event_builder: Option<&mut ConnectorEvent>, - res: types::Response, - ) -> CustomResult { + res: Response, + ) -> CustomResult { let response: shift4::Shift4ThreeDsResponse = res .response .parse_struct("Shift4ThreeDsResponse") @@ -510,7 +530,7 @@ impl 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, @@ -520,25 +540,21 @@ impl fn get_error_response( &self, - res: types::Response, + res: Response, event_builder: Option<&mut ConnectorEvent>, ) -> CustomResult { self.build_error_response(res, event_builder) } } -impl - ConnectorIntegration< - api::CompleteAuthorize, - types::CompleteAuthorizeData, - types::PaymentsResponseData, - > for Shift4 +impl ConnectorIntegration + for Shift4 { fn get_headers( &self, - req: &types::PaymentsCompleteAuthorizeRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsCompleteAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -548,29 +564,35 @@ impl fn get_url( &self, - _req: &types::PaymentsCompleteAuthorizeRouterData, - connectors: &settings::Connectors, + _req: &PaymentsCompleteAuthorizeRouterData, + connectors: &Connectors, ) -> CustomResult { Ok(format!("{}charges", self.base_url(connectors))) } fn get_request_body( &self, - req: &types::PaymentsCompleteAuthorizeRouterData, - _connectors: &settings::Connectors, + req: &PaymentsCompleteAuthorizeRouterData, + _connectors: &Connectors, ) -> CustomResult { - let connector_req = shift4::Shift4PaymentsRequest::try_from(req)?; + let amount = convert_amount( + self.amount_converter, + req.request.minor_amount, + req.request.currency, + )?; + let connector_router_data = shift4::Shift4RouterData::try_from((amount, req))?; + let connector_req = Shift4PaymentsRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } fn build_request( &self, - req: &types::PaymentsCompleteAuthorizeRouterData, - connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + req: &PaymentsCompleteAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsCompleteAuthorizeType::get_url( self, req, connectors, )?) @@ -586,10 +608,10 @@ impl fn handle_response( &self, - data: &types::PaymentsCompleteAuthorizeRouterData, + data: &PaymentsCompleteAuthorizeRouterData, event_builder: Option<&mut ConnectorEvent>, - res: types::Response, - ) -> CustomResult { + res: Response, + ) -> CustomResult { let response: shift4::Shift4NonThreeDsResponse = res .response .parse_struct("Shift4NonThreeDsResponse") @@ -598,7 +620,7 @@ impl 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, @@ -608,19 +630,19 @@ impl fn get_error_response( &self, - res: types::Response, + res: Response, event_builder: Option<&mut ConnectorEvent>, ) -> CustomResult { self.build_error_response(res, event_builder) } } -impl ConnectorIntegration for Shift4 { +impl ConnectorIntegration for Shift4 { 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) } @@ -630,28 +652,34 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, + _req: &RefundsRouterData, + connectors: &Connectors, ) -> CustomResult { Ok(format!("{}refunds", self.base_url(connectors),)) } fn get_request_body( &self, - req: &types::RefundsRouterData, - _connectors: &settings::Connectors, + req: &RefundsRouterData, + _connectors: &Connectors, ) -> CustomResult { - let connector_req = shift4::Shift4RefundRequest::try_from(req)?; + let amount = convert_amount( + self.amount_converter, + req.request.minor_refund_amount, + req.request.currency, + )?; + let connector_router_data = shift4::Shift4RouterData::try_from((amount, req))?; + let connector_req = Shift4RefundRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } fn build_request( &self, - req: &types::RefundsRouterData, - 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( @@ -666,10 +694,10 @@ impl ConnectorIntegration, + data: &RefundsRouterData, event_builder: Option<&mut ConnectorEvent>, - res: types::Response, - ) -> CustomResult, errors::ConnectorError> { + res: Response, + ) -> CustomResult, errors::ConnectorError> { let response: shift4::RefundResponse = res .response .parse_struct("RefundResponse") @@ -678,7 +706,7 @@ impl ConnectorIntegration, ) -> CustomResult { self.build_error_response(res, event_builder) } } -impl ConnectorIntegration for Shift4 { +impl ConnectorIntegration for Shift4 { 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) } @@ -710,8 +738,8 @@ impl ConnectorIntegration CustomResult { let refund_id = req.request.get_connector_refund_id()?; Ok(format!( @@ -723,12 +751,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)?) @@ -738,17 +766,17 @@ impl ConnectorIntegration, - res: types::Response, - ) -> CustomResult { + res: Response, + ) -> CustomResult { let response: shift4::RefundResponse = res.response .parse_struct("shift4 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, @@ -758,7 +786,7 @@ impl ConnectorIntegration, ) -> CustomResult { self.build_error_response(res, event_builder) @@ -766,10 +794,10 @@ impl ConnectorIntegration, + request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult { let details: shift4::Shift4WebhookObjectId = request .body @@ -799,18 +827,18 @@ impl api::IncomingWebhook for Shift4 { fn get_webhook_event_type( &self, - request: &api::IncomingWebhookRequestDetails<'_>, - ) -> CustomResult { + request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { let details: shift4::Shift4WebhookObjectEventType = request .body .parse_struct("Shift4WebhookObjectEventType") .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?; - Ok(api::IncomingWebhookEvent::from(details.event_type)) + Ok(IncomingWebhookEvent::from(details.event_type)) } fn get_webhook_resource_object( &self, - request: &api::IncomingWebhookRequestDetails<'_>, + request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { let details: shift4::Shift4WebhookObjectResource = request .body diff --git a/crates/router/src/connector/shift4/transformers.rs b/crates/hyperswitch_connectors/src/connectors/shift4/transformers.rs similarity index 56% rename from crates/router/src/connector/shift4/transformers.rs rename to crates/hyperswitch_connectors/src/connectors/shift4/transformers.rs index 2210ab0a3614..4fb48938c429 100644 --- a/crates/router/src/connector/shift4/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/shift4/transformers.rs @@ -1,19 +1,38 @@ -use api_models::payments; +use api_models::{payments::AddressDetails, webhooks::IncomingWebhookEvent}; use cards::CardNumber; -use common_utils::pii::SecretSerdeValue; +use common_enums::enums; +use common_utils::{ + pii::{self, SecretSerdeValue}, + request::Method, + types::MinorUnit, +}; use error_stack::ResultExt; +use hyperswitch_domain_models::{ + payment_method_data::{ + BankRedirectData, BankTransferData, Card as CardData, GiftCardData, PaymentMethodData, + VoucherData, WalletData, + }, + router_data::{ConnectorAuthType, RouterData}, + router_flow_types::refunds::{Execute, RSync}, + router_request_types::{ + CompleteAuthorizeData, PaymentsAuthorizeData, PaymentsPreProcessingData, ResponseId, + }, + router_response_types::{PaymentsResponseData, RedirectForm, RefundsResponseData}, + types::{PaymentsPreProcessingRouterData, RefundsRouterData}, +}; +use hyperswitch_interfaces::errors; use masking::Secret; use serde::{Deserialize, Serialize}; use url::Url; use crate::{ - connector::utils::{ + types::{ + PaymentsPreprocessingResponseRouterData, RefundsResponseRouterData, ResponseRouterData, + }, + utils::{ self, to_connector_meta, PaymentsAuthorizeRequestData, - PaymentsCompleteAuthorizeRequestData, PaymentsPreProcessingData, RouterData, + PaymentsCompleteAuthorizeRequestData, PaymentsPreProcessingRequestData, RouterData as _, }, - core::errors, - pii, services, - types::{self, api, domain, storage::enums, transformers::ForeignFrom}, }; type Error = error_stack::Report; @@ -23,12 +42,26 @@ trait Shift4AuthorizePreprocessingCommon { fn get_router_return_url(&self) -> Option; fn get_email_optional(&self) -> Option; fn get_complete_authorize_url(&self) -> Option; - fn get_amount_required(&self) -> Result; - fn get_currency_required(&self) -> Result; - fn get_payment_method_data_required(&self) -> Result; + fn get_currency_required(&self) -> Result; + fn get_payment_method_data_required(&self) -> Result; +} + +pub struct Shift4RouterData { + pub amount: MinorUnit, + pub router_data: T, +} + +impl TryFrom<(MinorUnit, T)> for Shift4RouterData { + type Error = error_stack::Report; + fn try_from((amount, item): (MinorUnit, T)) -> Result { + Ok(Self { + amount, + router_data: item, + }) + } } -impl Shift4AuthorizePreprocessingCommon for types::PaymentsAuthorizeData { +impl Shift4AuthorizePreprocessingCommon for PaymentsAuthorizeData { fn get_email_optional(&self) -> Option { self.email.clone() } @@ -37,18 +70,14 @@ impl Shift4AuthorizePreprocessingCommon for types::PaymentsAuthorizeData { self.complete_authorize_url.clone() } - fn get_amount_required(&self) -> Result> { - Ok(self.amount) - } - fn get_currency_required( &self, - ) -> Result> { + ) -> Result> { Ok(self.currency) } fn get_payment_method_data_required( &self, - ) -> Result> { + ) -> Result> { Ok(self.payment_method_data.clone()) } @@ -61,7 +90,7 @@ impl Shift4AuthorizePreprocessingCommon for types::PaymentsAuthorizeData { } } -impl Shift4AuthorizePreprocessingCommon for types::PaymentsPreProcessingData { +impl Shift4AuthorizePreprocessingCommon for PaymentsPreProcessingData { fn get_email_optional(&self) -> Option { self.email.clone() } @@ -70,14 +99,10 @@ impl Shift4AuthorizePreprocessingCommon for types::PaymentsPreProcessingData { self.complete_authorize_url.clone() } - fn get_amount_required(&self) -> Result { - self.get_amount() - } - - fn get_currency_required(&self) -> Result { + fn get_currency_required(&self) -> Result { self.get_currency() } - fn get_payment_method_data_required(&self) -> Result { + fn get_payment_method_data_required(&self) -> Result { self.payment_method_data.clone().ok_or( errors::ConnectorError::MissingRequiredField { field_name: "payment_method_data", @@ -95,7 +120,7 @@ impl Shift4AuthorizePreprocessingCommon for types::PaymentsPreProcessingData { } #[derive(Debug, Serialize)] pub struct Shift4PaymentsRequest { - amount: String, + amount: MinorUnit, currency: enums::Currency, captured: bool, #[serde(flatten)] @@ -195,19 +220,19 @@ pub enum CardPayment { CardToken(Secret), } -impl TryFrom<&types::RouterData> +impl TryFrom<&Shift4RouterData<&RouterData>> for Shift4PaymentsRequest where Req: Shift4AuthorizePreprocessingCommon, { type Error = Error; fn try_from( - item: &types::RouterData, + item: &Shift4RouterData<&RouterData>, ) -> Result { - let submit_for_settlement = item.request.is_automatic_capture()?; - let amount = item.request.get_amount_required()?.to_string(); - let currency = item.request.get_currency_required()?; - let payment_method = Shift4PaymentMethod::try_from(item)?; + let submit_for_settlement = item.router_data.request.is_automatic_capture()?; + let amount = item.amount.to_owned(); + let currency = item.router_data.request.get_currency_required()?; + let payment_method = Shift4PaymentMethod::try_from(item.router_data)?; Ok(Self { amount, currency, @@ -217,40 +242,35 @@ where } } -impl TryFrom<&types::RouterData> - for Shift4PaymentMethod +impl TryFrom<&RouterData> for Shift4PaymentMethod where Req: Shift4AuthorizePreprocessingCommon, { type Error = Error; - fn try_from( - item: &types::RouterData, - ) -> Result { + fn try_from(item: &RouterData) -> Result { match item.request.get_payment_method_data_required()? { - domain::PaymentMethodData::Card(ref ccard) => Self::try_from((item, ccard)), - domain::PaymentMethodData::BankRedirect(ref redirect) => { - Self::try_from((item, redirect)) - } - domain::PaymentMethodData::Wallet(ref wallet_data) => Self::try_from(wallet_data), - domain::PaymentMethodData::BankTransfer(ref bank_transfer_data) => { + PaymentMethodData::Card(ref ccard) => Self::try_from((item, ccard)), + PaymentMethodData::BankRedirect(ref redirect) => Self::try_from((item, redirect)), + PaymentMethodData::Wallet(ref wallet_data) => Self::try_from(wallet_data), + PaymentMethodData::BankTransfer(ref bank_transfer_data) => { Self::try_from(bank_transfer_data.as_ref()) } - domain::PaymentMethodData::Voucher(ref voucher_data) => Self::try_from(voucher_data), - domain::PaymentMethodData::GiftCard(ref giftcard_data) => { + PaymentMethodData::Voucher(ref voucher_data) => Self::try_from(voucher_data), + PaymentMethodData::GiftCard(ref giftcard_data) => { Self::try_from(giftcard_data.as_ref()) } - domain::PaymentMethodData::CardRedirect(_) - | domain::PaymentMethodData::PayLater(_) - | domain::PaymentMethodData::BankDebit(_) - | 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::CardRedirect(_) + | PaymentMethodData::PayLater(_) + | PaymentMethodData::BankDebit(_) + | 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("Shift4"), ) @@ -260,38 +280,38 @@ where } } -impl TryFrom<&domain::WalletData> for Shift4PaymentMethod { +impl TryFrom<&WalletData> for Shift4PaymentMethod { type Error = Error; - fn try_from(wallet_data: &domain::WalletData) -> Result { + fn try_from(wallet_data: &WalletData) -> Result { match wallet_data { - domain::WalletData::AliPayRedirect(_) - | domain::WalletData::ApplePay(_) - | domain::WalletData::WeChatPayRedirect(_) - | domain::WalletData::AliPayQr(_) - | 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::PaypalRedirect(_) - | domain::WalletData::PaypalSdk(_) - | domain::WalletData::Paze(_) - | domain::WalletData::SamsungPay(_) - | domain::WalletData::TwintRedirect {} - | domain::WalletData::VippsRedirect {} - | domain::WalletData::TouchNGoRedirect(_) - | domain::WalletData::WeChatPayQr(_) - | domain::WalletData::CashappQr(_) - | domain::WalletData::SwishQr(_) - | domain::WalletData::Mifinity(_) => Err(errors::ConnectorError::NotImplemented( + WalletData::AliPayRedirect(_) + | WalletData::ApplePay(_) + | WalletData::WeChatPayRedirect(_) + | WalletData::AliPayQr(_) + | 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::PaypalRedirect(_) + | WalletData::PaypalSdk(_) + | WalletData::Paze(_) + | WalletData::SamsungPay(_) + | WalletData::TwintRedirect {} + | WalletData::VippsRedirect {} + | WalletData::TouchNGoRedirect(_) + | WalletData::WeChatPayQr(_) + | WalletData::CashappQr(_) + | WalletData::SwishQr(_) + | WalletData::Mifinity(_) => Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("Shift4"), ) .into()), @@ -299,24 +319,24 @@ impl TryFrom<&domain::WalletData> for Shift4PaymentMethod { } } -impl TryFrom<&domain::BankTransferData> for Shift4PaymentMethod { +impl TryFrom<&BankTransferData> for Shift4PaymentMethod { type Error = Error; - fn try_from(bank_transfer_data: &domain::BankTransferData) -> Result { + fn try_from(bank_transfer_data: &BankTransferData) -> Result { match bank_transfer_data { - domain::BankTransferData::MultibancoBankTransfer { .. } - | domain::BankTransferData::AchBankTransfer { .. } - | domain::BankTransferData::SepaBankTransfer { .. } - | domain::BankTransferData::BacsBankTransfer { .. } - | domain::BankTransferData::PermataBankTransfer { .. } - | domain::BankTransferData::BcaBankTransfer { .. } - | domain::BankTransferData::BniVaBankTransfer { .. } - | domain::BankTransferData::BriVaBankTransfer { .. } - | domain::BankTransferData::CimbVaBankTransfer { .. } - | domain::BankTransferData::DanamonVaBankTransfer { .. } - | domain::BankTransferData::MandiriVaBankTransfer { .. } - | domain::BankTransferData::Pix { .. } - | domain::BankTransferData::Pse {} - | domain::BankTransferData::LocalBankTransfer { .. } => { + BankTransferData::MultibancoBankTransfer { .. } + | BankTransferData::AchBankTransfer { .. } + | BankTransferData::SepaBankTransfer { .. } + | BankTransferData::BacsBankTransfer { .. } + | BankTransferData::PermataBankTransfer { .. } + | BankTransferData::BcaBankTransfer { .. } + | BankTransferData::BniVaBankTransfer { .. } + | BankTransferData::BriVaBankTransfer { .. } + | BankTransferData::CimbVaBankTransfer { .. } + | BankTransferData::DanamonVaBankTransfer { .. } + | BankTransferData::MandiriVaBankTransfer { .. } + | BankTransferData::Pix { .. } + | BankTransferData::Pse {} + | BankTransferData::LocalBankTransfer { .. } => { Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("Shift4"), ) @@ -326,24 +346,24 @@ impl TryFrom<&domain::BankTransferData> for Shift4PaymentMethod { } } -impl TryFrom<&domain::VoucherData> for Shift4PaymentMethod { +impl TryFrom<&VoucherData> for Shift4PaymentMethod { type Error = Error; - fn try_from(voucher_data: &domain::VoucherData) -> Result { + fn try_from(voucher_data: &VoucherData) -> Result { match voucher_data { - domain::VoucherData::Boleto(_) - | domain::VoucherData::Efecty - | domain::VoucherData::PagoEfectivo - | domain::VoucherData::RedCompra - | domain::VoucherData::RedPagos - | domain::VoucherData::Alfamart(_) - | domain::VoucherData::Indomaret(_) - | domain::VoucherData::Oxxo - | domain::VoucherData::SevenEleven(_) - | domain::VoucherData::Lawson(_) - | domain::VoucherData::MiniStop(_) - | domain::VoucherData::FamilyMart(_) - | domain::VoucherData::Seicomart(_) - | domain::VoucherData::PayEasy(_) => Err(errors::ConnectorError::NotImplemented( + VoucherData::Boleto(_) + | VoucherData::Efecty + | VoucherData::PagoEfectivo + | VoucherData::RedCompra + | VoucherData::RedPagos + | VoucherData::Alfamart(_) + | VoucherData::Indomaret(_) + | VoucherData::Oxxo + | VoucherData::SevenEleven(_) + | VoucherData::Lawson(_) + | VoucherData::MiniStop(_) + | VoucherData::FamilyMart(_) + | VoucherData::Seicomart(_) + | VoucherData::PayEasy(_) => Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("Shift4"), ) .into()), @@ -351,11 +371,11 @@ impl TryFrom<&domain::VoucherData> for Shift4PaymentMethod { } } -impl TryFrom<&domain::GiftCardData> for Shift4PaymentMethod { +impl TryFrom<&GiftCardData> for Shift4PaymentMethod { type Error = Error; - fn try_from(gift_card_data: &domain::GiftCardData) -> Result { + fn try_from(gift_card_data: &GiftCardData) -> Result { match gift_card_data { - domain::GiftCardData::Givex(_) | domain::GiftCardData::PaySafeCard {} => { + GiftCardData::Givex(_) | GiftCardData::PaySafeCard {} => { Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("Shift4"), ) @@ -365,20 +385,13 @@ impl TryFrom<&domain::GiftCardData> for Shift4PaymentMethod { } } -impl - TryFrom<( - &types::RouterData, - &domain::Card, - )> for Shift4PaymentMethod +impl TryFrom<(&RouterData, &CardData)> for Shift4PaymentMethod where Req: Shift4AuthorizePreprocessingCommon, { type Error = Error; fn try_from( - (item, card): ( - &types::RouterData, - &domain::Card, - ), + (item, card): (&RouterData, &CardData), ) -> Result { let card_object = Card { number: card.card_number.clone(), @@ -408,20 +421,14 @@ where } } -impl - TryFrom<( - &types::RouterData, - &domain::BankRedirectData, - )> for Shift4PaymentMethod +impl TryFrom<(&RouterData, &BankRedirectData)> + for Shift4PaymentMethod where Req: Shift4AuthorizePreprocessingCommon, { type Error = Error; fn try_from( - (item, redirect_data): ( - &types::RouterData, - &domain::BankRedirectData, - ), + (item, redirect_data): (&RouterData, &BankRedirectData), ) -> Result { let flow = Flow::try_from(item.request.get_router_return_url())?; let method_type = PaymentMethodType::try_from(redirect_data)?; @@ -437,46 +444,46 @@ where } } -impl TryFrom<&types::RouterData> +impl TryFrom<&Shift4RouterData<&RouterData>> for Shift4PaymentsRequest { type Error = Error; fn try_from( - item: &types::RouterData, + item: &Shift4RouterData<&RouterData>, ) -> Result { - match &item.request.payment_method_data { - Some(domain::PaymentMethodData::Card(_)) => { + match &item.router_data.request.payment_method_data { + Some(PaymentMethodData::Card(_)) => { let card_token: Shift4CardToken = - to_connector_meta(item.request.connector_meta.clone())?; + to_connector_meta(item.router_data.request.connector_meta.clone())?; Ok(Self { - amount: item.request.amount.to_string(), - currency: item.request.currency, + amount: item.amount.to_owned(), + currency: item.router_data.request.currency, payment_method: Shift4PaymentMethod::CardsNon3DSRequest(Box::new( CardsNon3DSRequest { card: CardPayment::CardToken(card_token.id), - description: item.description.clone(), + description: item.router_data.description.clone(), }, )), - captured: item.request.is_auto_capture()?, + captured: item.router_data.request.is_auto_capture()?, }) } - Some(domain::PaymentMethodData::Wallet(_)) - | Some(domain::PaymentMethodData::GiftCard(_)) - | Some(domain::PaymentMethodData::CardRedirect(_)) - | Some(domain::PaymentMethodData::PayLater(_)) - | Some(domain::PaymentMethodData::BankDebit(_)) - | Some(domain::PaymentMethodData::BankRedirect(_)) - | Some(domain::PaymentMethodData::BankTransfer(_)) - | Some(domain::PaymentMethodData::Crypto(_)) - | Some(domain::PaymentMethodData::MandatePayment) - | Some(domain::PaymentMethodData::Voucher(_)) - | Some(domain::PaymentMethodData::Reward) - | Some(domain::PaymentMethodData::RealTimePayment(_)) - | Some(domain::PaymentMethodData::Upi(_)) - | Some(domain::PaymentMethodData::OpenBanking(_)) - | Some(domain::PaymentMethodData::CardToken(_)) - | Some(domain::PaymentMethodData::NetworkToken(_)) - | Some(domain::PaymentMethodData::CardDetailsForNetworkTransactionId(_)) + Some(PaymentMethodData::Wallet(_)) + | Some(PaymentMethodData::GiftCard(_)) + | Some(PaymentMethodData::CardRedirect(_)) + | Some(PaymentMethodData::PayLater(_)) + | Some(PaymentMethodData::BankDebit(_)) + | Some(PaymentMethodData::BankRedirect(_)) + | Some(PaymentMethodData::BankTransfer(_)) + | Some(PaymentMethodData::Crypto(_)) + | Some(PaymentMethodData::MandatePayment) + | Some(PaymentMethodData::Voucher(_)) + | Some(PaymentMethodData::Reward) + | Some(PaymentMethodData::RealTimePayment(_)) + | Some(PaymentMethodData::Upi(_)) + | Some(PaymentMethodData::OpenBanking(_)) + | Some(PaymentMethodData::CardToken(_)) + | Some(PaymentMethodData::NetworkToken(_)) + | Some(PaymentMethodData::CardDetailsForNetworkTransactionId(_)) | None => Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("Shift4"), ) @@ -485,28 +492,28 @@ impl TryFrom<&types::RouterData for PaymentMethodType { +impl TryFrom<&BankRedirectData> for PaymentMethodType { type Error = Error; - fn try_from(value: &domain::BankRedirectData) -> Result { + fn try_from(value: &BankRedirectData) -> Result { match value { - domain::BankRedirectData::Eps { .. } => Ok(Self::Eps), - domain::BankRedirectData::Giropay { .. } => Ok(Self::Giropay), - domain::BankRedirectData::Ideal { .. } => Ok(Self::Ideal), - domain::BankRedirectData::Sofort { .. } => Ok(Self::Sofort), - domain::BankRedirectData::BancontactCard { .. } - | domain::BankRedirectData::Blik { .. } - | domain::BankRedirectData::Trustly { .. } - | 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::Eps { .. } => Ok(Self::Eps), + BankRedirectData::Giropay { .. } => Ok(Self::Giropay), + BankRedirectData::Ideal { .. } => Ok(Self::Ideal), + BankRedirectData::Sofort { .. } => Ok(Self::Sofort), + BankRedirectData::BancontactCard { .. } + | BankRedirectData::Blik { .. } + | BankRedirectData::Trustly { .. } + | 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("Shift4"), ) @@ -525,14 +532,12 @@ impl TryFrom> for Flow { } } -impl TryFrom<&types::RouterData> for Billing +impl TryFrom<&RouterData> for Billing where Req: Shift4AuthorizePreprocessingCommon, { type Error = Error; - fn try_from( - item: &types::RouterData, - ) -> Result { + fn try_from(item: &RouterData) -> Result { let billing_address = item .get_optional_billing() .as_ref() @@ -548,7 +553,7 @@ where } } -fn get_address_details(address_details: Option<&payments::AddressDetails>) -> Option
{ +fn get_address_details(address_details: Option<&AddressDetails>) -> Option
{ address_details.map(|address| Address { line1: address.line1.clone(), line2: address.line1.clone(), @@ -564,10 +569,10 @@ pub struct Shift4AuthType { pub(super) api_key: Secret, } -impl TryFrom<&types::ConnectorAuthType> for Shift4AuthType { +impl TryFrom<&ConnectorAuthType> for Shift4AuthType { type Error = Error; - fn try_from(item: &types::ConnectorAuthType) -> Result { - if let types::ConnectorAuthType::HeaderKey { api_key } = item { + fn try_from(item: &ConnectorAuthType) -> Result { + if let ConnectorAuthType::HeaderKey { api_key } = item { Ok(Self { api_key: api_key.to_owned(), }) @@ -586,23 +591,24 @@ pub enum Shift4PaymentStatus { Pending, } -impl ForeignFrom<(bool, Option<&NextAction>, Shift4PaymentStatus)> for enums::AttemptStatus { - fn foreign_from(item: (bool, Option<&NextAction>, Shift4PaymentStatus)) -> Self { - let (captured, next_action, payment_status) = item; - match payment_status { - Shift4PaymentStatus::Successful => { - if captured { - Self::Charged - } else { - Self::Authorized - } +fn get_status( + captured: bool, + next_action: Option<&NextAction>, + payment_status: Shift4PaymentStatus, +) -> enums::AttemptStatus { + match payment_status { + Shift4PaymentStatus::Successful => { + if captured { + enums::AttemptStatus::Charged + } else { + enums::AttemptStatus::Authorized } - Shift4PaymentStatus::Failed => Self::Failure, - Shift4PaymentStatus::Pending => match next_action { - Some(NextAction::Redirect) => Self::AuthenticationPending, - Some(NextAction::Wait) | Some(NextAction::None) | None => Self::Pending, - }, } + Shift4PaymentStatus::Failed => enums::AttemptStatus::Failure, + Shift4PaymentStatus::Pending => match next_action { + Some(NextAction::Redirect) => enums::AttemptStatus::AuthenticationPending, + Some(NextAction::Wait) | Some(NextAction::None) | None => enums::AttemptStatus::Pending, + }, } } @@ -687,7 +693,7 @@ pub struct Token { #[derive(Default, Debug, Deserialize, Serialize)] pub struct ThreeDSecureInfo { - pub amount: i64, + pub amount: MinorUnit, pub currency: String, pub enrolled: bool, #[serde(rename = "liabilityShift")] @@ -724,31 +730,31 @@ pub struct Shift4CardToken { pub id: Secret, } -impl TryFrom> - for types::PaymentsPreProcessingRouterData +impl TryFrom> + for PaymentsPreProcessingRouterData { type Error = Error; fn try_from( - item: types::PaymentsPreprocessingResponseRouterData, + item: PaymentsPreprocessingResponseRouterData, ) -> Result { let redirection_data = item .response .redirect_url - .map(|url| services::RedirectForm::from((url, services::Method::Get))); + .map(|url| RedirectForm::from((url, Method::Get))); Ok(Self { status: if redirection_data.is_some() { enums::AttemptStatus::AuthenticationPending } else { enums::AttemptStatus::Pending }, - request: types::PaymentsPreProcessingData { + request: PaymentsPreProcessingData { enrolled_for_3ds: item.response.enrolled, ..item.data.request }, - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::NoResponseId, - redirection_data, - mandate_reference: None, + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::NoResponseId, + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(None), connector_metadata: Some( serde_json::to_value(Shift4CardToken { id: item.response.token.id, @@ -765,38 +771,33 @@ impl TryFrom - TryFrom> - for types::RouterData +impl TryFrom> + for RouterData { type Error = Error; fn try_from( - item: types::ResponseRouterData< - F, - Shift4NonThreeDsResponse, - T, - types::PaymentsResponseData, - >, + item: ResponseRouterData, ) -> Result { - let connector_id = types::ResponseId::ConnectorTransactionId(item.response.id.clone()); + let connector_id = ResponseId::ConnectorTransactionId(item.response.id.clone()); Ok(Self { - status: enums::AttemptStatus::foreign_from(( + status: get_status( item.response.captured, item.response .flow .as_ref() .and_then(|flow| flow.next_action.as_ref()), item.response.status, - )), - response: Ok(types::PaymentsResponseData::TransactionResponse { + ), + response: Ok(PaymentsResponseData::TransactionResponse { resource_id: connector_id, - redirection_data: item - .response - .flow - .and_then(|flow| flow.redirect) - .and_then(|redirect| redirect.redirect_url) - .map(|url| services::RedirectForm::from((url, services::Method::Get))), - mandate_reference: None, + redirection_data: Box::new( + item.response + .flow + .and_then(|flow| flow.redirect) + .and_then(|redirect| redirect.redirect_url) + .map(|url| RedirectForm::from((url, Method::Get))), + ), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.id), @@ -814,15 +815,15 @@ impl #[serde(rename_all = "camelCase")] pub struct Shift4RefundRequest { charge_id: String, - amount: i64, + amount: MinorUnit, } -impl TryFrom<&types::RefundsRouterData> for Shift4RefundRequest { +impl TryFrom<&Shift4RouterData<&RefundsRouterData>> for Shift4RefundRequest { type Error = Error; - fn try_from(item: &types::RefundsRouterData) -> Result { + fn try_from(item: &Shift4RouterData<&RefundsRouterData>) -> Result { Ok(Self { - charge_id: item.request.connector_transaction_id.clone(), - amount: item.request.refund_amount, + charge_id: item.router_data.request.connector_transaction_id.clone(), + amount: item.amount.to_owned(), }) } } @@ -855,16 +856,14 @@ pub enum Shift4RefundStatus { Failed, } -impl TryFrom> - for types::RefundsRouterData -{ +impl TryFrom> for RefundsRouterData { type Error = Error; 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, }), @@ -873,16 +872,14 @@ impl TryFrom> } } -impl TryFrom> - for types::RefundsRouterData -{ +impl TryFrom> for RefundsRouterData { type Error = Error; 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, }), @@ -916,7 +913,7 @@ pub fn is_refund_event(event: &Shift4WebhookEvent) -> bool { matches!(event, Shift4WebhookEvent::ChargeRefunded) } -impl From for api::IncomingWebhookEvent { +impl From for IncomingWebhookEvent { fn from(event: Shift4WebhookEvent) -> Self { match event { Shift4WebhookEvent::ChargeSucceeded | Shift4WebhookEvent::ChargeUpdated => { diff --git a/crates/hyperswitch_connectors/src/connectors/square/transformers.rs b/crates/hyperswitch_connectors/src/connectors/square/transformers.rs index b2151c524be9..0e6d3128b301 100644 --- a/crates/hyperswitch_connectors/src/connectors/square/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/square/transformers.rs @@ -385,8 +385,8 @@ impl TryFrom TryFrom { pub amount: FloatMajorUnit, // The type of amount that a connector accepts, for example, String, i64, f64, etc. + pub order_amount: FloatMajorUnit, pub shipping: FloatMajorUnit, pub router_data: T, } -impl From<(FloatMajorUnit, FloatMajorUnit, T)> for TaxjarRouterData { - fn from((amount, shipping, item): (FloatMajorUnit, FloatMajorUnit, T)) -> Self { +impl From<(FloatMajorUnit, FloatMajorUnit, FloatMajorUnit, T)> for TaxjarRouterData { + fn from( + (amount, order_amount, shipping, item): (FloatMajorUnit, FloatMajorUnit, FloatMajorUnit, T), + ) -> Self { Self { amount, + order_amount, shipping, router_data: item, } @@ -49,7 +53,7 @@ pub struct LineItem { id: Option, quantity: Option, product_tax_code: Option, - unit_price: Option, + unit_price: Option, } #[derive(Default, Debug, Serialize, Eq, PartialEq)] @@ -69,8 +73,6 @@ impl TryFrom<&TaxjarRouterData<&types::PaymentsTaxCalculationRouterData>> item: &TaxjarRouterData<&types::PaymentsTaxCalculationRouterData>, ) -> Result { let request = &item.router_data.request; - let currency = item.router_data.request.currency; - let currency_unit = &api::CurrencyUnit::Base; let shipping = &item .router_data .request @@ -87,16 +89,11 @@ impl TryFrom<&TaxjarRouterData<&types::PaymentsTaxCalculationRouterData>> order_details .iter() .map(|line_item| { - let unit_price = utils::get_amount_as_f64( - currency_unit, - line_item.amount, - currency, - )?; Ok(LineItem { id: line_item.product_id.clone(), quantity: Some(line_item.quantity), product_tax_code: line_item.product_tax_code.clone(), - unit_price: Some(unit_price), + unit_price: Some(item.order_amount), }) }) .collect(); diff --git a/crates/hyperswitch_connectors/src/connectors/thunes/transformers.rs b/crates/hyperswitch_connectors/src/connectors/thunes/transformers.rs index c0ee0fdae944..ca18179ff171 100644 --- a/crates/hyperswitch_connectors/src/connectors/thunes/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/thunes/transformers.rs @@ -129,8 +129,8 @@ impl TryFrom + Sync), +} -#[derive(Debug, Clone)] -pub struct Tsys; - +impl Tsys { + pub fn new() -> &'static Self { + &Self { + amount_converter: &StringMinorUnitForConnector, + } + } +} impl api::Payment for Tsys {} impl api::PaymentSession for Tsys {} impl api::ConnectorAccessToken for Tsys {} @@ -156,7 +163,14 @@ impl ConnectorIntegration CustomResult { - let connector_req = tsys::TsysPaymentsRequest::try_from(req)?; + let amount = utils::convert_amount( + self.amount_converter, + req.request.minor_amount, + req.request.currency, + )?; + let connector_router_data = tsys::TsysRouterData::from((amount, req)); + let connector_req: transformers::TsysPaymentsRequest = + tsys::TsysPaymentsRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -316,7 +330,13 @@ impl ConnectorIntegration fo req: &PaymentsCaptureRouterData, _connectors: &Connectors, ) -> CustomResult { - let connector_req = tsys::TsysPaymentsCaptureRequest::try_from(req)?; + let amount = utils::convert_amount( + self.amount_converter, + req.request.minor_amount_to_capture, + req.request.currency, + )?; + let connector_router_data = tsys::TsysRouterData::from((amount, req)); + let connector_req = tsys::TsysPaymentsCaptureRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -473,7 +493,14 @@ impl ConnectorIntegration for Tsys { req: &RefundsRouterData, _connectors: &Connectors, ) -> CustomResult { - let connector_req = tsys::TsysRefundRequest::try_from(req)?; + let amount = utils::convert_amount( + self.amount_converter, + req.request.minor_refund_amount, + req.request.currency, + )?; + let connector_router_data = tsys::TsysRouterData::from((amount, req)); + + let connector_req = tsys::TsysRefundRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } diff --git a/crates/hyperswitch_connectors/src/connectors/tsys/transformers.rs b/crates/hyperswitch_connectors/src/connectors/tsys/transformers.rs index e97cf228729d..c867adaa23ea 100644 --- a/crates/hyperswitch_connectors/src/connectors/tsys/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/tsys/transformers.rs @@ -1,4 +1,5 @@ use common_enums::enums; +use common_utils::types::StringMinorUnit; use error_stack::ResultExt; use hyperswitch_domain_models::{ payment_method_data::PaymentMethodData, @@ -7,13 +8,26 @@ use hyperswitch_domain_models::{ router_request_types::ResponseId, router_response_types::{PaymentsResponseData, RefundsResponseData}, types::{ - self, PaymentsCancelRouterData, PaymentsCaptureRouterData, PaymentsSyncRouterData, - RefundSyncRouterData, RefundsRouterData, + self, PaymentsCancelRouterData, PaymentsSyncRouterData, RefundSyncRouterData, + RefundsRouterData, }, }; use hyperswitch_interfaces::errors; use masking::Secret; use serde::{Deserialize, Serialize}; +pub struct TsysRouterData { + pub amount: StringMinorUnit, + pub router_data: T, +} + +impl From<(StringMinorUnit, T)> for TsysRouterData { + fn from((amount, router_data): (StringMinorUnit, T)) -> Self { + Self { + amount, + router_data, + } + } +} use crate::{ types::{RefundsResponseRouterData, ResponseRouterData}, @@ -33,7 +47,7 @@ pub struct TsysPaymentAuthSaleRequest { device_id: Secret, transaction_key: Secret, card_data_source: String, - transaction_amount: String, + transaction_amount: StringMinorUnit, currency_code: enums::Currency, card_number: cards::CardNumber, expiration_date: Secret, @@ -46,9 +60,12 @@ pub struct TsysPaymentAuthSaleRequest { order_number: String, } -impl TryFrom<&types::PaymentsAuthorizeRouterData> for TsysPaymentsRequest { +impl TryFrom<&TsysRouterData<&types::PaymentsAuthorizeRouterData>> for TsysPaymentsRequest { type Error = error_stack::Report; - fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result { + fn try_from( + item_data: &TsysRouterData<&types::PaymentsAuthorizeRouterData>, + ) -> Result { + let item = item_data.router_data.clone(); match item.request.payment_method_data.clone() { PaymentMethodData::Card(ccard) => { let connector_auth: TsysAuthType = @@ -57,7 +74,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for TsysPaymentsRequest { device_id: connector_auth.device_id, transaction_key: connector_auth.transaction_key, card_data_source: "INTERNET".to_string(), - transaction_amount: item.request.amount.to_string(), + transaction_amount: item_data.amount.clone(), currency_code: item.request.currency, card_number: ccard.card_number.clone(), expiration_date: ccard @@ -226,8 +243,8 @@ fn get_error_response( fn get_payments_response(connector_response: TsysResponse) -> PaymentsResponseData { PaymentsResponseData::TransactionResponse { resource_id: ResponseId::ConnectorTransactionId(connector_response.transaction_id.clone()), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(connector_response.transaction_id), @@ -246,8 +263,8 @@ fn get_payments_sync_response( .transaction_id .clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some( @@ -430,7 +447,7 @@ pub struct TsysCaptureRequest { #[serde(rename = "deviceID")] device_id: Secret, transaction_key: Secret, - transaction_amount: String, + transaction_amount: StringMinorUnit, #[serde(rename = "transactionID")] transaction_id: String, #[serde(rename = "developerID")] @@ -444,16 +461,19 @@ pub struct TsysPaymentsCaptureRequest { capture: TsysCaptureRequest, } -impl TryFrom<&PaymentsCaptureRouterData> for TsysPaymentsCaptureRequest { +impl TryFrom<&TsysRouterData<&types::PaymentsCaptureRouterData>> for TsysPaymentsCaptureRequest { type Error = error_stack::Report; - fn try_from(item: &PaymentsCaptureRouterData) -> Result { + fn try_from( + item_data: &TsysRouterData<&types::PaymentsCaptureRouterData>, + ) -> Result { + let item = item_data.router_data.clone(); let connector_auth: TsysAuthType = TsysAuthType::try_from(&item.connector_auth_type)?; let capture = TsysCaptureRequest { device_id: connector_auth.device_id, transaction_key: connector_auth.transaction_key, transaction_id: item.request.connector_transaction_id.clone(), developer_id: connector_auth.developer_id, - transaction_amount: item.request.amount_to_capture.to_string(), + transaction_amount: item_data.amount.clone(), }; Ok(Self { capture }) } @@ -466,7 +486,7 @@ pub struct TsysReturnRequest { #[serde(rename = "deviceID")] device_id: Secret, transaction_key: Secret, - transaction_amount: String, + transaction_amount: StringMinorUnit, #[serde(rename = "transactionID")] transaction_id: String, } @@ -478,14 +498,15 @@ pub struct TsysRefundRequest { return_request: TsysReturnRequest, } -impl TryFrom<&RefundsRouterData> for TsysRefundRequest { +impl TryFrom<&TsysRouterData<&RefundsRouterData>> for TsysRefundRequest { type Error = error_stack::Report; - fn try_from(item: &RefundsRouterData) -> Result { + fn try_from(item_data: &TsysRouterData<&RefundsRouterData>) -> Result { + let item = item_data.router_data; let connector_auth: TsysAuthType = TsysAuthType::try_from(&item.connector_auth_type)?; let return_request = TsysReturnRequest { device_id: connector_auth.device_id, transaction_key: connector_auth.transaction_key, - transaction_amount: item.request.refund_amount.to_string(), + transaction_amount: item_data.amount.clone(), transaction_id: item.request.connector_transaction_id.clone(), }; Ok(Self { return_request }) diff --git a/crates/hyperswitch_connectors/src/connectors/volt/transformers.rs b/crates/hyperswitch_connectors/src/connectors/volt/transformers.rs index e04eae63b4c8..b13d029185f5 100644 --- a/crates/hyperswitch_connectors/src/connectors/volt/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/volt/transformers.rs @@ -277,8 +277,8 @@ impl TryFrom TryFrom TryFrom TryFrom> status: get_status((item.response.status, item.response.capture_method)), response: Ok(PaymentsResponseData::TransactionResponse { resource_id: ResponseId::ConnectorTransactionId(item.response.id.clone()), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.id), @@ -621,8 +621,8 @@ impl TryFrom, - _connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { let mut headers = vec![ ( headers::ACCEPT.to_string(), @@ -64,6 +93,7 @@ where headers::CONTENT_TYPE.to_string(), self.get_content_type().to_string().into(), ), + (headers::WP_API_VERSION.to_string(), "2024-06-01".into()), ]; let mut api_key = self.get_auth_header(&req.connector_auth_type)?; headers.append(&mut api_key); @@ -81,17 +111,17 @@ impl ConnectorCommon for Worldpay { } fn common_get_content_type(&self) -> &'static str { - "application/vnd.worldpay.payments-v7+json" + "application/json" } - fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { + fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str { connectors.worldpay.base_url.as_ref() } fn get_auth_header( &self, - auth_type: &types::ConnectorAuthType, - ) -> CustomResult)>, errors::ConnectorError> { + auth_type: &ConnectorAuthType, + ) -> CustomResult)>, errors::ConnectorError> { let auth = worldpay::WorldpayAuthType::try_from(auth_type) .change_context(errors::ConnectorError::FailedToObtainAuthType)?; Ok(vec![( @@ -121,7 +151,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, }) } @@ -137,7 +167,7 @@ impl ConnectorValidation for Worldpay { 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()), ), } } @@ -146,22 +176,14 @@ impl ConnectorValidation for Worldpay { impl api::Payment for Worldpay {} impl api::MandateSetup for Worldpay {} -impl - ConnectorIntegration< - api::SetupMandate, - types::SetupMandateRequestData, - types::PaymentsResponseData, - > for Worldpay +impl ConnectorIntegration + for Worldpay { 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 Worldpay".to_string()) .into(), @@ -171,26 +193,20 @@ impl impl api::PaymentToken for Worldpay {} -impl - ConnectorIntegration< - api::PaymentMethodToken, - types::PaymentMethodTokenizationData, - types::PaymentsResponseData, - > for Worldpay +impl ConnectorIntegration + for Worldpay { // Not Implemented (R) } impl api::PaymentVoid for Worldpay {} -impl ConnectorIntegration - for Worldpay -{ +impl ConnectorIntegration for Worldpay { 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) } @@ -200,41 +216,42 @@ impl ConnectorIntegration CustomResult { let connector_payment_id = req.request.connector_transaction_id.clone(); Ok(format!( - "{}payments/authorizations/cancellations/{connector_payment_id}", + "{}api/payments/{}/cancellations", self.base_url(connectors), + urlencoding::encode(&connector_payment_id), )) } fn build_request( &self, - req: &types::PaymentsCancelRouterData, - connectors: &settings::Connectors, - ) -> 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)?) + RequestBuilder::new() + .method(Method::Post) + .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(), )) } fn handle_response( &self, - data: &types::PaymentsCancelRouterData, + data: &PaymentsCancelRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult + ) -> CustomResult where - api::Void: Clone, - types::PaymentsCancelData: Clone, - types::PaymentsResponseData: Clone, + Void: Clone, + PaymentsCancelData: Clone, + PaymentsResponseData: Clone, { match res.status_code { 202 => { @@ -244,15 +261,24 @@ impl ConnectorIntegration - for Worldpay -{ -} +impl ConnectorIntegration for Worldpay {} impl api::PaymentSync for Worldpay {} -impl ConnectorIntegration - for Worldpay -{ +impl ConnectorIntegration for Worldpay { 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) } @@ -297,8 +318,8 @@ impl ConnectorIntegration CustomResult { let connector_payment_id = req .request @@ -306,20 +327,20 @@ 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)?) @@ -332,15 +353,33 @@ 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( &self, - data: &types::PaymentsSyncRouterData, + data: &PaymentsSyncRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: WorldpayEventResponse = res.response .parse_struct("Worldpay EventResponse") @@ -349,6 +388,12 @@ impl ConnectorIntegration enums::AttemptStatus::from(&worldpay_status), }; - Ok(types::PaymentsSyncRouterData { + Ok(PaymentsSyncRouterData { status, - response: Ok(types::PaymentsResponseData::TransactionResponse { + response: Ok(PaymentsResponseData::TransactionResponse { resource_id: data.request.connector_transaction_id.clone(), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, - connector_response_reference_id: None, + connector_response_reference_id: optional_correlation_id, incremental_authorization_allowed: None, charge_id: None, }), @@ -381,14 +426,12 @@ impl ConnectorIntegration - for Worldpay -{ +impl ConnectorIntegration for Worldpay { 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) } @@ -398,23 +441,23 @@ impl ConnectorIntegration CustomResult { let connector_payment_id = req.request.connector_transaction_id.clone(); Ok(format!( - "{}payments/settlements/partials/{}", + "{}api/payments/{}/partialSettlements", self.base_url(connectors), - connector_payment_id + urlencoding::encode(&connector_payment_id), )) } fn get_request_body( &self, - req: &types::PaymentsCaptureRouterData, - _connectors: &settings::Connectors, + req: &PaymentsCaptureRouterData, + _connectors: &Connectors, ) -> CustomResult { - let amount_to_capture = connector_utils::convert_amount( + let amount_to_capture = convert_amount( self.amount_converter, req.request.minor_amount_to_capture, req.request.currency, @@ -425,12 +468,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::PaymentsCaptureType::get_headers( @@ -445,10 +488,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { match res.status_code { 202 => { let response: WorldpayPaymentsResponse = res @@ -457,15 +500,24 @@ 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 {} -impl ConnectorIntegration - for Worldpay -{ -} +impl ConnectorIntegration for Worldpay {} impl api::PaymentAuthorize for Worldpay {} -impl ConnectorIntegration - for Worldpay -{ +impl ConnectorIntegration for Worldpay { 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) } @@ -511,19 +566,16 @@ impl ConnectorIntegration CustomResult { - Ok(format!( - "{}cardPayments/customerInitiatedTransactions", - self.base_url(connectors) - )) + Ok(format!("{}api/payments", self.base_url(connectors))) } fn get_request_body( &self, - req: &types::PaymentsAuthorizeRouterData, - _connectors: &settings::Connectors, + req: &PaymentsAuthorizeRouterData, + _connectors: &Connectors, ) -> CustomResult { let connector_router_data = worldpay::WorldpayRouterData::try_from(( &self.get_currency_unit(), @@ -540,12 +592,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, )?) @@ -562,10 +614,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: WorldpayPaymentsResponse = res .response .parse_struct("Worldpay PaymentsResponse") @@ -573,12 +625,132 @@ 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 {} +impl ConnectorIntegration + for Worldpay +{ + fn get_headers( + &self, + req: &PaymentsCompleteAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { + self.build_headers(req, connectors) + } + + fn get_content_type(&self) -> &'static str { + self.common_get_content_type() + } + + fn get_url( + &self, + req: &PaymentsCompleteAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult { + let connector_payment_id = req + .request + .connector_transaction_id + .clone() + .ok_or(errors::ConnectorError::MissingConnectorTransactionID)?; + let stage = match req.status { + enums::AttemptStatus::DeviceDataCollectionPending => "3dsDeviceData".to_string(), + _ => "3dsChallenges".to_string(), + }; + Ok(format!( + "{}api/payments/{connector_payment_id}/{stage}", + self.base_url(connectors), + )) + } + + fn get_request_body( + &self, + req: &PaymentsCompleteAuthorizeRouterData, + _connectors: &Connectors, + ) -> CustomResult { + let req_obj = WorldpayCompleteAuthorizationRequest::try_from(req)?; + Ok(RequestContent::Json(Box::new(req_obj))) + } + + fn build_request( + &self, + req: &PaymentsCompleteAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + let request = RequestBuilder::new() + .method(Method::Post) + .url(&types::PaymentsCompleteAuthorizeType::get_url( + self, req, connectors, + )?) + .headers(types::PaymentsCompleteAuthorizeType::get_headers( + self, req, connectors, + )?) + .set_body(types::PaymentsCompleteAuthorizeType::get_request_body( + self, req, connectors, + )?) + .build(); + Ok(Some(request)) + } + + fn handle_response( + &self, + data: &PaymentsCompleteAuthorizeRouterData, + event_builder: Option<&mut ConnectorEvent>, + res: Response, + ) -> CustomResult { + let response: WorldpayPaymentsResponse = res + .response + .parse_struct("WorldpayPaymentsResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + event_builder.map(|i| i.set_response_body(&response)); + router_env::logger::info!(connector_response=?response); + let optional_correlation_id = res.headers.and_then(|headers| { + headers + .get("WP-CorrelationId") + .and_then(|header_value| header_value.to_str().ok()) + .map(|id| id.to_string()) + }); + RouterData::foreign_try_from(( + ResponseRouterData { + response, + data: data.clone(), + http_code: res.status_code, + }, + optional_correlation_id, + )) .change_context(errors::ConnectorError::ResponseHandlingFailed) } @@ -589,20 +761,26 @@ 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::Refund for Worldpay {} impl api::RefundExecute for Worldpay {} impl api::RefundSync for Worldpay {} -impl ConnectorIntegration - for Worldpay -{ +impl ConnectorIntegration for Worldpay { 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) } @@ -612,10 +790,10 @@ impl ConnectorIntegration CustomResult { - let amount_to_refund = connector_utils::convert_amount( + let amount_to_refund = convert_amount( self.amount_converter, req.request.minor_refund_amount, req.request.currency, @@ -626,24 +804,24 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, + req: &RefundsRouterData, + connectors: &Connectors, ) -> CustomResult { let connector_payment_id = req.request.connector_transaction_id.clone(); Ok(format!( - "{}payments/settlements/refunds/partials/{}", + "{}api/payments/{}/partialRefunds", self.base_url(connectors), - connector_payment_id + urlencoding::encode(&connector_payment_id), )) } fn build_request( &self, - req: &types::RefundsRouterData, - 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( @@ -658,10 +836,10 @@ impl ConnectorIntegration, + data: &RefundsRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult, errors::ConnectorError> { + ) -> CustomResult, errors::ConnectorError> { match res.status_code { 202 => { let response: WorldpayPaymentsResponse = res @@ -670,9 +848,19 @@ 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 { +impl ConnectorIntegration for Worldpay { 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) } @@ -706,24 +902,24 @@ impl ConnectorIntegration CustomResult { Ok(format!( - "{}payments/events/{}", + "{}api/payments/{}", self.base_url(connectors), - req.request.get_connector_refund_id()? + urlencoding::encode(&req.request.get_connector_refund_id()?), )) } fn build_request( &self, - req: &types::RefundSyncRouterData, - connectors: &settings::Connectors, - ) -> 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)?) @@ -733,18 +929,18 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: WorldpayEventResponse = res.response .parse_struct("Worldpay EventResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - Ok(types::RefundSyncRouterData { - response: Ok(types::RefundsResponseData { + Ok(RefundSyncRouterData { + response: Ok(RefundsResponseData { connector_refund_id: data.request.refund_id.clone(), refund_status: enums::RefundStatus::from(response.last_event), }), @@ -759,24 +955,31 @@ 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] -impl api::IncomingWebhook for Worldpay { +impl IncomingWebhook for Worldpay { fn get_webhook_source_verification_algorithm( &self, - _request: &api::IncomingWebhookRequestDetails<'_>, + _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 event_signature = - connector_utils::get_header_key_value("Event-Signature", request.headers)?.split(','); + let event_signature = get_header_key_value("Event-Signature", request.headers)?.split(','); let sign_header = event_signature .last() .ok_or(errors::ConnectorError::WebhookSignatureNotFound)?; @@ -789,7 +992,7 @@ impl api::IncomingWebhook for Worldpay { 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> { @@ -806,47 +1009,46 @@ impl api::IncomingWebhook for Worldpay { fn get_webhook_object_reference_id( &self, - request: &api::IncomingWebhookRequestDetails<'_>, + request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult { let body: WorldpayWebhookTransactionId = request .body .parse_struct("WorldpayWebhookTransactionId") .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?; Ok(api_models::webhooks::ObjectReferenceId::PaymentId( - api::PaymentIdType::ConnectorTransactionId(body.event_details.transaction_reference), + PaymentIdType::PaymentAttemptId(body.event_details.transaction_reference), )) } fn get_webhook_event_type( &self, - request: &api::IncomingWebhookRequestDetails<'_>, - ) -> CustomResult { + request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { let body: WorldpayWebhookEventType = request .body .parse_struct("WorldpayWebhookEventType") .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?; match body.event_details.event_type { - EventType::Authorized => { - Ok(api::IncomingWebhookEvent::PaymentIntentAuthorizationSuccess) + EventType::Authorized => Ok(IncomingWebhookEvent::PaymentIntentAuthorizationSuccess), + EventType::Settled => Ok(IncomingWebhookEvent::PaymentIntentSuccess), + EventType::SentForSettlement | EventType::SentForAuthorization => { + Ok(IncomingWebhookEvent::PaymentIntentProcessing) } - EventType::SentForSettlement => Ok(api::IncomingWebhookEvent::PaymentIntentProcessing), - EventType::Settled => Ok(api::IncomingWebhookEvent::PaymentIntentSuccess), EventType::Error | EventType::Expired | EventType::SettlementFailed => { - Ok(api::IncomingWebhookEvent::PaymentIntentFailure) + Ok(IncomingWebhookEvent::PaymentIntentFailure) } EventType::Unknown - | EventType::SentForAuthorization | EventType::Cancelled | EventType::Refused | EventType::Refunded | EventType::SentForRefund - | EventType::RefundFailed => Ok(api::IncomingWebhookEvent::EventNotSupported), + | EventType::RefundFailed => Ok(IncomingWebhookEvent::EventNotSupported), } } fn get_webhook_resource_object( &self, - request: &api::IncomingWebhookRequestDetails<'_>, + request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { let body: WorldpayWebhookEventType = request .body @@ -856,3 +1058,19 @@ impl api::IncomingWebhook for Worldpay { Ok(Box::new(psync_body)) } } + +impl ConnectorRedirectResponse for Worldpay { + fn get_flow_type( + &self, + _query_params: &str, + _json_payload: Option, + action: PaymentAction, + ) -> CustomResult { + match action { + PaymentAction::CompleteAuthorize => Ok(enums::CallConnectorAction::Trigger), + PaymentAction::PSync | PaymentAction::PaymentAuthenticateCompleteAuthorize => { + Ok(enums::CallConnectorAction::Avoid) + } + } + } +} diff --git a/crates/router/src/connector/worldpay/requests.rs b/crates/hyperswitch_connectors/src/connectors/worldpay/requests.rs similarity index 77% rename from crates/router/src/connector/worldpay/requests.rs rename to crates/hyperswitch_connectors/src/connectors/worldpay/requests.rs index 301ae64946d1..b0fa85a64c36 100644 --- a/crates/router/src/connector/worldpay/requests.rs +++ b/crates/hyperswitch_connectors/src/connectors/worldpay/requests.rs @@ -1,5 +1,101 @@ use masking::Secret; use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorldpayPaymentsRequest { + pub transaction_reference: String, + pub merchant: Merchant, + pub instruction: Instruction, + #[serde(skip_serializing_if = "Option::is_none")] + pub customer: Option, +} + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Merchant { + pub entity: Secret, + #[serde(skip_serializing_if = "Option::is_none")] + pub mcc: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub payment_facilitator: Option, +} + +#[derive(Clone, Debug, PartialEq, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Instruction { + pub settlement: Option, + pub method: PaymentMethod, + pub payment_instrument: PaymentInstrument, + pub narrative: InstructionNarrative, + pub value: PaymentValue, + #[serde(skip_serializing_if = "Option::is_none")] + pub debt_repayment: Option, + #[serde(rename = "threeDS")] + pub three_ds: Option, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum PaymentInstrument { + Card(CardPayment), + CardToken(CardToken), + Googlepay(WalletPayment), + Applepay(WalletPayment), +} + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CardPayment { + #[serde(rename = "type")] + pub payment_type: PaymentType, + #[serde(skip_serializing_if = "Option::is_none")] + pub card_holder_name: Option>, + pub card_number: cards::CardNumber, + pub expiry_date: ExpiryDate, + #[serde(skip_serializing_if = "Option::is_none")] + pub billing_address: Option, + pub cvc: Secret, +} + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CardToken { + #[serde(rename = "type")] + pub payment_type: PaymentType, + pub href: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub cvc: Option>, +} + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct WalletPayment { + #[serde(rename = "type")] + pub payment_type: PaymentType, + pub wallet_token: Secret, + #[serde(skip_serializing_if = "Option::is_none")] + pub billing_address: Option, +} + +#[derive( + Clone, Copy, Debug, Eq, Default, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, +)] +#[serde(rename_all = "lowercase")] +pub enum PaymentType { + #[default] + Plain, + Token, + Encrypted, + Checkout, +} + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ExpiryDate { + pub month: Secret, + pub year: Secret, +} + #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct BillingAddress { @@ -17,17 +113,6 @@ pub struct BillingAddress { pub country_code: common_enums::CountryAlpha2, } -#[derive(Clone, Debug, PartialEq, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct WorldpayPaymentsRequest { - pub transaction_reference: String, - pub merchant: Merchant, - pub instruction: Instruction, - pub channel: Channel, - #[serde(skip_serializing_if = "Option::is_none")] - pub customer: Option, -} - #[derive( Clone, Copy, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, )] @@ -100,89 +185,61 @@ pub struct NetworkToken { #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct Instruction { - pub request_auto_settlement: RequestAutoSettlement, - pub narrative: InstructionNarrative, - pub value: PaymentValue, - pub payment_instrument: PaymentInstrument, - #[serde(skip_serializing_if = "Option::is_none")] - pub debt_repayment: Option, +pub struct AutoSettlement { + pub auto: bool, } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct RequestAutoSettlement { - pub enabled: bool, +pub struct ThreeDSRequest { + #[serde(rename = "type")] + pub three_ds_type: String, + pub mode: String, + pub device_data: ThreeDSRequestDeviceData, + pub challenge: ThreeDSRequestChallenge, } -#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct InstructionNarrative { - pub line1: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub line2: Option, +pub struct ThreeDSRequestDeviceData { + pub accept_header: String, + pub user_agent_header: String, + pub browser_language: Option, + pub browser_screen_width: Option, + pub browser_screen_height: Option, + pub browser_color_depth: Option, + pub time_zone: Option, + pub browser_java_enabled: Option, + pub browser_javascript_enabled: Option, + pub channel: Option, } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[serde(untagged)] -pub enum PaymentInstrument { - Card(CardPayment), - CardToken(CardToken), - Googlepay(WalletPayment), - Applepay(WalletPayment), +#[serde(rename_all = "lowercase")] +pub enum ThreeDSRequestChannel { + Browser, + Native, } -#[derive( - Clone, Copy, Debug, Eq, Default, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, -)] -pub enum PaymentType { - #[default] - #[serde(rename = "card/plain")] - Card, - #[serde(rename = "card/token")] - CardToken, - #[serde(rename = "card/wallet+googlepay")] - Googlepay, - #[serde(rename = "card/wallet+applepay")] - Applepay, -} - -#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct CardPayment { - #[serde(rename = "type")] - pub payment_type: PaymentType, - pub card_number: cards::CardNumber, - pub expiry_date: ExpiryDate, - #[serde(skip_serializing_if = "Option::is_none")] - pub card_holder_name: Option>, - #[serde(skip_serializing_if = "Option::is_none")] - pub billing_address: Option, - pub cvc: Secret, +pub struct ThreeDSRequestChallenge { + pub return_url: String, } #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CardToken { - #[serde(rename = "type")] - pub payment_type: PaymentType, - pub href: String, +#[serde(rename_all = "lowercase")] +pub enum PaymentMethod { + #[default] + Card, + ApplePay, + GooglePay, } #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct WalletPayment { - #[serde(rename = "type")] - pub payment_type: PaymentType, - pub wallet_token: Secret, - #[serde(skip_serializing_if = "Option::is_none")] - pub billing_address: Option, -} - -#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] -pub struct ExpiryDate { - pub month: Secret, - pub year: Secret, +pub struct InstructionNarrative { + pub line1: String, } #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] @@ -191,16 +248,6 @@ pub struct PaymentValue { pub currency: api_models::enums::Currency, } -#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Merchant { - pub entity: Secret, - #[serde(skip_serializing_if = "Option::is_none")] - pub mcc: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub payment_facilitator: Option, -} - #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct PaymentFacilitator { @@ -230,3 +277,10 @@ pub struct WorldpayPartialRequest { pub value: PaymentValue, pub reference: String, } + +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct WorldpayCompleteAuthorizationRequest { + #[serde(skip_serializing_if = "Option::is_none")] + pub collection_reference: Option, +} diff --git a/crates/hyperswitch_connectors/src/connectors/worldpay/response.rs b/crates/hyperswitch_connectors/src/connectors/worldpay/response.rs new file mode 100644 index 000000000000..2b090bf02ac3 --- /dev/null +++ b/crates/hyperswitch_connectors/src/connectors/worldpay/response.rs @@ -0,0 +1,447 @@ +use error_stack::ResultExt; +use hyperswitch_interfaces::errors; +use masking::Secret; +use serde::{Deserialize, Serialize}; +use url::Url; + +use super::requests::*; + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct WorldpayPaymentsResponse { + pub outcome: PaymentOutcome, + pub transaction_reference: Option, + #[serde(flatten)] + pub other_fields: Option, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum WorldpayPaymentResponseFields { + AuthorizedResponse(Box), + DDCResponse(DDCResponse), + FraudHighRisk(FraudHighRiskResponse), + RefusedResponse(RefusedResponse), + ThreeDsChallenged(ThreeDsChallengedResponse), +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct AuthorizedResponse { + pub payment_instrument: PaymentsResPaymentInstrument, + #[serde(skip_serializing_if = "Option::is_none")] + pub issuer: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub scheme: Option, + #[serde(rename = "_links", skip_serializing_if = "Option::is_none")] + pub links: Option, + #[serde(rename = "_actions")] + pub actions: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, + pub risk_factors: Option>, + pub fraud: Option, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct FraudHighRiskResponse { + pub score: f32, + pub reason: Vec, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RefusedResponse { + pub refusal_description: String, + pub refusal_code: String, + pub risk_factors: Option>, + pub fraud: Option, + #[serde(rename = "threeDS")] + pub three_ds: Option, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ThreeDsResponse { + pub outcome: String, + pub issuer_response: IssuerResponse, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ThreeDsChallengedResponse { + pub authentication: AuthenticationResponse, + pub challenge: ThreeDsChallenge, + #[serde(rename = "_actions")] + pub actions: CompleteThreeDsActionLink, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct AuthenticationResponse { + pub version: String, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct ThreeDsChallenge { + pub reference: String, + pub url: Url, + pub jwt: Secret, + pub payload: Secret, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct CompleteThreeDsActionLink { + #[serde(rename = "complete3dsChallenge")] + pub complete_three_ds_challenge: ActionLink, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum IssuerResponse { + Challenged, + Frictionless, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct DDCResponse { + pub device_data_collection: DDCToken, + #[serde(rename = "_actions")] + pub actions: DDCActionLink, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct DDCToken { + pub jwt: Secret, + pub url: Url, + pub bin: Secret, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct DDCActionLink { + #[serde(rename = "supply3dsDeviceData")] + supply_ddc_data: ActionLink, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum PaymentOutcome { + #[serde(alias = "authorized", alias = "Authorized")] + Authorized, + Refused, + SentForSettlement, + SentForRefund, + FraudHighRisk, + #[serde(alias = "3dsDeviceDataRequired")] + ThreeDsDeviceDataRequired, + SentForCancellation, + #[serde(alias = "3dsAuthenticationFailed")] + ThreeDsAuthenticationFailed, + SentForPartialRefund, + #[serde(alias = "3dsChallenged")] + ThreeDsChallenged, + #[serde(alias = "3dsUnavailable")] + ThreeDsUnavailable, +} + +impl std::fmt::Display for PaymentOutcome { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Authorized => write!(f, "authorized"), + Self::Refused => write!(f, "refused"), + Self::SentForSettlement => write!(f, "sentForSettlement"), + Self::SentForRefund => write!(f, "sentForRefund"), + Self::FraudHighRisk => write!(f, "fraudHighRisk"), + Self::ThreeDsDeviceDataRequired => write!(f, "3dsDeviceDataRequired"), + Self::SentForCancellation => write!(f, "sentForCancellation"), + Self::ThreeDsAuthenticationFailed => write!(f, "3dsAuthenticationFailed"), + Self::SentForPartialRefund => write!(f, "sentForPartialRefund"), + Self::ThreeDsChallenged => write!(f, "3dsChallenged"), + Self::ThreeDsUnavailable => write!(f, "3dsUnavailable"), + } + } +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct SelfLink { + #[serde(rename = "self")] + pub self_link: SelfLinkInner, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct SelfLinkInner { + pub href: String, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ActionLinks { + supply_3ds_device_data: Option, + settle_payment: Option, + partially_settle_payment: Option, + refund_payment: Option, + partiall_refund_payment: Option, + cancel_payment: Option, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct ActionLink { + pub href: String, + pub method: String, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct Fraud { + pub outcome: FraudOutcome, + pub score: f32, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum FraudOutcome { + LowRisk, + HighRisk, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct WorldpayEventResponse { + pub last_event: EventType, + #[serde(rename = "_links", skip_serializing_if = "Option::is_none")] + pub links: Option, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum EventType { + SentForAuthorization, + #[serde(alias = "Authorized")] + Authorized, + #[serde(alias = "Sent for Settlement")] + SentForSettlement, + Settled, + SettlementFailed, + Cancelled, + Error, + Expired, + Refused, + #[serde(alias = "Sent for Refund")] + SentForRefund, + Refunded, + RefundFailed, + #[serde(other)] + Unknown, +} + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct EventLinks { + #[serde(rename = "payments:events", skip_serializing_if = "Option::is_none")] + pub events: Option, +} + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct PaymentLink { + pub href: String, +} + +pub fn get_resource_id( + response: WorldpayPaymentsResponse, + connector_transaction_id: Option, + transform_fn: F, +) -> Result> +where + F: Fn(String) -> T, +{ + let optional_reference_id = response + .other_fields + .as_ref() + .and_then(|other_fields| match other_fields { + WorldpayPaymentResponseFields::AuthorizedResponse(res) => res + .links + .as_ref() + .and_then(|link| link.self_link.href.rsplit_once('/').map(|(_, h)| h)), + WorldpayPaymentResponseFields::DDCResponse(res) => { + res.actions.supply_ddc_data.href.split('/').nth_back(1) + } + WorldpayPaymentResponseFields::ThreeDsChallenged(res) => res + .actions + .complete_three_ds_challenge + .href + .split('/') + .nth_back(1), + WorldpayPaymentResponseFields::FraudHighRisk(_) + | WorldpayPaymentResponseFields::RefusedResponse(_) => None, + }) + .map(|href| { + urlencoding::decode(href) + .map(|s| transform_fn(s.into_owned())) + .change_context(errors::ConnectorError::ResponseHandlingFailed) + }) + .transpose()?; + optional_reference_id + .or_else(|| connector_transaction_id.map(transform_fn)) + .ok_or_else(|| { + errors::ConnectorError::MissingRequiredField { + field_name: "_links.self.href", + } + .into() + }) +} + +pub struct ResponseIdStr { + pub id: String, +} + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Issuer { + pub authorization_code: Secret, +} + +impl Issuer { + pub fn new(code: String) -> Self { + Self { + authorization_code: Secret::new(code), + } + } +} + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PaymentsResPaymentInstrument { + #[serde(rename = "type")] + pub payment_instrument_type: String, + pub card_bin: Option, + pub last_four: Option, + pub expiry_date: Option, + pub card_brand: Option, + pub funding_type: Option, + pub category: Option, + pub issuer_name: Option, + pub payment_account_reference: Option, +} + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RiskFactorsInner { + #[serde(rename = "type")] + pub risk_type: RiskType, + #[serde(skip_serializing_if = "Option::is_none")] + pub detail: Option, + pub risk: Risk, +} + +impl RiskFactorsInner { + pub fn new(risk_type: RiskType, risk: Risk) -> Self { + Self { + risk_type, + detail: None, + risk, + } + } +} + +#[derive( + Clone, Copy, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, +)] +#[serde(rename_all = "camelCase")] +pub enum RiskType { + #[default] + Avs, + Cvc, + RiskProfile, +} + +#[derive( + Clone, Copy, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, +)] +#[serde(rename_all = "lowercase")] +pub enum Detail { + #[default] + Address, + Postcode, +} + +#[derive( + Clone, Copy, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, +)] +#[serde(rename_all = "camelCase")] +pub enum Risk { + #[default] + NotChecked, + NotMatched, + NotSupplied, + VerificationFailed, +} + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct PaymentsResponseScheme { + pub reference: String, +} + +impl PaymentsResponseScheme { + pub fn new(reference: String) -> Self { + Self { reference } + } +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct WorldpayErrorResponse { + pub error_name: String, + pub message: String, + pub validation_errors: Option, +} + +impl WorldpayErrorResponse { + pub fn default(status_code: u16) -> Self { + match status_code { + code @ 404 => Self { + error_name: format!("{} Not found", code), + message: "Resource not found".to_string(), + validation_errors: None, + }, + code => Self { + error_name: code.to_string(), + message: "Unknown error".to_string(), + validation_errors: None, + }, + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct WorldpayWebhookTransactionId { + pub event_details: EventDetails, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct EventDetails { + pub transaction_reference: String, + #[serde(rename = "type")] + pub event_type: EventType, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct WorldpayWebhookEventType { + pub event_id: String, + pub event_timestamp: String, + pub event_details: EventDetails, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub enum WorldpayWebhookStatus { + SentForSettlement, + Authorized, + SentForAuthorization, + Cancelled, + Error, + Expired, + Refused, + SentForRefund, + RefundFailed, +} diff --git a/crates/hyperswitch_connectors/src/connectors/worldpay/transformers.rs b/crates/hyperswitch_connectors/src/connectors/worldpay/transformers.rs new file mode 100644 index 000000000000..daaa095c3149 --- /dev/null +++ b/crates/hyperswitch_connectors/src/connectors/worldpay/transformers.rs @@ -0,0 +1,579 @@ +use std::collections::HashMap; + +use api_models::payments::Address; +use base64::Engine; +use common_enums::enums; +use common_utils::{ + consts::BASE64_ENGINE, errors::CustomResult, ext_traits::OptionExt, pii, types::MinorUnit, +}; +use error_stack::ResultExt; +use hyperswitch_domain_models::{ + payment_method_data::{PaymentMethodData, WalletData}, + router_data::{ConnectorAuthType, ErrorResponse, RouterData}, + router_flow_types::Authorize, + router_request_types::{PaymentsAuthorizeData, ResponseId}, + router_response_types::{PaymentsResponseData, RedirectForm}, + types, +}; +use hyperswitch_interfaces::{api, errors}; +use masking::{ExposeInterface, PeekInterface, Secret}; +use serde::{Deserialize, Serialize}; + +use super::{requests::*, response::*}; +use crate::{ + types::ResponseRouterData, + utils::{self, AddressData, ForeignTryFrom, PaymentsAuthorizeRequestData, RouterData as _}, +}; + +#[derive(Debug, Serialize)] +pub struct WorldpayRouterData { + amount: i64, + router_data: T, +} +impl TryFrom<(&api::CurrencyUnit, enums::Currency, MinorUnit, T)> for WorldpayRouterData { + type Error = error_stack::Report; + fn try_from( + (_currency_unit, _currency, minor_amount, item): ( + &api::CurrencyUnit, + enums::Currency, + MinorUnit, + T, + ), + ) -> Result { + Ok(Self { + amount: minor_amount.get_amount_as_i64(), + router_data: item, + }) + } +} + +/// Worldpay's unique reference ID for a request +pub const WP_CORRELATION_ID: &str = "WP-CorrelationId"; + +#[derive(Debug, Default, Serialize, Deserialize)] +pub struct WorldpayConnectorMetadataObject { + pub merchant_name: Option>, +} + +impl TryFrom<&Option> for WorldpayConnectorMetadataObject { + type Error = error_stack::Report; + fn try_from(meta_data: &Option) -> Result { + let metadata: Self = utils::to_connector_meta_from_secret::(meta_data.clone()) + .change_context(errors::ConnectorError::InvalidConnectorConfig { + config: "metadata", + })?; + Ok(metadata) + } +} + +fn fetch_payment_instrument( + payment_method: PaymentMethodData, + billing_address: Option<&Address>, +) -> CustomResult { + match payment_method { + PaymentMethodData::Card(card) => Ok(PaymentInstrument::Card(CardPayment { + payment_type: PaymentType::Plain, + expiry_date: ExpiryDate { + month: utils::CardData::get_expiry_month_as_i8(&card)?, + year: utils::CardData::get_expiry_year_as_i32(&card)?, + }, + card_number: card.card_number, + cvc: card.card_cvc, + card_holder_name: billing_address.and_then(|address| address.get_optional_full_name()), + billing_address: if let Some(address) = + billing_address.and_then(|addr| addr.address.clone()) + { + Some(BillingAddress { + address1: address.line1, + address2: address.line2, + address3: address.line3, + city: address.city, + state: address.state, + postal_code: address.zip.get_required_value("zip").change_context( + errors::ConnectorError::MissingRequiredField { field_name: "zip" }, + )?, + country_code: address + .country + .get_required_value("country_code") + .change_context(errors::ConnectorError::MissingRequiredField { + field_name: "country_code", + })?, + }) + } else { + None + }, + })), + PaymentMethodData::Wallet(wallet) => match wallet { + WalletData::GooglePay(data) => Ok(PaymentInstrument::Googlepay(WalletPayment { + payment_type: PaymentType::Encrypted, + wallet_token: Secret::new(data.tokenization_data.token), + ..WalletPayment::default() + })), + WalletData::ApplePay(data) => Ok(PaymentInstrument::Applepay(WalletPayment { + payment_type: PaymentType::Encrypted, + wallet_token: Secret::new(data.payment_data), + ..WalletPayment::default() + })), + WalletData::AliPayQr(_) + | WalletData::AliPayRedirect(_) + | WalletData::AliPayHkRedirect(_) + | WalletData::MomoRedirect(_) + | WalletData::KakaoPayRedirect(_) + | WalletData::GoPayRedirect(_) + | WalletData::GcashRedirect(_) + | WalletData::ApplePayRedirect(_) + | WalletData::ApplePayThirdPartySdk(_) + | WalletData::DanaRedirect {} + | WalletData::GooglePayRedirect(_) + | WalletData::GooglePayThirdPartySdk(_) + | WalletData::MbWayRedirect(_) + | WalletData::MobilePayRedirect(_) + | WalletData::PaypalRedirect(_) + | WalletData::PaypalSdk(_) + | WalletData::Paze(_) + | WalletData::SamsungPay(_) + | WalletData::TwintRedirect {} + | WalletData::VippsRedirect {} + | WalletData::TouchNGoRedirect(_) + | WalletData::WeChatPayRedirect(_) + | WalletData::CashappQr(_) + | WalletData::SwishQr(_) + | WalletData::WeChatPayQr(_) + | WalletData::Mifinity(_) => Err(errors::ConnectorError::NotImplemented( + utils::get_unimplemented_payment_method_error_message("worldpay"), + ) + .into()), + }, + PaymentMethodData::PayLater(_) + | PaymentMethodData::BankRedirect(_) + | PaymentMethodData::BankDebit(_) + | PaymentMethodData::BankTransfer(_) + | PaymentMethodData::Crypto(_) + | PaymentMethodData::MandatePayment + | PaymentMethodData::Reward + | PaymentMethodData::RealTimePayment(_) + | PaymentMethodData::Upi(_) + | PaymentMethodData::Voucher(_) + | PaymentMethodData::CardRedirect(_) + | PaymentMethodData::GiftCard(_) + | PaymentMethodData::OpenBanking(_) + | PaymentMethodData::CardToken(_) + | PaymentMethodData::NetworkToken(_) + | PaymentMethodData::CardDetailsForNetworkTransactionId(_) => { + Err(errors::ConnectorError::NotImplemented( + utils::get_unimplemented_payment_method_error_message("worldpay"), + ) + .into()) + } + } +} + +impl TryFrom<(enums::PaymentMethod, Option)> for PaymentMethod { + type Error = error_stack::Report; + fn try_from( + src: (enums::PaymentMethod, Option), + ) -> Result { + match (src.0, src.1) { + (enums::PaymentMethod::Card, _) => Ok(Self::Card), + (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"), + ) + .into()), + } + } +} + +impl + TryFrom<( + &WorldpayRouterData<&RouterData>, + &Secret, + )> for WorldpayPaymentsRequest +{ + type Error = error_stack::Report; + + fn try_from( + req: ( + &WorldpayRouterData< + &RouterData, + >, + &Secret, + ), + ) -> Result { + let (item, entity_id) = req; + let worldpay_connector_metadata_object: WorldpayConnectorMetadataObject = + WorldpayConnectorMetadataObject::try_from(&item.router_data.connector_meta_data)?; + let merchant_name = worldpay_connector_metadata_object.merchant_name.ok_or( + errors::ConnectorError::InvalidConnectorConfig { + config: "metadata.merchant_name", + }, + )?; + let three_ds = match item.router_data.auth_type { + enums::AuthenticationType::ThreeDs => { + let browser_info = item + .router_data + .request + .browser_info + .clone() + .get_required_value("browser_info") + .change_context(errors::ConnectorError::MissingRequiredField { + field_name: "browser_info", + })?; + let accept_header = browser_info + .accept_header + .get_required_value("accept_header") + .change_context(errors::ConnectorError::MissingRequiredField { + field_name: "accept_header", + })?; + let user_agent_header = browser_info + .user_agent + .get_required_value("user_agent") + .change_context(errors::ConnectorError::MissingRequiredField { + field_name: "user_agent", + })?; + Some(ThreeDSRequest { + three_ds_type: "integrated".to_string(), + mode: "always".to_string(), + device_data: ThreeDSRequestDeviceData { + accept_header, + user_agent_header, + browser_language: browser_info.language.clone(), + browser_screen_width: browser_info.screen_width, + browser_screen_height: browser_info.screen_height, + browser_color_depth: browser_info + .color_depth + .map(|depth| depth.to_string()), + time_zone: browser_info.time_zone.map(|tz| tz.to_string()), + browser_java_enabled: browser_info.java_enabled, + browser_javascript_enabled: browser_info.java_script_enabled, + channel: Some(ThreeDSRequestChannel::Browser), + }, + challenge: ThreeDSRequestChallenge { + return_url: item.router_data.request.get_complete_authorize_url()?, + }, + }) + } + _ => None, + }; + Ok(Self { + instruction: Instruction { + settlement: item + .router_data + .request + .capture_method + .map(|capture_method| AutoSettlement { + auto: capture_method == enums::CaptureMethod::Automatic, + }), + 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(), + )?, + narrative: InstructionNarrative { + line1: merchant_name.expose(), + }, + value: PaymentValue { + amount: item.amount, + currency: item.router_data.request.currency, + }, + debt_repayment: None, + three_ds, + }, + merchant: Merchant { + entity: entity_id.clone(), + ..Default::default() + }, + transaction_reference: item.router_data.connector_request_reference_id.clone(), + customer: None, + }) + } +} + +pub struct WorldpayAuthType { + pub(super) api_key: Secret, + pub(super) entity_id: Secret, +} + +impl TryFrom<&ConnectorAuthType> for WorldpayAuthType { + type Error = error_stack::Report; + fn try_from(auth_type: &ConnectorAuthType) -> Result { + match auth_type { + // TODO: Remove this later, kept purely for backwards compatibility + ConnectorAuthType::BodyKey { api_key, key1 } => { + let auth_key = format!("{}:{}", key1.peek(), api_key.peek()); + let auth_header = format!("Basic {}", BASE64_ENGINE.encode(auth_key)); + Ok(Self { + api_key: Secret::new(auth_header), + entity_id: Secret::new("default".to_string()), + }) + } + ConnectorAuthType::SignatureKey { + api_key, + key1, + api_secret, + } => { + let auth_key = format!("{}:{}", key1.peek(), api_key.peek()); + let auth_header = format!("Basic {}", BASE64_ENGINE.encode(auth_key)); + Ok(Self { + api_key: Secret::new(auth_header), + entity_id: api_secret.clone(), + }) + } + _ => Err(errors::ConnectorError::FailedToObtainAuthType)?, + } + } +} + +impl From for enums::AttemptStatus { + fn from(item: PaymentOutcome) -> Self { + match item { + PaymentOutcome::Authorized => Self::Authorized, + PaymentOutcome::SentForSettlement => Self::CaptureInitiated, + PaymentOutcome::ThreeDsDeviceDataRequired => Self::DeviceDataCollectionPending, + PaymentOutcome::ThreeDsAuthenticationFailed => Self::AuthenticationFailed, + PaymentOutcome::ThreeDsChallenged => Self::AuthenticationPending, + PaymentOutcome::SentForCancellation => Self::VoidInitiated, + PaymentOutcome::SentForPartialRefund | PaymentOutcome::SentForRefund => { + Self::AutoRefunded + } + PaymentOutcome::Refused | PaymentOutcome::FraudHighRisk => Self::Failure, + PaymentOutcome::ThreeDsUnavailable => Self::AuthenticationFailed, + } + } +} + +impl From<&EventType> for enums::AttemptStatus { + fn from(value: &EventType) -> Self { + match value { + EventType::SentForAuthorization => Self::Authorizing, + EventType::SentForSettlement => Self::CaptureInitiated, + EventType::Settled => Self::Charged, + EventType::Authorized => Self::Authorized, + EventType::Refused | EventType::SettlementFailed => Self::Failure, + EventType::Cancelled + | EventType::SentForRefund + | EventType::RefundFailed + | EventType::Refunded + | EventType::Error + | EventType::Expired + | EventType::Unknown => Self::Pending, + } + } +} + +impl From for enums::RefundStatus { + fn from(value: EventType) -> Self { + match value { + EventType::Refunded | EventType::SentForRefund => Self::Success, + EventType::RefundFailed => Self::Failure, + EventType::Authorized + | EventType::Cancelled + | EventType::Settled + | EventType::Refused + | EventType::Error + | EventType::SentForSettlement + | EventType::SentForAuthorization + | EventType::SettlementFailed + | EventType::Expired + | EventType::Unknown => Self::Pending, + } + } +} + +impl + ForeignTryFrom<( + ResponseRouterData, + Option, + )> for RouterData +{ + type Error = error_stack::Report; + fn foreign_try_from( + item: ( + ResponseRouterData, + Option, + ), + ) -> Result { + let (router_data, optional_correlation_id) = item; + 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, None) + } + WorldpayPaymentResponseFields::DDCResponse(res) => ( + None, + Some(RedirectForm::WorldpayDDCForm { + endpoint: res.device_data_collection.url.clone(), + method: common_utils::request::Method::Post, + collection_id: Some("SessionId".to_string()), + form_fields: HashMap::from([ + ( + "Bin".to_string(), + res.device_data_collection.bin.clone().expose(), + ), + ( + "JWT".to_string(), + res.device_data_collection.jwt.clone().expose(), + ), + ]), + }), + None, + ), + WorldpayPaymentResponseFields::ThreeDsChallenged(res) => ( + None, + Some(RedirectForm::Form { + endpoint: res.challenge.url.to_string(), + method: common_utils::request::Method::Post, + form_fields: HashMap::from([( + "JWT".to_string(), + res.challenge.jwt.clone().expose(), + )]), + }), + None, + ), + WorldpayPaymentResponseFields::RefusedResponse(res) => ( + None, + None, + Some((res.refusal_code.clone(), res.refusal_description.clone())), + ), + WorldpayPaymentResponseFields::FraudHighRisk(_) => (None, None, None), + }) + .unwrap_or((None, None, None)); + let worldpay_status = router_data.response.outcome.clone(); + 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".to_string()), + _ => None, + }; + let status = enums::AttemptStatus::from(worldpay_status.clone()); + let response = match (optional_error_message, error) { + (None, None) => Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::foreign_try_from(( + router_data.response, + optional_correlation_id.clone(), + ))?, + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(None), + connector_metadata: None, + network_txn_id: None, + connector_response_reference_id: optional_correlation_id.clone(), + incremental_authorization_allowed: None, + charge_id: None, + }), + (Some(reason), _) => Err(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(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, + response, + ..router_data.data + }) + } +} + +impl TryFrom<(&types::PaymentsCaptureRouterData, MinorUnit)> for WorldpayPartialRequest { + type Error = error_stack::Report; + fn try_from(req: (&types::PaymentsCaptureRouterData, MinorUnit)) -> Result { + let (item, amount) = req; + Ok(Self { + reference: item.payment_id.clone().replace("_", "-"), + value: PaymentValue { + amount: amount.get_amount_as_i64(), + currency: item.request.currency, + }, + }) + } +} + +impl TryFrom<(&types::RefundsRouterData, MinorUnit)> for WorldpayPartialRequest { + type Error = error_stack::Report; + fn try_from(req: (&types::RefundsRouterData, MinorUnit)) -> Result { + let (item, amount) = req; + Ok(Self { + reference: item.request.refund_id.clone().replace("_", "-"), + value: PaymentValue { + amount: amount.get_amount_as_i64(), + currency: item.request.currency, + }, + }) + } +} + +impl TryFrom for WorldpayEventResponse { + type Error = error_stack::Report; + fn try_from(event: WorldpayWebhookEventType) -> Result { + Ok(Self { + last_event: event.event_details.event_type, + links: None, + }) + } +} + +impl ForeignTryFrom<(WorldpayPaymentsResponse, Option)> for ResponseIdStr { + type Error = error_stack::Report; + fn foreign_try_from( + item: (WorldpayPaymentsResponse, Option), + ) -> Result { + get_resource_id(item.0, item.1, |id| Self { id }) + } +} + +impl ForeignTryFrom<(WorldpayPaymentsResponse, Option)> for ResponseId { + type Error = error_stack::Report; + fn foreign_try_from( + item: (WorldpayPaymentsResponse, Option), + ) -> Result { + get_resource_id(item.0, item.1, Self::ConnectorTransactionId) + } +} + +impl TryFrom<&types::PaymentsCompleteAuthorizeRouterData> for WorldpayCompleteAuthorizationRequest { + type Error = error_stack::Report; + fn try_from(item: &types::PaymentsCompleteAuthorizeRouterData) -> Result { + let params = item + .request + .redirect_response + .as_ref() + .and_then(|redirect_response| redirect_response.params.as_ref()) + .ok_or(errors::ConnectorError::ResponseDeserializationFailed)?; + serde_urlencoded::from_str::(params.peek()) + .change_context(errors::ConnectorError::ResponseDeserializationFailed) + } +} 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 2d522dbdf1bd..a90b10fbd866 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 799753fd52c1..166e71304835 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"), ))?, }; @@ -613,11 +624,14 @@ fn get_item_object( name: data.product_name.clone(), quantity: data.quantity, price: utils::to_currency_base_unit_with_zero_decimal_check( - data.amount, + data.amount.get_amount_as_i64(), // This should be changed to MinorUnit when we implement amount conversion for this connector. Additionally, the function get_amount_as_i64() should be avoided in the future. item.request.currency, )?, line_amount_total: (f64::from(data.quantity) - * utils::to_currency_base_unit_asf64(data.amount, item.request.currency)?) + * utils::to_currency_base_unit_asf64( + data.amount.get_amount_as_i64(), // This should be changed to MinorUnit when we implement amount conversion for this connector. Additionally, the function get_amount_as_i64() should be avoided in the future. + item.request.currency, + )?) .to_string(), }) }) @@ -625,7 +639,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 +683,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 +713,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 +744,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 +879,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 +907,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 +924,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,10 +940,10 @@ fn get_zen_response( } else { None }; - let payment_response_data = types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId(response.id.clone()), - redirection_data, - mandate_reference: None, + let payment_response_data = PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(response.id.clone()), + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -958,12 +953,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,23 +971,23 @@ 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, - redirection_data, - mandate_reference: None, + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::NoResponseId, + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -1054,12 +1049,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 +1067,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 +1086,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/router/src/connector/zsl.rs b/crates/hyperswitch_connectors/src/connectors/zsl.rs similarity index 64% rename from crates/router/src/connector/zsl.rs rename to crates/hyperswitch_connectors/src/connectors/zsl.rs index d2341a510e11..0a833a1f84ad 100644 --- a/crates/router/src/connector/zsl.rs +++ b/crates/hyperswitch_connectors/src/connectors/zsl.rs @@ -2,30 +2,49 @@ pub mod transformers; use std::fmt::Debug; -use common_utils::ext_traits::ValueExt; -use diesel_models::enums; +use api_models::webhooks::{IncomingWebhookEvent, ObjectReferenceId}; +use common_enums::enums; +use common_utils::{ + errors::CustomResult, + ext_traits::{BytesExt, ValueExt}, + request::{Method, Request, RequestBuilder, RequestContent}, +}; use error_stack::ResultExt; -use masking::{ExposeInterface, Secret}; -use transformers as zsl; - -use crate::{ - configs::settings, - connector::utils as connector_utils, - core::errors::{self, CustomResult}, - events::connector_api_logs::ConnectorEvent, - headers, - services::{ - self, - request::{self}, - ConnectorIntegration, ConnectorValidation, +use hyperswitch_domain_models::{ + api::ApplicationResponse, + 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}, - transformers::ForeignFrom, - ErrorResponse, RequestContent, Response, + PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData, + PaymentsSessionRouterData, PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData, + TokenizationRouterData, }, - utils::BytesExt, +}; +use hyperswitch_interfaces::{ + api::{self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorValidation}, + configs::Connectors, + errors, + events::connector_api_logs::ConnectorEvent, + types::{self, Response}, + webhooks::{IncomingWebhook, IncomingWebhookRequestDetails}, +}; +use masking::{ExposeInterface, Secret}; +use transformers::{self as zsl, get_status}; + +use crate::{ + constants::headers, + types::{RefreshTokenRouterData, ResponseRouterData}, + utils::construct_not_supported_error_report, }; #[derive(Debug, Clone)] @@ -50,9 +69,9 @@ where { fn build_headers( &self, - _req: &types::RouterData, - _connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + _req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { let header = vec![( headers::CONTENT_TYPE.to_string(), self.get_content_type().to_string().into(), @@ -74,7 +93,7 @@ impl ConnectorCommon for Zsl { "application/x-www-form-urlencoded" } - fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { + fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str { connectors.zsl.base_url.as_ref() } @@ -113,9 +132,10 @@ impl ConnectorValidation for Zsl { enums::CaptureMethod::Automatic => Ok(()), enums::CaptureMethod::Manual | enums::CaptureMethod::ManualMultiple - | enums::CaptureMethod::Scheduled => Err( - connector_utils::construct_not_supported_error_report(capture_method, self.id()), - ), + | enums::CaptureMethod::Scheduled => Err(construct_not_supported_error_report( + capture_method, + self.id(), + )), } } @@ -124,14 +144,12 @@ impl ConnectorValidation for Zsl { } } -impl ConnectorIntegration - for Zsl -{ +impl ConnectorIntegration for Zsl { 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) } @@ -141,16 +159,16 @@ impl ConnectorIntegration CustomResult { Ok(format!("{}ecp", self.base_url(connectors))) } fn get_request_body( &self, - req: &types::PaymentsAuthorizeRouterData, - _connectors: &settings::Connectors, + req: &PaymentsAuthorizeRouterData, + _connectors: &Connectors, ) -> CustomResult { let connector_router_data = zsl::ZslRouterData::try_from(( &self.get_currency_unit(), @@ -164,12 +182,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, )?) @@ -186,17 +204,17 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response = serde_urlencoded::from_bytes::(&res.response) .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; event_builder.map(|i: &mut ConnectorEvent| 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, @@ -220,15 +238,13 @@ impl ConnectorIntegration - for Zsl -{ +impl ConnectorIntegration for Zsl { fn handle_response( &self, - data: &types::PaymentsSyncRouterData, + data: &PaymentsSyncRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: zsl::ZslWebhookResponse = res .response .parse_struct("ZslWebhookResponse") @@ -237,7 +253,7 @@ impl ConnectorIntegration - for Zsl -{ +impl ConnectorIntegration for Zsl { fn build_request( &self, - _req: &types::PaymentsSessionRouterData, - _connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + _req: &PaymentsSessionRouterData, + _connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Err(errors::ConnectorError::NotSupported { message: "Session flow".to_owned(), connector: "Zsl", @@ -261,18 +275,14 @@ impl ConnectorIntegration for Zsl +impl ConnectorIntegration + for Zsl { fn build_request( &self, - _req: &types::TokenizationRouterData, - _connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + _req: &TokenizationRouterData, + _connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Err(errors::ConnectorError::NotSupported { message: "PaymentMethod Tokenization flow ".to_owned(), connector: "Zsl", @@ -281,14 +291,12 @@ impl } } -impl ConnectorIntegration - for Zsl -{ +impl ConnectorIntegration for Zsl { fn build_request( &self, - _req: &types::RefreshTokenRouterData, - _connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + _req: &RefreshTokenRouterData, + _connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Err(errors::ConnectorError::NotSupported { message: "AccessTokenAuth flow".to_owned(), connector: "Zsl", @@ -297,22 +305,12 @@ impl ConnectorIntegration for Zsl -{ +impl ConnectorIntegration for Zsl { 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::NotSupported { message: "SetupMandate flow".to_owned(), connector: "Zsl", @@ -321,14 +319,12 @@ impl } } -impl ConnectorIntegration - for Zsl -{ +impl ConnectorIntegration for Zsl { fn build_request( &self, - _req: &types::PaymentsCaptureRouterData, - _connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + _req: &PaymentsCaptureRouterData, + _connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Err(errors::ConnectorError::NotSupported { message: "Capture flow".to_owned(), connector: "Zsl", @@ -337,14 +333,12 @@ impl ConnectorIntegration - for Zsl -{ +impl ConnectorIntegration for Zsl { fn build_request( &self, - _req: &types::PaymentsCancelRouterData, - _connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + _req: &PaymentsCancelRouterData, + _connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Err(errors::ConnectorError::NotSupported { message: "Void flow ".to_owned(), connector: "Zsl", @@ -353,12 +347,12 @@ impl ConnectorIntegration for Zsl { +impl ConnectorIntegration for Zsl { fn build_request( &self, - _req: &types::RefundsRouterData, - _connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + _req: &RefundsRouterData, + _connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Err(errors::ConnectorError::NotSupported { message: "Refund flow".to_owned(), connector: "Zsl", @@ -367,12 +361,12 @@ impl ConnectorIntegration for Zsl { +impl ConnectorIntegration for Zsl { fn build_request( &self, - _req: &types::RefundSyncRouterData, - _connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + _req: &RefundSyncRouterData, + _connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Err(errors::ConnectorError::NotSupported { message: "Rsync flow ".to_owned(), connector: "Zsl", @@ -382,33 +376,31 @@ impl ConnectorIntegration, - ) -> CustomResult { + request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { let notif = get_webhook_object_from_body(request.body) .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?; - Ok(api_models::webhooks::ObjectReferenceId::PaymentId( + Ok(ObjectReferenceId::PaymentId( api_models::payments::PaymentIdType::PaymentAttemptId(notif.mer_ref), )) } fn get_webhook_event_type( &self, - request: &api::IncomingWebhookRequestDetails<'_>, - ) -> CustomResult { + request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { let notif = get_webhook_object_from_body(request.body) .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?; - Ok(api_models::webhooks::IncomingWebhookEvent::foreign_from( - notif.status, - )) + Ok(get_status(notif.status)) } fn get_webhook_resource_object( &self, - request: &api::IncomingWebhookRequestDetails<'_>, + request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { let response = get_webhook_object_from_body(request.body) .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?; @@ -417,14 +409,14 @@ impl api::IncomingWebhook for Zsl { 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: common_utils::crypto::Encryptable>, _connector_label: &str, ) -> CustomResult { let connector_account_details = connector_account_details - .parse_value::("ConnectorAuthType") + .parse_value::("ConnectorAuthType") .change_context_lazy(|| errors::ConnectorError::WebhookSourceVerificationFailed)?; let auth_type = zsl::ZslAuthType::try_from(&connector_account_details)?; let key = auth_type.api_key.expose(); @@ -449,12 +441,9 @@ impl api::IncomingWebhook for Zsl { fn get_webhook_api_response( &self, - _request: &api::IncomingWebhookRequestDetails<'_>, - ) -> CustomResult, errors::ConnectorError> - { - Ok(services::api::ApplicationResponse::TextPlain( - "CALLBACK-OK".to_string(), - )) + _request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult, errors::ConnectorError> { + Ok(ApplicationResponse::TextPlain("CALLBACK-OK".to_string())) } } diff --git a/crates/router/src/connector/zsl/transformers.rs b/crates/hyperswitch_connectors/src/connectors/zsl/transformers.rs similarity index 84% rename from crates/router/src/connector/zsl/transformers.rs rename to crates/hyperswitch_connectors/src/connectors/zsl/transformers.rs index c8758f5322ca..8db75fe61aab 100644 --- a/crates/router/src/connector/zsl/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/zsl/transformers.rs @@ -1,18 +1,27 @@ use std::collections::HashMap; use base64::Engine; -use common_utils::{crypto::GenerateDigest, date_time, pii::Email}; +use common_enums::enums; +use common_utils::{crypto::GenerateDigest, date_time, pii::Email, request::Method}; use error_stack::ResultExt; +use hyperswitch_domain_models::{ + payment_method_data::{BankTransferData, PaymentMethodData}, + router_data::{ConnectorAuthType, ErrorResponse, RouterData}, + router_request_types::{PaymentsSyncData, ResponseId}, + router_response_types::{PaymentsResponseData, RedirectForm}, + types, +}; +use hyperswitch_interfaces::{api, consts::NO_ERROR_CODE, errors}; use masking::{ExposeInterface, Secret}; use ring::digest; use serde::{Deserialize, Serialize}; use crate::{ - connector::utils::{self as connector_utils, PaymentsAuthorizeRequestData, RouterData}, - consts, - core::errors, - services, - types::{self, domain, storage::enums}, + types::ResponseRouterData, + utils::{ + get_amount_as_string, get_unimplemented_payment_method_error_message, + PaymentsAuthorizeRequestData, RouterData as _, + }, }; mod auth_error { @@ -27,17 +36,12 @@ pub struct ZslRouterData { pub router_data: T, } -impl TryFrom<(&types::api::CurrencyUnit, enums::Currency, i64, T)> for ZslRouterData { +impl TryFrom<(&api::CurrencyUnit, enums::Currency, i64, T)> for ZslRouterData { type Error = error_stack::Report; fn try_from( - (currency_unit, currency, txn_amount, item): ( - &types::api::CurrencyUnit, - enums::Currency, - i64, - T, - ), + (currency_unit, currency, txn_amount, item): (&api::CurrencyUnit, enums::Currency, i64, T), ) -> Result { - let amount = connector_utils::get_amount_as_string(currency_unit, txn_amount, currency)?; + let amount = get_amount_as_string(currency_unit, txn_amount, currency)?; Ok(Self { amount, router_data: item, @@ -50,11 +54,11 @@ pub struct ZslAuthType { pub(super) merchant_id: Secret, } -impl TryFrom<&types::ConnectorAuthType> for ZslAuthType { +impl TryFrom<&ConnectorAuthType> for ZslAuthType { 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_id: key1.clone(), }), @@ -139,58 +143,50 @@ impl TryFrom<&ZslRouterData<&types::PaymentsAuthorizeRouterData>> for ZslPayment item: &ZslRouterData<&types::PaymentsAuthorizeRouterData>, ) -> Result { let payment_method = match item.router_data.request.payment_method_data.clone() { - domain::PaymentMethodData::BankTransfer(bank_transfer_data) => { - match *bank_transfer_data { - domain::BankTransferData::LocalBankTransfer { bank_code } => Ok( - ZslPaymentMethods::LocalBankTransfer(LocalBankTransaferRequest { - bank_code, - pay_method: None, - }), - ), - domain::BankTransferData::AchBankTransfer { .. } - | domain::BankTransferData::SepaBankTransfer { .. } - | domain::BankTransferData::BacsBankTransfer { .. } - | domain::BankTransferData::MultibancoBankTransfer { .. } - | domain::BankTransferData::PermataBankTransfer { .. } - | domain::BankTransferData::BcaBankTransfer { .. } - | domain::BankTransferData::BniVaBankTransfer { .. } - | domain::BankTransferData::BriVaBankTransfer { .. } - | domain::BankTransferData::CimbVaBankTransfer { .. } - | domain::BankTransferData::DanamonVaBankTransfer { .. } - | domain::BankTransferData::MandiriVaBankTransfer { .. } - | domain::BankTransferData::Pix { .. } - | domain::BankTransferData::Pse {} => { - Err(errors::ConnectorError::NotImplemented( - connector_utils::get_unimplemented_payment_method_error_message( - item.router_data.connector.as_str(), - ), - )) - } - } - } - domain::PaymentMethodData::Card(_) - | domain::PaymentMethodData::CardRedirect(_) - | domain::PaymentMethodData::Wallet(_) - | domain::PaymentMethodData::PayLater(_) - | domain::PaymentMethodData::BankRedirect(_) - | domain::PaymentMethodData::BankDebit(_) - | domain::PaymentMethodData::Crypto(_) - | domain::PaymentMethodData::MandatePayment - | domain::PaymentMethodData::Reward - | domain::PaymentMethodData::RealTimePayment(_) - | domain::PaymentMethodData::Upi(_) - | domain::PaymentMethodData::Voucher(_) - | domain::PaymentMethodData::GiftCard(_) - | domain::PaymentMethodData::CardToken(_) - | domain::PaymentMethodData::NetworkToken(_) - | domain::PaymentMethodData::CardDetailsForNetworkTransactionId(_) - | domain::PaymentMethodData::OpenBanking(_) => { - Err(errors::ConnectorError::NotImplemented( - connector_utils::get_unimplemented_payment_method_error_message( + PaymentMethodData::BankTransfer(bank_transfer_data) => match *bank_transfer_data { + BankTransferData::LocalBankTransfer { bank_code } => Ok( + ZslPaymentMethods::LocalBankTransfer(LocalBankTransaferRequest { + bank_code, + pay_method: None, + }), + ), + BankTransferData::AchBankTransfer { .. } + | BankTransferData::SepaBankTransfer { .. } + | BankTransferData::BacsBankTransfer { .. } + | BankTransferData::MultibancoBankTransfer { .. } + | BankTransferData::PermataBankTransfer { .. } + | BankTransferData::BcaBankTransfer { .. } + | BankTransferData::BniVaBankTransfer { .. } + | BankTransferData::BriVaBankTransfer { .. } + | BankTransferData::CimbVaBankTransfer { .. } + | BankTransferData::DanamonVaBankTransfer { .. } + | BankTransferData::MandiriVaBankTransfer { .. } + | BankTransferData::Pix { .. } + | BankTransferData::Pse {} => Err(errors::ConnectorError::NotImplemented( + get_unimplemented_payment_method_error_message( item.router_data.connector.as_str(), ), - )) - } + )), + }, + PaymentMethodData::Card(_) + | PaymentMethodData::CardRedirect(_) + | PaymentMethodData::Wallet(_) + | PaymentMethodData::PayLater(_) + | PaymentMethodData::BankRedirect(_) + | PaymentMethodData::BankDebit(_) + | PaymentMethodData::Crypto(_) + | PaymentMethodData::MandatePayment + | PaymentMethodData::Reward + | PaymentMethodData::RealTimePayment(_) + | PaymentMethodData::Upi(_) + | PaymentMethodData::Voucher(_) + | PaymentMethodData::GiftCard(_) + | PaymentMethodData::CardToken(_) + | PaymentMethodData::NetworkToken(_) + | PaymentMethodData::CardDetailsForNetworkTransactionId(_) + | PaymentMethodData::OpenBanking(_) => Err(errors::ConnectorError::NotImplemented( + get_unimplemented_payment_method_error_message(item.router_data.connector.as_str()), + )), }?; let auth_type = ZslAuthType::try_from(&item.router_data.connector_auth_type)?; let key: Secret = auth_type.api_key; @@ -293,13 +289,12 @@ pub struct ZslPaymentsResponse { signature: Secret, } -impl - TryFrom> - for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData, + item: ResponseRouterData, ) -> Result { if item.response.status.eq("0") && !item.response.txn_url.is_empty() { let auth_type = ZslAuthType::try_from(&item.data.connector_auth_type)?; @@ -326,14 +321,14 @@ impl Ok(Self { status: enums::AttemptStatus::AuthenticationPending, // Redirect is always expected after success response - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::NoResponseId, - redirection_data: Some(services::RedirectForm::Form { + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::NoResponseId, + redirection_data: Box::new(Some(RedirectForm::Form { endpoint: redirect_url, - method: services::Method::Get, + method: Method::Get, form_fields: HashMap::new(), - }), - mandate_reference: None, + })), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.mer_ref.clone()), @@ -346,8 +341,8 @@ impl // When the signature check fails Ok(Self { status: enums::AttemptStatus::Failure, - response: Err(types::ErrorResponse { - code: consts::NO_ERROR_CODE.to_string(), + response: Err(ErrorResponse { + code: NO_ERROR_CODE.to_string(), message: auth_error::INVALID_SIGNATURE.to_string(), reason: Some(auth_error::INVALID_SIGNATURE.to_string()), status_code: item.http_code, @@ -362,7 +357,7 @@ impl ZslResponseStatus::try_from(item.response.status.clone())?.to_string(); Ok(Self { status: enums::AttemptStatus::Failure, - response: Err(types::ErrorResponse { + response: Err(ErrorResponse { code: item.response.status.clone(), message: error_reason.clone(), reason: Some(error_reason.clone()), @@ -398,34 +393,20 @@ pub struct ZslWebhookResponse { pub signature: Secret, } -impl types::transformers::ForeignFrom for api_models::webhooks::IncomingWebhookEvent { - fn foreign_from(status: String) -> Self { - match status.as_str() { - //any response with status != 0 are a failed deposit transaction - "0" => Self::PaymentIntentSuccess, - _ => Self::PaymentIntentFailure, - } +pub(crate) fn get_status(status: String) -> api_models::webhooks::IncomingWebhookEvent { + match status.as_str() { + //any response with status != 0 are a failed deposit transaction + "0" => api_models::webhooks::IncomingWebhookEvent::PaymentIntentSuccess, + _ => api_models::webhooks::IncomingWebhookEvent::PaymentIntentFailure, } } -impl - TryFrom< - types::ResponseRouterData< - F, - ZslWebhookResponse, - types::PaymentsSyncData, - types::PaymentsResponseData, - >, - > for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData< - F, - ZslWebhookResponse, - types::PaymentsSyncData, - types::PaymentsResponseData, - >, + item: ResponseRouterData, ) -> Result { let paid_amount = item .response @@ -447,12 +428,10 @@ impl Ok(Self { status, amount_captured: Some(paid_amount), - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId( - item.response.txn_id.clone(), - ), - redirection_data: None, - mandate_reference: None, + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(item.response.txn_id.clone()), + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.mer_ref.clone()), @@ -466,7 +445,7 @@ impl ZslResponseStatus::try_from(item.response.status.clone())?.to_string(); Ok(Self { status: enums::AttemptStatus::Failure, - response: Err(types::ErrorResponse { + response: Err(ErrorResponse { code: item.response.status.clone(), message: error_reason.clone(), reason: Some(error_reason.clone()), diff --git a/crates/hyperswitch_connectors/src/constants.rs b/crates/hyperswitch_connectors/src/constants.rs index 6c579977005d..48a32c180474 100644 --- a/crates/hyperswitch_connectors/src/constants.rs +++ b/crates/hyperswitch_connectors/src/constants.rs @@ -1,6 +1,8 @@ /// Header Constants pub(crate) mod headers { + pub(crate) const ACCEPT: &str = "Accept"; 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 +10,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"; @@ -21,4 +25,8 @@ pub(crate) mod headers { pub(crate) const X_VERSION: &str = "X-Version"; pub(crate) const X_API_KEY: &str = "X-Api-Key"; pub(crate) const CORRELATION_ID: &str = "Correlation-Id"; + pub(crate) const WP_API_VERSION: &str = "WP-Api-Version"; } + +/// Unsupported response type error message +pub const UNSUPPORTED_ERROR_MESSAGE: &str = "Unsupported response type"; diff --git a/crates/hyperswitch_connectors/src/default_implementations.rs b/crates/hyperswitch_connectors/src/default_implementations.rs index 1e411ded76f2..fe866d2af7c9 100644 --- a/crates/hyperswitch_connectors/src/default_implementations.rs +++ b/crates/hyperswitch_connectors/src/default_implementations.rs @@ -89,6 +89,7 @@ macro_rules! default_imp_for_authorize_session_token { } default_imp_for_authorize_session_token!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -98,21 +99,33 @@ default_imp_for_authorize_session_token!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Taxjar, connectors::Volt, connectors::Thunes, connectors::Tsys, - connectors::Worldline + connectors::Worldline, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); macro_rules! default_imp_for_calculate_tax { @@ -130,30 +143,43 @@ macro_rules! default_imp_for_calculate_tax { } default_imp_for_calculate_tax!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, + connectors::Fiuu, + connectors::Forte, + connectors::Globepay, connectors::Helcim, - connectors::Stax, - connectors::Square, - connectors::Novalnet, + connectors::Jpmorgan, connectors::Mollie, + connectors::Multisafepay, + connectors::Nexinets, connectors::Nexixpay, - connectors::Fiuu, - connectors::Globepay, - connectors::Worldline, + connectors::Novalnet, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, + connectors::Razorpay, + connectors::Shift4, + connectors::Stax, + connectors::Square, connectors::Thunes, connectors::Tsys, connectors::Volt, - connectors::Deutschebank + connectors::Worldline, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); macro_rules! default_imp_for_session_update { @@ -171,6 +197,7 @@ macro_rules! default_imp_for_session_update { } default_imp_for_session_update!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -179,18 +206,30 @@ default_imp_for_session_update!( connectors::Cryptopay, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, + connectors::Forte, connectors::Helcim, + connectors::Jpmorgan, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Mollie, + connectors::Multisafepay, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Fiuu, connectors::Globepay, connectors::Worldline, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl, connectors::Powertranz, connectors::Thunes, connectors::Tsys, @@ -213,6 +252,7 @@ macro_rules! default_imp_for_post_session_tokens { } default_imp_for_post_session_tokens!( + connectors::Airwallex, connectors::Bambora, connectors::Bitpay, connectors::Billwerk, @@ -221,23 +261,35 @@ default_imp_for_post_session_tokens!( connectors::Cryptopay, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Square, connectors::Fiserv, connectors::Fiservemea, + connectors::Forte, connectors::Helcim, + connectors::Jpmorgan, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Taxjar, connectors::Mollie, + connectors::Multisafepay, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Fiuu, connectors::Globepay, connectors::Worldline, + connectors::Worldpay, connectors::Powertranz, connectors::Thunes, connectors::Tsys, connectors::Deutschebank, - connectors::Volt + connectors::Volt, + connectors::Zen, + connectors::Zsl ); use crate::connectors; @@ -264,19 +316,29 @@ default_imp_for_complete_authorize!( connectors::Cryptopay, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, + connectors::Multisafepay, connectors::Novalnet, + connectors::Nexinets, + connectors::Payeezy, + connectors::Payu, + connectors::Razorpay, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen, + connectors::Zsl ); macro_rules! default_imp_for_incremental_authorization { @@ -295,6 +357,7 @@ macro_rules! default_imp_for_incremental_authorization { } default_imp_for_incremental_authorization!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -304,22 +367,34 @@ default_imp_for_incremental_authorization!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); macro_rules! default_imp_for_create_customer { @@ -338,6 +413,7 @@ macro_rules! default_imp_for_create_customer { } default_imp_for_create_customer!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -347,21 +423,33 @@ default_imp_for_create_customer!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Mollie, + connectors::Multisafepay, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, + connectors::Razorpay, + connectors::Shift4, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); macro_rules! default_imp_for_connector_redirect_response { @@ -390,20 +478,30 @@ default_imp_for_connector_redirect_response!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, + connectors::Multisafepay, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zsl ); macro_rules! default_imp_for_pre_processing_steps{ @@ -431,21 +529,32 @@ default_imp_for_pre_processing_steps!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); macro_rules! default_imp_for_post_processing_steps{ @@ -464,6 +573,7 @@ macro_rules! default_imp_for_post_processing_steps{ } default_imp_for_post_processing_steps!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -473,22 +583,34 @@ default_imp_for_post_processing_steps!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); macro_rules! default_imp_for_approve { @@ -507,6 +629,7 @@ macro_rules! default_imp_for_approve { } default_imp_for_approve!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -516,22 +639,34 @@ default_imp_for_approve!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); macro_rules! default_imp_for_reject { @@ -550,6 +685,7 @@ macro_rules! default_imp_for_reject { } default_imp_for_reject!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -559,22 +695,34 @@ default_imp_for_reject!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); macro_rules! default_imp_for_webhook_source_verification { @@ -593,6 +741,7 @@ macro_rules! default_imp_for_webhook_source_verification { } default_imp_for_webhook_source_verification!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -602,22 +751,34 @@ default_imp_for_webhook_source_verification!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); macro_rules! default_imp_for_accept_dispute { @@ -637,6 +798,7 @@ macro_rules! default_imp_for_accept_dispute { } default_imp_for_accept_dispute!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -646,22 +808,34 @@ default_imp_for_accept_dispute!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); macro_rules! default_imp_for_submit_evidence { @@ -680,6 +854,7 @@ macro_rules! default_imp_for_submit_evidence { } default_imp_for_submit_evidence!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -689,22 +864,34 @@ default_imp_for_submit_evidence!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); macro_rules! default_imp_for_defend_dispute { @@ -723,6 +910,7 @@ macro_rules! default_imp_for_defend_dispute { } default_imp_for_defend_dispute!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -732,22 +920,34 @@ default_imp_for_defend_dispute!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, + connectors::Jpmorgan, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); macro_rules! default_imp_for_file_upload { @@ -775,6 +975,7 @@ macro_rules! default_imp_for_file_upload { } default_imp_for_file_upload!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -784,22 +985,34 @@ default_imp_for_file_upload!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "payouts")] @@ -820,6 +1033,7 @@ macro_rules! default_imp_for_payouts_create { #[cfg(feature = "payouts")] default_imp_for_payouts_create!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -829,22 +1043,34 @@ default_imp_for_payouts_create!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "payouts")] @@ -865,6 +1091,7 @@ macro_rules! default_imp_for_payouts_retrieve { #[cfg(feature = "payouts")] default_imp_for_payouts_retrieve!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -874,22 +1101,34 @@ default_imp_for_payouts_retrieve!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "payouts")] @@ -910,6 +1149,7 @@ macro_rules! default_imp_for_payouts_eligibility { #[cfg(feature = "payouts")] default_imp_for_payouts_eligibility!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -919,22 +1159,34 @@ default_imp_for_payouts_eligibility!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "payouts")] @@ -955,6 +1207,7 @@ macro_rules! default_imp_for_payouts_fulfill { #[cfg(feature = "payouts")] default_imp_for_payouts_fulfill!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -964,22 +1217,34 @@ default_imp_for_payouts_fulfill!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "payouts")] @@ -1000,6 +1265,7 @@ macro_rules! default_imp_for_payouts_cancel { #[cfg(feature = "payouts")] default_imp_for_payouts_cancel!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -1009,22 +1275,34 @@ default_imp_for_payouts_cancel!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "payouts")] @@ -1045,6 +1323,7 @@ macro_rules! default_imp_for_payouts_quote { #[cfg(feature = "payouts")] default_imp_for_payouts_quote!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -1054,22 +1333,34 @@ default_imp_for_payouts_quote!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "payouts")] @@ -1090,6 +1381,7 @@ macro_rules! default_imp_for_payouts_recipient { #[cfg(feature = "payouts")] default_imp_for_payouts_recipient!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -1099,22 +1391,34 @@ default_imp_for_payouts_recipient!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "payouts")] @@ -1135,6 +1439,7 @@ macro_rules! default_imp_for_payouts_recipient_account { #[cfg(feature = "payouts")] default_imp_for_payouts_recipient_account!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -1144,22 +1449,34 @@ default_imp_for_payouts_recipient_account!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "frm")] @@ -1180,6 +1497,7 @@ macro_rules! default_imp_for_frm_sale { #[cfg(feature = "frm")] default_imp_for_frm_sale!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -1189,22 +1507,34 @@ default_imp_for_frm_sale!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "frm")] @@ -1225,6 +1555,7 @@ macro_rules! default_imp_for_frm_checkout { #[cfg(feature = "frm")] default_imp_for_frm_checkout!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -1234,22 +1565,34 @@ default_imp_for_frm_checkout!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "frm")] @@ -1270,6 +1613,7 @@ macro_rules! default_imp_for_frm_transaction { #[cfg(feature = "frm")] default_imp_for_frm_transaction!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -1279,22 +1623,34 @@ default_imp_for_frm_transaction!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "frm")] @@ -1315,6 +1671,7 @@ macro_rules! default_imp_for_frm_fulfillment { #[cfg(feature = "frm")] default_imp_for_frm_fulfillment!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -1324,22 +1681,34 @@ default_imp_for_frm_fulfillment!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "frm")] @@ -1360,6 +1729,7 @@ macro_rules! default_imp_for_frm_record_return { #[cfg(feature = "frm")] default_imp_for_frm_record_return!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -1369,22 +1739,34 @@ default_imp_for_frm_record_return!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); macro_rules! default_imp_for_revoking_mandates { @@ -1402,6 +1784,7 @@ macro_rules! default_imp_for_revoking_mandates { } default_imp_for_revoking_mandates!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -1411,20 +1794,32 @@ default_imp_for_revoking_mandates!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Worldpay, + connectors::Volt, + connectors::Zen, + connectors::Zsl ); diff --git a/crates/hyperswitch_connectors/src/default_implementations_v2.rs b/crates/hyperswitch_connectors/src/default_implementations_v2.rs index 54c0b6a82890..47cf6b9c1e40 100644 --- a/crates/hyperswitch_connectors/src/default_implementations_v2.rs +++ b/crates/hyperswitch_connectors/src/default_implementations_v2.rs @@ -205,6 +205,7 @@ macro_rules! default_imp_for_new_connector_integration_payment { } default_imp_for_new_connector_integration_payment!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -214,22 +215,34 @@ default_imp_for_new_connector_integration_payment!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); macro_rules! default_imp_for_new_connector_integration_refund { @@ -249,6 +262,7 @@ macro_rules! default_imp_for_new_connector_integration_refund { } default_imp_for_new_connector_integration_refund!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -258,22 +272,34 @@ default_imp_for_new_connector_integration_refund!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); macro_rules! default_imp_for_new_connector_integration_connector_access_token { @@ -288,6 +314,7 @@ macro_rules! default_imp_for_new_connector_integration_connector_access_token { } default_imp_for_new_connector_integration_connector_access_token!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -297,22 +324,34 @@ default_imp_for_new_connector_integration_connector_access_token!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); macro_rules! default_imp_for_new_connector_integration_accept_dispute { @@ -333,6 +372,7 @@ macro_rules! default_imp_for_new_connector_integration_accept_dispute { } default_imp_for_new_connector_integration_accept_dispute!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -342,22 +382,34 @@ default_imp_for_new_connector_integration_accept_dispute!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); macro_rules! default_imp_for_new_connector_integration_submit_evidence { @@ -377,6 +429,7 @@ macro_rules! default_imp_for_new_connector_integration_submit_evidence { } default_imp_for_new_connector_integration_submit_evidence!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -386,22 +439,34 @@ default_imp_for_new_connector_integration_submit_evidence!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); macro_rules! default_imp_for_new_connector_integration_defend_dispute { @@ -421,6 +486,7 @@ macro_rules! default_imp_for_new_connector_integration_defend_dispute { } default_imp_for_new_connector_integration_defend_dispute!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -430,22 +496,34 @@ default_imp_for_new_connector_integration_defend_dispute!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); macro_rules! default_imp_for_new_connector_integration_file_upload { @@ -475,6 +553,7 @@ macro_rules! default_imp_for_new_connector_integration_file_upload { } default_imp_for_new_connector_integration_file_upload!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -484,22 +563,34 @@ default_imp_for_new_connector_integration_file_upload!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "payouts")] @@ -521,6 +612,7 @@ macro_rules! default_imp_for_new_connector_integration_payouts_create { #[cfg(feature = "payouts")] default_imp_for_new_connector_integration_payouts_create!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -530,22 +622,34 @@ default_imp_for_new_connector_integration_payouts_create!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "payouts")] @@ -567,6 +671,7 @@ macro_rules! default_imp_for_new_connector_integration_payouts_eligibility { #[cfg(feature = "payouts")] default_imp_for_new_connector_integration_payouts_eligibility!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -576,22 +681,34 @@ default_imp_for_new_connector_integration_payouts_eligibility!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "payouts")] @@ -613,6 +730,7 @@ macro_rules! default_imp_for_new_connector_integration_payouts_fulfill { #[cfg(feature = "payouts")] default_imp_for_new_connector_integration_payouts_fulfill!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -622,22 +740,34 @@ default_imp_for_new_connector_integration_payouts_fulfill!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "payouts")] @@ -659,6 +789,7 @@ macro_rules! default_imp_for_new_connector_integration_payouts_cancel { #[cfg(feature = "payouts")] default_imp_for_new_connector_integration_payouts_cancel!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -668,22 +799,34 @@ default_imp_for_new_connector_integration_payouts_cancel!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "payouts")] @@ -705,6 +848,7 @@ macro_rules! default_imp_for_new_connector_integration_payouts_quote { #[cfg(feature = "payouts")] default_imp_for_new_connector_integration_payouts_quote!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -714,22 +858,34 @@ default_imp_for_new_connector_integration_payouts_quote!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "payouts")] @@ -751,6 +907,7 @@ macro_rules! default_imp_for_new_connector_integration_payouts_recipient { #[cfg(feature = "payouts")] default_imp_for_new_connector_integration_payouts_recipient!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -760,22 +917,34 @@ default_imp_for_new_connector_integration_payouts_recipient!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "payouts")] @@ -797,6 +966,7 @@ macro_rules! default_imp_for_new_connector_integration_payouts_sync { #[cfg(feature = "payouts")] default_imp_for_new_connector_integration_payouts_sync!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -806,22 +976,34 @@ default_imp_for_new_connector_integration_payouts_sync!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "payouts")] @@ -843,6 +1025,7 @@ macro_rules! default_imp_for_new_connector_integration_payouts_recipient_account #[cfg(feature = "payouts")] default_imp_for_new_connector_integration_payouts_recipient_account!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -852,22 +1035,34 @@ default_imp_for_new_connector_integration_payouts_recipient_account!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); macro_rules! default_imp_for_new_connector_integration_webhook_source_verification { @@ -887,6 +1082,7 @@ macro_rules! default_imp_for_new_connector_integration_webhook_source_verificati } default_imp_for_new_connector_integration_webhook_source_verification!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -896,22 +1092,34 @@ default_imp_for_new_connector_integration_webhook_source_verification!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "frm")] @@ -933,6 +1141,7 @@ macro_rules! default_imp_for_new_connector_integration_frm_sale { #[cfg(feature = "frm")] default_imp_for_new_connector_integration_frm_sale!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -942,22 +1151,34 @@ default_imp_for_new_connector_integration_frm_sale!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "frm")] @@ -979,6 +1200,7 @@ macro_rules! default_imp_for_new_connector_integration_frm_checkout { #[cfg(feature = "frm")] default_imp_for_new_connector_integration_frm_checkout!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -988,22 +1210,34 @@ default_imp_for_new_connector_integration_frm_checkout!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "frm")] @@ -1025,6 +1259,7 @@ macro_rules! default_imp_for_new_connector_integration_frm_transaction { #[cfg(feature = "frm")] default_imp_for_new_connector_integration_frm_transaction!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -1034,22 +1269,34 @@ default_imp_for_new_connector_integration_frm_transaction!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "frm")] @@ -1071,6 +1318,7 @@ macro_rules! default_imp_for_new_connector_integration_frm_fulfillment { #[cfg(feature = "frm")] default_imp_for_new_connector_integration_frm_fulfillment!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -1080,22 +1328,34 @@ default_imp_for_new_connector_integration_frm_fulfillment!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); #[cfg(feature = "frm")] @@ -1117,6 +1377,7 @@ macro_rules! default_imp_for_new_connector_integration_frm_record_return { #[cfg(feature = "frm")] default_imp_for_new_connector_integration_frm_record_return!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -1126,22 +1387,34 @@ default_imp_for_new_connector_integration_frm_record_return!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); macro_rules! default_imp_for_new_connector_integration_revoking_mandates { @@ -1160,6 +1433,7 @@ macro_rules! default_imp_for_new_connector_integration_revoking_mandates { } default_imp_for_new_connector_integration_revoking_mandates!( + connectors::Airwallex, connectors::Bambora, connectors::Billwerk, connectors::Bitpay, @@ -1169,20 +1443,32 @@ default_imp_for_new_connector_integration_revoking_mandates!( connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, + connectors::Elavon, connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Jpmorgan, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, + connectors::Multisafepay, + connectors::Razorpay, + connectors::Shift4, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Worldpay, + connectors::Zen, + connectors::Zsl ); diff --git a/crates/hyperswitch_connectors/src/lib.rs b/crates/hyperswitch_connectors/src/lib.rs index aa0ff7e975ea..5873398d8e47 100644 --- a/crates/hyperswitch_connectors/src/lib.rs +++ b/crates/hyperswitch_connectors/src/lib.rs @@ -4,5 +4,6 @@ pub mod connectors; pub mod constants; pub mod default_implementations; pub mod default_implementations_v2; +pub mod metrics; pub mod types; pub mod utils; diff --git a/crates/hyperswitch_connectors/src/metrics.rs b/crates/hyperswitch_connectors/src/metrics.rs new file mode 100644 index 000000000000..0ce7942663b1 --- /dev/null +++ b/crates/hyperswitch_connectors/src/metrics.rs @@ -0,0 +1,8 @@ +//! Metrics interface + +use router_env::{counter_metric, global_meter, metrics_context}; + +metrics_context!(CONTEXT); +global_meter!(GLOBAL_METER, "ROUTER_API"); + +counter_metric!(CONNECTOR_RESPONSE_DESERIALIZATION_FAILURE, GLOBAL_METER); diff --git a/crates/hyperswitch_connectors/src/types.rs b/crates/hyperswitch_connectors/src/types.rs index 05279b53ef89..0d7ecfc36433 100644 --- a/crates/hyperswitch_connectors/src/types.rs +++ b/crates/hyperswitch_connectors/src/types.rs @@ -1,25 +1,27 @@ use hyperswitch_domain_models::{ router_data::{AccessToken, RouterData}, - router_flow_types::{AccessTokenAuth, Capture, PSync, Void}, + router_flow_types::{AccessTokenAuth, Capture, PSync, PreProcessing, Void}, router_request_types::{ - AccessTokenRequestData, PaymentsCancelData, PaymentsCaptureData, PaymentsSyncData, - RefundsData, + AccessTokenRequestData, PaymentsCancelData, PaymentsCaptureData, PaymentsPreProcessingData, + PaymentsSyncData, RefundsData, }, router_response_types::{PaymentsResponseData, RefundsResponseData}, }; -pub type PaymentsSyncResponseRouterData = +pub(crate) type PaymentsSyncResponseRouterData = ResponseRouterData; -pub type PaymentsCaptureResponseRouterData = +pub(crate) type PaymentsCaptureResponseRouterData = ResponseRouterData; pub(crate) type RefundsResponseRouterData = ResponseRouterData; pub(crate) type RefreshTokenRouterData = RouterData; -pub type PaymentsCancelResponseRouterData = +pub(crate) type PaymentsCancelResponseRouterData = ResponseRouterData; +pub(crate) type PaymentsPreprocessingResponseRouterData = + ResponseRouterData; // TODO: Remove `ResponseRouterData` from router crate after all the related type aliases are moved to this crate. pub struct ResponseRouterData { diff --git a/crates/hyperswitch_connectors/src/utils.rs b/crates/hyperswitch_connectors/src/utils.rs index 0134253f2f95..a0daab47a24e 100644 --- a/crates/hyperswitch_connectors/src/utils.rs +++ b/crates/hyperswitch_connectors/src/utils.rs @@ -17,7 +17,9 @@ use common_utils::{ use error_stack::{report, ResultExt}; use hyperswitch_domain_models::{ payment_method_data::{Card, PaymentMethodData}, - router_data::{ApplePayPredecryptData, PaymentMethodToken, RecurringMandatePaymentData}, + router_data::{ + ApplePayPredecryptData, ErrorResponse, PaymentMethodToken, RecurringMandatePaymentData, + }, router_request_types::{ AuthenticationData, BrowserInformation, CompleteAuthorizeData, PaymentMethodTokenizationData, PaymentsAuthorizeData, PaymentsCancelData, @@ -25,12 +27,16 @@ use hyperswitch_domain_models::{ SetupMandateRequestData, }, }; -use hyperswitch_interfaces::{api, errors}; +use hyperswitch_interfaces::{api, consts, errors, types::Response}; use image::Luma; use masking::{ExposeInterface, PeekInterface, Secret}; use once_cell::sync::Lazy; use regex::Regex; +use router_env::{logger, metrics::add_attributes}; use serde::Serializer; +use serde_json::Value; + +use crate::{constants::UNSUPPORTED_ERROR_MESSAGE, types::RefreshTokenRouterData}; type Error = error_stack::Report; @@ -45,6 +51,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, @@ -90,7 +105,7 @@ pub(crate) fn to_currency_base_unit_asf64( } pub(crate) fn to_connector_meta_from_secret( - connector_meta: Option>, + connector_meta: Option>, ) -> Result where T: serde::de::DeserializeOwned, @@ -112,6 +127,39 @@ pub(crate) fn missing_field_err( }) } +pub(crate) fn handle_json_response_deserialization_failure( + res: Response, + connector: &'static str, +) -> CustomResult { + crate::metrics::CONNECTOR_RESPONSE_DESERIALIZATION_FAILURE.add( + &crate::metrics::CONTEXT, + 1, + &add_attributes([("connector", connector)]), + ); + + let response_data = String::from_utf8(res.response.to_vec()) + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + + // check for whether the response is in json format + match serde_json::from_str::(&response_data) { + // in case of unexpected response but in json format + Ok(_) => Err(errors::ConnectorError::ResponseDeserializationFailed)?, + // in case of unexpected response but in html or string format + Err(error_msg) => { + logger::error!(deserialization_error=?error_msg); + logger::error!("UNEXPECTED RESPONSE FROM CONNECTOR: {}", response_data); + Ok(ErrorResponse { + status_code: res.status_code, + code: consts::NO_ERROR_CODE.to_string(), + message: UNSUPPORTED_ERROR_MESSAGE.to_string(), + reason: Some(response_data), + attempt_status: None, + connector_transaction_id: None, + }) + } + } +} + pub(crate) fn construct_not_implemented_error_report( capture_method: enums::CaptureMethod, connector_name: &str, @@ -136,7 +184,7 @@ pub(crate) fn get_unimplemented_payment_method_error_message(connector: &str) -> format!("{} through {}", SELECTED_PAYMENT_METHOD, connector) } -pub(crate) fn to_connector_meta(connector_meta: Option) -> Result +pub(crate) fn to_connector_meta(connector_meta: Option) -> Result where T: serde::de::DeserializeOwned, { @@ -193,6 +241,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>; @@ -722,6 +780,18 @@ impl RouterData } } +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 ApplePayDecrypt { fn get_expiry_month(&self) -> Result, Error>; fn get_four_digit_expiry_year(&self) -> Result, Error>; @@ -1083,6 +1153,7 @@ pub trait PaymentsAuthorizeRequestData { fn get_total_surcharge_amount(&self) -> Option; fn get_metadata_as_object(&self) -> Option; fn get_authentication_data(&self) -> Result; + fn get_customer_name(&self) -> Result, Error>; } impl PaymentsAuthorizeRequestData for PaymentsAuthorizeData { @@ -1093,6 +1164,7 @@ impl PaymentsAuthorizeRequestData for PaymentsAuthorizeData { Some(_) => Err(errors::ConnectorError::CaptureMethodNotSupported.into()), } } + fn get_email(&self) -> Result { self.email.clone().ok_or_else(missing_field_err("email")) } @@ -1136,7 +1208,7 @@ impl PaymentsAuthorizeRequestData for PaymentsAuthorizeData { .as_ref() .and_then(|mandate_ids| match &mandate_ids.mandate_reference_id { Some(payments::MandateReferenceId::ConnectorMandateId(connector_mandate_ids)) => { - connector_mandate_ids.connector_mandate_id.clone() + connector_mandate_ids.get_connector_mandate_id() } Some(payments::MandateReferenceId::NetworkMandateId(_)) | None @@ -1223,12 +1295,12 @@ impl PaymentsAuthorizeRequestData for PaymentsAuthorizeData { fn get_metadata_as_object(&self) -> Option { self.metadata.clone().and_then(|meta_data| match meta_data { - serde_json::Value::Null - | serde_json::Value::Bool(_) - | serde_json::Value::Number(_) - | serde_json::Value::String(_) - | serde_json::Value::Array(_) => None, - serde_json::Value::Object(_) => Some(meta_data.into()), + Value::Null + | Value::Bool(_) + | Value::Number(_) + | Value::String(_) + | Value::Array(_) => None, + Value::Object(_) => Some(meta_data.into()), }) } @@ -1237,6 +1309,12 @@ impl PaymentsAuthorizeRequestData for PaymentsAuthorizeData { .clone() .ok_or_else(missing_field_err("authentication_data")) } + + fn get_customer_name(&self) -> Result, Error> { + self.customer_name + .clone() + .ok_or_else(missing_field_err("customer_name")) + } } pub trait PaymentsCaptureRequestData { @@ -1431,8 +1509,20 @@ impl PaymentsCompleteAuthorizeRequestData for CompleteAuthorizeData { .is_some() } } +pub trait AddressData { + fn get_optional_full_name(&self) -> Option>; +} +impl AddressData for Address { + fn get_optional_full_name(&self) -> Option> { + self.address + .as_ref() + .and_then(|billing_address| billing_address.get_optional_full_name()) + } +} pub trait PaymentsPreProcessingRequestData { + fn get_amount(&self) -> Result; + fn get_currency(&self) -> Result; fn is_auto_capture(&self) -> Result; } @@ -1446,6 +1536,12 @@ impl PaymentsPreProcessingRequestData for PaymentsPreProcessingData { } } } + fn get_amount(&self) -> Result { + self.amount.ok_or_else(missing_field_err("amount")) + } + fn get_currency(&self) -> Result { + self.currency.ok_or_else(missing_field_err("currency")) + } } pub trait BrowserInformationData { @@ -2051,3 +2147,66 @@ 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: 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/hyperswitch_domain_models/Cargo.toml b/crates/hyperswitch_domain_models/Cargo.toml index 3a0d4b402b74..8fa6d2cc4e81 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/customer.rs b/crates/hyperswitch_domain_models/src/customer.rs index af901a80558e..71cb4ebc2f92 100644 --- a/crates/hyperswitch_domain_models/src/customer.rs +++ b/crates/hyperswitch_domain_models/src/customer.rs @@ -1,8 +1,8 @@ -use api_models::customers::CustomerRequestWithEncryption; #[cfg(all(feature = "v2", feature = "customer_v2"))] use common_enums::DeleteStatus; use common_utils::{ - crypto, date_time, + crypto::{self, Encryptable}, + date_time, encryption::Encryption, errors::{CustomResult, ValidationError}, id_type, pii, @@ -13,19 +13,23 @@ use common_utils::{ }; use diesel_models::customers::CustomerUpdateInternal; use error_stack::ResultExt; -use masking::{PeekInterface, Secret}; +use masking::{PeekInterface, Secret, SwitchStrategy}; +use rustc_hash::FxHashMap; use time::PrimitiveDateTime; use crate::type_encryption as types; #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] -#[derive(Clone, Debug)] +#[derive(Clone, Debug, router_derive::ToEncryption)] pub struct Customer { pub customer_id: id_type::CustomerId, pub merchant_id: id_type::MerchantId, - pub name: crypto::OptionalEncryptableName, - pub email: crypto::OptionalEncryptableEmail, - pub phone: crypto::OptionalEncryptablePhone, + #[encrypt] + pub name: Option>>, + #[encrypt] + pub email: Option>>, + #[encrypt] + pub phone: Option>>, pub phone_country_code: Option, pub description: Option, pub created_at: PrimitiveDateTime, @@ -39,12 +43,15 @@ pub struct Customer { } #[cfg(all(feature = "v2", feature = "customer_v2"))] -#[derive(Clone, Debug)] +#[derive(Clone, Debug, router_derive::ToEncryption)] pub struct Customer { pub merchant_id: id_type::MerchantId, - pub name: crypto::OptionalEncryptableName, - pub email: crypto::OptionalEncryptableEmail, - pub phone: crypto::OptionalEncryptablePhone, + #[encrypt] + pub name: Option>>, + #[encrypt] + pub email: Option>>, + #[encrypt] + pub phone: Option>>, pub phone_country_code: Option, pub description: Option, pub created_at: PrimitiveDateTime, @@ -98,8 +105,8 @@ impl super::behaviour::Conversion for Customer { let decrypted = types::crypto_operation( state, common_utils::type_name!(Self::DstType), - types::CryptoOperation::BatchDecrypt(CustomerRequestWithEncryption::to_encryptable( - CustomerRequestWithEncryption { + types::CryptoOperation::BatchDecrypt(EncryptedCustomer::to_encryptable( + EncryptedCustomer { name: item.name.clone(), phone: item.phone.clone(), email: item.email.clone(), @@ -113,16 +120,23 @@ impl super::behaviour::Conversion for Customer { .change_context(ValidationError::InvalidValue { message: "Failed while decrypting customer data".to_string(), })?; - let encryptable_customer = CustomerRequestWithEncryption::from_encryptable(decrypted) - .change_context(ValidationError::InvalidValue { + let encryptable_customer = EncryptedCustomer::from_encryptable(decrypted).change_context( + ValidationError::InvalidValue { message: "Failed while decrypting customer data".to_string(), - })?; + }, + )?; Ok(Self { customer_id: item.customer_id, merchant_id: item.merchant_id, name: encryptable_customer.name, - email: encryptable_customer.email, + email: encryptable_customer.email.map(|email| { + let encryptable: Encryptable> = Encryptable::new( + email.clone().into_inner().switch_strategy(), + email.into_encrypted(), + ); + encryptable + }), phone: encryptable_customer.phone, phone_country_code: item.phone_country_code, description: item.description, @@ -198,8 +212,8 @@ impl super::behaviour::Conversion for Customer { let decrypted = types::crypto_operation( state, common_utils::type_name!(Self::DstType), - types::CryptoOperation::BatchDecrypt(CustomerRequestWithEncryption::to_encryptable( - CustomerRequestWithEncryption { + types::CryptoOperation::BatchDecrypt(EncryptedCustomer::to_encryptable( + EncryptedCustomer { name: item.name.clone(), phone: item.phone.clone(), email: item.email.clone(), @@ -213,17 +227,24 @@ impl super::behaviour::Conversion for Customer { .change_context(ValidationError::InvalidValue { message: "Failed while decrypting customer data".to_string(), })?; - let encryptable_customer = CustomerRequestWithEncryption::from_encryptable(decrypted) - .change_context(ValidationError::InvalidValue { + let encryptable_customer = EncryptedCustomer::from_encryptable(decrypted).change_context( + ValidationError::InvalidValue { message: "Failed while decrypting customer data".to_string(), - })?; + }, + )?; Ok(Self { id: item.id, merchant_reference_id: item.merchant_reference_id, merchant_id: item.merchant_id, name: encryptable_customer.name, - email: encryptable_customer.email, + email: encryptable_customer.email.map(|email| { + let encryptable: Encryptable> = Encryptable::new( + email.clone().into_inner().switch_strategy(), + email.into_encrypted(), + ); + encryptable + }), phone: encryptable_customer.phone, phone_country_code: item.phone_country_code, description: item.description, @@ -275,7 +296,7 @@ pub enum CustomerUpdate { description: Option, phone_country_code: Option, metadata: Option, - connector_customer: Option, + connector_customer: Box>, default_billing_address: Option, default_shipping_address: Option, default_payment_method_id: Option>, @@ -312,7 +333,7 @@ impl From for CustomerUpdateInternal { description, phone_country_code, metadata, - connector_customer, + connector_customer: *connector_customer, modified_at: date_time::now(), default_billing_address, default_shipping_address, @@ -366,7 +387,7 @@ pub enum CustomerUpdate { description: Option, phone_country_code: Option, metadata: Option, - connector_customer: Option, + connector_customer: Box>, address_id: Option, }, ConnectorCustomer { @@ -397,7 +418,7 @@ impl From for CustomerUpdateInternal { description, phone_country_code, metadata, - connector_customer, + connector_customer: *connector_customer, modified_at: date_time::now(), address_id, default_payment_method_id: None, diff --git a/crates/hyperswitch_domain_models/src/lib.rs b/crates/hyperswitch_domain_models/src/lib.rs index 4803514617fd..af6c8e65c848 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/merchant_account.rs b/crates/hyperswitch_domain_models/src/merchant_account.rs index 3e860d362845..1e3302dab4a3 100644 --- a/crates/hyperswitch_domain_models/src/merchant_account.rs +++ b/crates/hyperswitch_domain_models/src/merchant_account.rs @@ -201,7 +201,7 @@ impl MerchantAccount { #[cfg(feature = "v1")] #[allow(clippy::large_enum_variant)] -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum MerchantAccountUpdate { Update { merchant_name: OptionalEncryptableName, @@ -237,7 +237,7 @@ pub enum MerchantAccountUpdate { #[cfg(feature = "v2")] #[allow(clippy::large_enum_variant)] -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum MerchantAccountUpdate { Update { merchant_name: OptionalEncryptableName, diff --git a/crates/hyperswitch_domain_models/src/merchant_connector_account.rs b/crates/hyperswitch_domain_models/src/merchant_connector_account.rs index 66b983898185..0d730be203b1 100644 --- a/crates/hyperswitch_domain_models/src/merchant_connector_account.rs +++ b/crates/hyperswitch_domain_models/src/merchant_connector_account.rs @@ -10,16 +10,18 @@ use diesel_models::{enums, merchant_connector_account::MerchantConnectorAccountU use error_stack::ResultExt; use masking::{PeekInterface, Secret}; use rustc_hash::FxHashMap; +use serde_json::Value; use super::behaviour; use crate::type_encryption::{crypto_operation, CryptoOperation}; #[cfg(feature = "v1")] -#[derive(Clone, Debug)] +#[derive(Clone, Debug, router_derive::ToEncryption)] pub struct MerchantConnectorAccount { pub merchant_id: id_type::MerchantId, pub connector_name: String, - pub connector_account_details: Encryptable, + #[encrypt] + pub connector_account_details: Encryptable>, pub test_mode: Option, pub disabled: Option, pub merchant_connector_id: id_type::MerchantConnectorAccountId, @@ -38,8 +40,10 @@ pub struct MerchantConnectorAccount { pub applepay_verified_domains: Option>, pub pm_auth_config: Option, pub status: enums::ConnectorStatus, - pub connector_wallets_details: Option>, - pub additional_merchant_data: Option>, + #[encrypt] + pub connector_wallets_details: Option>>, + #[encrypt] + pub additional_merchant_data: Option>>, pub version: common_enums::ApiVersion, } @@ -51,12 +55,13 @@ impl MerchantConnectorAccount { } #[cfg(feature = "v2")] -#[derive(Clone, Debug)] +#[derive(Clone, Debug, router_derive::ToEncryption)] pub struct MerchantConnectorAccount { pub id: id_type::MerchantConnectorAccountId, pub merchant_id: id_type::MerchantId, pub connector_name: String, - pub connector_account_details: Encryptable, + #[encrypt] + pub connector_account_details: Encryptable>, pub disabled: Option, pub payment_methods_enabled: Option>, pub connector_type: enums::ConnectorType, @@ -70,8 +75,10 @@ pub struct MerchantConnectorAccount { pub applepay_verified_domains: Option>, pub pm_auth_config: Option, pub status: enums::ConnectorStatus, - pub connector_wallets_details: Option>, - pub additional_merchant_data: Option>, + #[encrypt] + pub connector_wallets_details: Option>>, + #[encrypt] + pub additional_merchant_data: Option>>, pub version: common_enums::ApiVersion, } @@ -88,20 +95,20 @@ pub enum MerchantConnectorAccountUpdate { Update { connector_type: Option, connector_name: Option, - connector_account_details: Option>, + connector_account_details: Box>>, test_mode: Option, disabled: Option, merchant_connector_id: Option, payment_methods_enabled: Option>, metadata: Option, frm_configs: Option>, - connector_webhook_details: Option, + connector_webhook_details: Box>, applepay_verified_domains: Option>, - pm_auth_config: Option, + pm_auth_config: Box>, connector_label: Option, status: Option, - connector_wallets_details: Option>, - additional_merchant_data: Option>, + connector_wallets_details: Box>>, + additional_merchant_data: Box>>, }, ConnectorWalletDetailsUpdate { connector_wallets_details: Encryptable, @@ -113,18 +120,18 @@ pub enum MerchantConnectorAccountUpdate { pub enum MerchantConnectorAccountUpdate { Update { connector_type: Option, - connector_account_details: Option>, + connector_account_details: Box>>, disabled: Option, payment_methods_enabled: Option>, metadata: Option, frm_configs: Option>, connector_webhook_details: Option, applepay_verified_domains: Option>, - pm_auth_config: Option, + pm_auth_config: Box>, connector_label: Option, status: Option, - connector_wallets_details: Option>, - additional_merchant_data: Option>, + connector_wallets_details: Box>>, + additional_merchant_data: Box>>, }, ConnectorWalletDetailsUpdate { connector_wallets_details: Encryptable, @@ -179,11 +186,13 @@ impl behaviour::Conversion for MerchantConnectorAccount { let decrypted_data = crypto_operation( state, type_name!(Self::DstType), - CryptoOperation::BatchDecrypt(EncryptedMca::to_encryptable(EncryptedMca { - connector_account_details: other.connector_account_details, - additional_merchant_data: other.additional_merchant_data, - connector_wallets_details: other.connector_wallets_details, - })), + CryptoOperation::BatchDecrypt(EncryptedMerchantConnectorAccount::to_encryptable( + EncryptedMerchantConnectorAccount { + connector_account_details: other.connector_account_details, + additional_merchant_data: other.additional_merchant_data, + connector_wallets_details: other.connector_wallets_details, + }, + )), identifier.clone(), key.peek(), ) @@ -193,11 +202,10 @@ impl behaviour::Conversion for MerchantConnectorAccount { message: "Failed while decrypting connector account details".to_string(), })?; - let decrypted_data = EncryptedMca::from_encryptable(decrypted_data).change_context( - ValidationError::InvalidValue { + let decrypted_data = EncryptedMerchantConnectorAccount::from_encryptable(decrypted_data) + .change_context(ValidationError::InvalidValue { message: "Failed while decrypting connector account details".to_string(), - }, - )?; + })?; Ok(Self { merchant_id: other.merchant_id, @@ -308,11 +316,13 @@ impl behaviour::Conversion for MerchantConnectorAccount { let decrypted_data = crypto_operation( state, type_name!(Self::DstType), - CryptoOperation::BatchDecrypt(EncryptedMca::to_encryptable(EncryptedMca { - connector_account_details: other.connector_account_details, - additional_merchant_data: other.additional_merchant_data, - connector_wallets_details: other.connector_wallets_details, - })), + CryptoOperation::BatchDecrypt(EncryptedMerchantConnectorAccount::to_encryptable( + EncryptedMerchantConnectorAccount { + connector_account_details: other.connector_account_details, + additional_merchant_data: other.additional_merchant_data, + connector_wallets_details: other.connector_wallets_details, + }, + )), identifier.clone(), key.peek(), ) @@ -322,11 +332,10 @@ impl behaviour::Conversion for MerchantConnectorAccount { message: "Failed while decrypting connector account details".to_string(), })?; - let decrypted_data = EncryptedMca::from_encryptable(decrypted_data).change_context( - ValidationError::InvalidValue { + let decrypted_data = EncryptedMerchantConnectorAccount::from_encryptable(decrypted_data) + .change_context(ValidationError::InvalidValue { message: "Failed while decrypting connector account details".to_string(), - }, - )?; + })?; Ok(Self { id: other.id, @@ -413,9 +422,9 @@ impl From for MerchantConnectorAccountUpdateInte frm_configs: None, frm_config: frm_configs, modified_at: Some(date_time::now()), - connector_webhook_details, + connector_webhook_details: *connector_webhook_details, applepay_verified_domains, - pm_auth_config, + pm_auth_config: *pm_auth_config, connector_label, status, connector_wallets_details: connector_wallets_details.map(Encryption::from), @@ -475,7 +484,7 @@ impl From for MerchantConnectorAccountUpdateInte modified_at: Some(date_time::now()), connector_webhook_details, applepay_verified_domains, - pm_auth_config, + pm_auth_config: *pm_auth_config, connector_label, status, connector_wallets_details: connector_wallets_details.map(Encryption::from), @@ -502,121 +511,3 @@ impl From for MerchantConnectorAccountUpdateInte } } } - -pub struct McaFromRequestfromUpdate { - pub connector_account_details: Option, - pub connector_wallets_details: Option, - pub additional_merchant_data: Option, -} -pub struct McaFromRequest { - pub connector_account_details: pii::SecretSerdeValue, - pub connector_wallets_details: Option, - pub additional_merchant_data: Option, -} - -pub struct DecryptedMca { - pub connector_account_details: Encryptable, - pub connector_wallets_details: Option>, - pub additional_merchant_data: Option>, -} - -pub struct EncryptedMca { - pub connector_account_details: Encryption, - pub connector_wallets_details: Option, - pub additional_merchant_data: Option, -} - -pub struct DecryptedUpdateMca { - pub connector_account_details: Option>, - pub connector_wallets_details: Option>, - pub additional_merchant_data: Option>, -} - -impl ToEncryptable, Encryption> for EncryptedMca { - fn from_encryptable( - mut hashmap: FxHashMap>>, - ) -> CustomResult { - Ok(DecryptedMca { - connector_account_details: hashmap.remove("connector_account_details").ok_or( - error_stack::report!(common_utils::errors::ParsingError::EncodeError( - "Unable to convert from HashMap to DecryptedMca", - )), - )?, - connector_wallets_details: hashmap.remove("connector_wallets_details"), - additional_merchant_data: hashmap.remove("additional_merchant_data"), - }) - } - - fn to_encryptable(self) -> FxHashMap { - let mut map = FxHashMap::with_capacity_and_hasher(3, Default::default()); - - map.insert( - "connector_account_details".to_string(), - self.connector_account_details, - ); - self.connector_wallets_details - .map(|s| map.insert("connector_wallets_details".to_string(), s)); - self.additional_merchant_data - .map(|s| map.insert("additional_merchant_data".to_string(), s)); - map - } -} - -impl ToEncryptable, Secret> - for McaFromRequestfromUpdate -{ - fn from_encryptable( - mut hashmap: FxHashMap>>, - ) -> CustomResult { - Ok(DecryptedUpdateMca { - connector_account_details: hashmap.remove("connector_account_details"), - connector_wallets_details: hashmap.remove("connector_wallets_details"), - additional_merchant_data: hashmap.remove("additional_merchant_data"), - }) - } - - fn to_encryptable(self) -> FxHashMap> { - let mut map = FxHashMap::with_capacity_and_hasher(3, Default::default()); - - self.connector_account_details - .map(|cad| map.insert("connector_account_details".to_string(), cad)); - - self.connector_wallets_details - .map(|s| map.insert("connector_wallets_details".to_string(), s)); - self.additional_merchant_data - .map(|s| map.insert("additional_merchant_data".to_string(), s)); - map - } -} - -impl ToEncryptable, Secret> - for McaFromRequest -{ - fn from_encryptable( - mut hashmap: FxHashMap>>, - ) -> CustomResult { - Ok(DecryptedMca { - connector_account_details: hashmap.remove("connector_account_details").ok_or( - error_stack::report!(common_utils::errors::ParsingError::EncodeError( - "Unable to convert from HashMap to DecryptedMca", - )), - )?, - connector_wallets_details: hashmap.remove("connector_wallets_details"), - additional_merchant_data: hashmap.remove("additional_merchant_data"), - }) - } - - fn to_encryptable(self) -> FxHashMap> { - let mut map = FxHashMap::with_capacity_and_hasher(3, Default::default()); - - map.insert( - "connector_account_details".to_string(), - self.connector_account_details, - ); - self.connector_wallets_details - .map(|s| map.insert("connector_wallets_details".to_string(), s)); - self.additional_merchant_data - .map(|s| map.insert("additional_merchant_data".to_string(), s)); - map - } -} diff --git a/crates/hyperswitch_domain_models/src/payments.rs b/crates/hyperswitch_domain_models/src/payments.rs index 4c8cb9c38ea3..cd41458dfbf5 100644 --- a/crates/hyperswitch_domain_models/src/payments.rs +++ b/crates/hyperswitch_domain_models/src/payments.rs @@ -5,11 +5,21 @@ use std::marker::PhantomData; use api_models::payments::Address; #[cfg(feature = "v2")] use api_models::payments::OrderDetailsWithAmount; -use common_utils::{self, crypto::Encryptable, id_type, pii, types::MinorUnit}; +use common_utils::{ + self, + crypto::Encryptable, + encryption::Encryption, + errors::CustomResult, + id_type, pii, + types::{keymanager::ToEncryptable, MinorUnit}, +}; use diesel_models::payment_intent::TaxDetails; #[cfg(feature = "v2")] use error_stack::ResultExt; use masking::Secret; +use router_derive::ToEncryption; +use rustc_hash::FxHashMap; +use serde_json::Value; use time::PrimitiveDateTime; pub mod payment_attempt; @@ -22,10 +32,10 @@ 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)] +#[derive(Clone, Debug, PartialEq, serde::Serialize, ToEncryption)] pub struct PaymentIntent { pub payment_id: id_type::PaymentId, pub merchant_id: id_type::MerchantId, @@ -37,7 +47,7 @@ pub struct PaymentIntent { pub customer_id: Option, pub description: Option, pub return_url: Option, - pub metadata: Option, + pub metadata: Option, pub connector_id: Option, pub shipping_address_id: Option, pub billing_address_id: Option, @@ -56,9 +66,9 @@ pub struct PaymentIntent { pub business_country: Option, pub business_label: Option, pub order_details: Option>, - pub allowed_payment_method_types: Option, - pub connector_metadata: Option, - pub feature_metadata: Option, + pub allowed_payment_method_types: Option, + pub connector_metadata: Option, + pub feature_metadata: Option, pub attempt_count: i16, pub profile_id: Option, pub payment_link_id: Option, @@ -78,10 +88,13 @@ pub struct PaymentIntent { pub request_external_three_ds_authentication: Option, pub charges: Option, pub frm_metadata: Option, - pub customer_details: Option>>, - pub billing_details: Option>>, + #[encrypt] + pub customer_details: Option>>, + #[encrypt] + pub billing_details: Option>>, pub merchant_order_reference_id: Option, - pub shipping_details: Option>>, + #[encrypt] + pub shipping_details: Option>>, pub is_payment_processor_token_flow: Option, pub organization_id: id_type::OrganizationId, pub tax_details: Option, @@ -101,7 +114,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 +123,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 +170,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,10 +192,53 @@ 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")] -#[derive(Clone, Debug, PartialEq, serde::Serialize)] +#[derive(Clone, Debug, PartialEq, serde::Serialize, ToEncryption)] pub struct PaymentIntent { /// The global identifier for the payment intent. This is generated by the system. /// The format of the global id is `{cell_id:5}_pay_{time_ordered_uuid:32}`. @@ -246,19 +305,22 @@ pub struct PaymentIntent { /// Metadata related to fraud and risk management pub frm_metadata: Option, /// The details of the customer in a denormalized form. Only a subset of fields are stored. - pub customer_details: Option>>, + #[encrypt] + pub customer_details: Option>>, /// The reference id for the order in the merchant's system. This value can be passed by the merchant. pub merchant_reference_id: Option, /// The billing address for the order in a denormalized form. + #[encrypt(ty = Value)] pub billing_address: Option>>, /// The shipping address for the order in a denormalized form. + #[encrypt(ty = Value)] pub shipping_address: Option>>, /// Capture method for the payment pub capture_method: storage_enums::CaptureMethod, /// Authentication type that is requested by the merchant for this payment. pub authentication_type: common_enums::AuthenticationType, /// This contains the pre routing results that are done when routing is done during listing the payment methods. - pub prerouting_algorithm: Option, + pub prerouting_algorithm: Option, /// The organization id for the payment. This is derived from the merchant account pub organization_id: id_type::OrganizationId, /// Denotes the request by the merchant whether to enable a payment link for this payment. @@ -277,7 +339,7 @@ pub struct PaymentIntent { impl PaymentIntent { fn get_request_incremental_authorization_value( request: &api_models::payments::PaymentsCreateIntentRequest, - ) -> common_utils::errors::CustomResult< + ) -> CustomResult< common_enums::RequestIncrementalAuthorization, errors::api_error_response::ApiErrorResponse, > { @@ -294,6 +356,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, @@ -301,8 +380,7 @@ impl PaymentIntent { request: api_models::payments::PaymentsCreateIntentRequest, billing_address: Option>>, shipping_address: Option>>, - ) -> common_utils::errors::CustomResult - { + ) -> CustomResult { let allowed_payment_method_types = request .get_allowed_payment_method_types_as_value() .change_context(errors::api_error_response::ApiErrorResponse::InternalServerError) @@ -384,6 +462,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 +513,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 8ecac77e54e4..831e97b54a17 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, @@ -159,70 +161,144 @@ pub trait PaymentAttemptInterface { payment_method_type: Option>, authentication_type: Option>, merchant_connector_id: Option>, + card_network: Option>, storage_scheme: storage_enums::MerchantStorageScheme, ) -> 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 +310,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 +321,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 +331,7 @@ impl PaymentAttempt { } #[cfg(feature = "v2")] - pub fn get_id(&self) -> &str { + pub fn get_id(&self) -> &id_type::GlobalAttemptId { &self.id } @@ -266,6 +344,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 +479,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 +494,7 @@ pub struct NetAmount { tax_on_surcharge: Option, } +#[cfg(feature = "v1")] impl NetAmount { pub fn new( order_amount: MinorUnit, @@ -511,57 +656,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 { @@ -693,6 +787,7 @@ pub enum PaymentAttemptUpdate { client_source: Option, client_version: Option, customer_acceptance: Option, + connector_mandate_detail: Option, }, RejectUpdate { status: storage_enums::AttemptStatus, @@ -933,6 +1028,7 @@ impl PaymentAttemptUpdate { client_source, client_version, customer_acceptance, + connector_mandate_detail, } => DieselPaymentAttemptUpdate::ConfirmUpdate { amount: net_amount.get_order_amount(), currency, @@ -966,6 +1062,7 @@ impl PaymentAttemptUpdate { customer_acceptance, shipping_cost: net_amount.get_shipping_cost(), order_tax_amount: net_amount.get_order_tax_amount(), + connector_mandate_detail, }, Self::VoidUpdate { status, @@ -1185,8 +1282,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 +1580,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 +1596,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 +1632,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 +1658,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 +1669,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 +1684,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 +1708,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 +1804,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 +1822,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 +1853,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 +1887,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 +1904,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 ebd630beb622..c9f7a5e2ae52 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs @@ -3,7 +3,7 @@ use common_enums as storage_enums; use common_utils::ext_traits::{Encode, ValueExt}; use common_utils::{ consts::{PAYMENTS_LIST_MAX_LIMIT_V1, PAYMENTS_LIST_MAX_LIMIT_V2}, - crypto::{self, Encryptable}, + crypto::Encryptable, encryption::Encryption, errors::{CustomResult, ValidationError}, id_type, @@ -21,7 +21,6 @@ use error_stack::ResultExt; #[cfg(feature = "v2")] use masking::ExposeInterface; use masking::{Deserialize, PeekInterface, Secret}; -use rustc_hash::FxHashMap; use serde::Serialize; use time::PrimitiveDateTime; @@ -266,78 +265,17 @@ 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 { + ConfirmIntent { 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 { + ConfirmIntentPostUpdate { 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 { - 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, - }, } #[cfg(feature = "v2")] @@ -353,7 +291,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 +355,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 +578,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 } + } + } } } @@ -1591,10 +1240,10 @@ impl behaviour::Conversion for PaymentIntent { let decrypted_data = crypto_operation( state, type_name!(Self::DstType), - CryptoOperation::BatchDecrypt(EncryptedPaymentIntentAddress::to_encryptable( - EncryptedPaymentIntentAddress { - billing: storage_model.billing_address, - shipping: storage_model.shipping_address, + CryptoOperation::BatchDecrypt(super::EncryptedPaymentIntent::to_encryptable( + super::EncryptedPaymentIntent { + billing_address: storage_model.billing_address, + shipping_address: storage_model.shipping_address, customer_details: storage_model.customer_details, }, )), @@ -1604,7 +1253,7 @@ impl behaviour::Conversion for PaymentIntent { .await .and_then(|val| val.try_into_batchoperation())?; - let data = EncryptedPaymentIntentAddress::from_encryptable(decrypted_data) + let data = super::EncryptedPaymentIntent::from_encryptable(decrypted_data) .change_context(common_utils::errors::CryptoError::DecodingFailed) .attach_printable("Invalid batch operation data")?; @@ -1621,9 +1270,11 @@ 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 + .billing_address .map(|billing| { billing.deserialize_inner_value(|value| value.parse_value("Address")) }) @@ -1632,7 +1283,7 @@ impl behaviour::Conversion for PaymentIntent { .attach_printable("Error while deserializing Address")?; let shipping_address = data - .shipping + .shipping_address .map(|shipping| { shipping.deserialize_inner_value(|value| value.parse_value("Address")) }) @@ -1861,10 +1512,10 @@ impl behaviour::Conversion for PaymentIntent { let decrypted_data = crypto_operation( state, type_name!(Self::DstType), - CryptoOperation::BatchDecrypt(EncryptedPaymentIntentAddress::to_encryptable( - EncryptedPaymentIntentAddress { - billing: storage_model.billing_details, - shipping: storage_model.shipping_details, + CryptoOperation::BatchDecrypt(super::EncryptedPaymentIntent::to_encryptable( + super::EncryptedPaymentIntent { + billing_details: storage_model.billing_details, + shipping_details: storage_model.shipping_details, customer_details: storage_model.customer_details, }, )), @@ -1874,7 +1525,7 @@ impl behaviour::Conversion for PaymentIntent { .await .and_then(|val| val.try_into_batchoperation())?; - let data = EncryptedPaymentIntentAddress::from_encryptable(decrypted_data) + let data = super::EncryptedPaymentIntent::from_encryptable(decrypted_data) .change_context(common_utils::errors::CryptoError::DecodingFailed) .attach_printable("Invalid batch operation data")?; @@ -1926,9 +1577,9 @@ impl behaviour::Conversion for PaymentIntent { shipping_cost: storage_model.shipping_cost, tax_details: storage_model.tax_details, customer_details: data.customer_details, - billing_details: data.billing, + billing_details: data.billing_details, merchant_order_reference_id: storage_model.merchant_order_reference_id, - shipping_details: data.shipping, + shipping_details: data.shipping_details, is_payment_processor_token_flow: storage_model.is_payment_processor_token_flow, organization_id: storage_model.organization_id, skip_external_tax_calculation: storage_model.skip_external_tax_calculation, @@ -1997,73 +1648,3 @@ impl behaviour::Conversion for PaymentIntent { }) } } - -pub struct EncryptedPaymentIntentAddress { - pub shipping: Option, - pub billing: Option, - pub customer_details: Option, -} - -pub struct PaymentAddressFromRequest { - pub shipping: Option>, - pub billing: Option>, - pub customer_details: Option>, -} - -pub struct DecryptedPaymentIntentAddress { - pub shipping: crypto::OptionalEncryptableValue, - pub billing: crypto::OptionalEncryptableValue, - pub customer_details: crypto::OptionalEncryptableValue, -} - -impl ToEncryptable, Encryption> - for EncryptedPaymentIntentAddress -{ - fn from_encryptable( - mut hashmap: FxHashMap>>, - ) -> CustomResult { - Ok(DecryptedPaymentIntentAddress { - shipping: hashmap.remove("shipping"), - billing: hashmap.remove("billing"), - customer_details: hashmap.remove("customer_details"), - }) - } - - fn to_encryptable(self) -> FxHashMap { - let mut map = FxHashMap::with_capacity_and_hasher(9, Default::default()); - - self.shipping.map(|s| map.insert("shipping".to_string(), s)); - self.billing.map(|s| map.insert("billing".to_string(), s)); - self.customer_details - .map(|s| map.insert("customer_details".to_string(), s)); - map - } -} - -impl - ToEncryptable< - DecryptedPaymentIntentAddress, - Secret, - Secret, - > for PaymentAddressFromRequest -{ - fn from_encryptable( - mut hashmap: FxHashMap>>, - ) -> CustomResult { - Ok(DecryptedPaymentIntentAddress { - shipping: hashmap.remove("shipping"), - billing: hashmap.remove("billing"), - customer_details: hashmap.remove("customer_details"), - }) - } - - fn to_encryptable(self) -> FxHashMap> { - let mut map = FxHashMap::with_capacity_and_hasher(9, Default::default()); - - self.shipping.map(|s| map.insert("shipping".to_string(), s)); - self.billing.map(|s| map.insert("billing".to_string(), s)); - self.customer_details - .map(|s| map.insert("customer_details".to_string(), s)); - map - } -} diff --git a/crates/hyperswitch_domain_models/src/router_data.rs b/crates/hyperswitch_domain_models/src/router_data.rs index b41b42eaa2d2..186a4f012629 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,9 @@ pub struct RouterData { pub additional_merchant_data: Option, - pub header_payload: Option, + pub header_payload: Option, + + pub connector_mandate_request_reference_id: Option, } // Different patterns of authentication. diff --git a/crates/hyperswitch_domain_models/src/router_flow_types/payments.rs b/crates/hyperswitch_domain_models/src/router_flow_types/payments.rs index 602c184139f9..c43d72ce8def 100644 --- a/crates/hyperswitch_domain_models/src/router_flow_types/payments.rs +++ b/crates/hyperswitch_domain_models/src/router_flow_types/payments.rs @@ -57,7 +57,10 @@ pub struct CalculateTax; pub struct SdkSessionUpdate; #[derive(Debug, Clone)] -pub struct CreateIntent; +pub struct PaymentCreateIntent; + +#[derive(Debug, Clone)] +pub struct PaymentGetIntent; #[derive(Debug, Clone)] pub struct PostSessionTokens; diff --git a/crates/hyperswitch_domain_models/src/router_request_types.rs b/crates/hyperswitch_domain_models/src/router_request_types.rs index fb4c0fd08002..344eb632f4ba 100644 --- a/crates/hyperswitch_domain_models/src/router_request_types.rs +++ b/crates/hyperswitch_domain_models/src/router_request_types.rs @@ -1,6 +1,6 @@ pub mod authentication; pub mod fraud_check; -use api_models::payments::{Address, RequestSurchargeDetails}; +use api_models::payments::{AdditionalPaymentData, Address, RequestSurchargeDetails}; use common_utils::{ consts, errors, ext_traits::OptionExt, @@ -71,17 +71,25 @@ pub struct PaymentsAuthorizeData { /// In case the connector supports only one reference id, Hyperswitch's Payment ID will be sent as reference. pub merchant_order_reference_id: Option, pub integrity_object: Option, + pub shipping_cost: Option, + pub additional_payment_method_data: Option, } #[derive(Debug, Clone)] pub struct PaymentsPostSessionTokensData { + // amount here would include amount, surcharge_amount and shipping_cost pub amount: MinorUnit, + /// original amount sent by the merchant + pub order_amount: MinorUnit, pub currency: storage_enums::Currency, pub capture_method: Option, /// Merchant's identifier for the payment/invoice. This will be sent to the connector /// if the connector provides support to accept multiple reference ids. /// In case the connector supports only one reference id, Hyperswitch's Payment ID will be sent as reference. pub merchant_order_reference_id: Option, + pub shipping_cost: Option, + pub setup_future_usage: Option, + pub router_return_url: Option, } #[derive(Debug, Clone, PartialEq)] @@ -362,7 +370,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> @@ -816,7 +824,7 @@ pub struct PaymentsSessionData { pub country: Option, pub surcharge_details: Option, pub order_details: Option>, - + pub email: Option, // Minor Unit amount for amount frame work pub minor_amount: MinorUnit, } @@ -833,10 +841,13 @@ pub struct PaymentsTaxCalculationData { #[derive(Debug, Clone, Default)] pub struct SdkPaymentsSessionUpdateData { pub order_tax_amount: MinorUnit, - pub net_amount: MinorUnit, + // amount here would include amount, surcharge_amount, order_tax_amount and shipping_cost pub amount: MinorUnit, + /// original amount sent by the merchant + pub order_amount: MinorUnit, pub currency: storage_enums::Currency, pub session_id: Option, + pub shipping_cost: Option, } #[derive(Debug, Clone)] @@ -862,4 +873,5 @@ pub struct SetupMandateRequestData { // MinorUnit for amount framework pub minor_amount: Option, + pub shipping_cost: Option, } diff --git a/crates/hyperswitch_domain_models/src/router_response_types.rs b/crates/hyperswitch_domain_models/src/router_response_types.rs index eca56b8c866f..6356301c7264 100644 --- a/crates/hyperswitch_domain_models/src/router_response_types.rs +++ b/crates/hyperswitch_domain_models/src/router_response_types.rs @@ -17,8 +17,8 @@ pub struct RefundsResponseData { pub enum PaymentsResponseData { TransactionResponse { resource_id: ResponseId, - redirection_data: Option, - mandate_reference: Option, + redirection_data: Box>, + mandate_reference: Box>, connector_metadata: Option, network_txn_id: Option, connector_response_reference_id: Option, @@ -83,6 +83,7 @@ pub struct MandateReference { pub connector_mandate_id: Option, pub payment_method_id: Option, pub mandate_metadata: Option, + pub connector_mandate_request_reference_id: Option, } #[derive(Debug, Clone)] @@ -163,6 +164,12 @@ pub enum RedirectForm { Mifinity { initialization_token: String, }, + WorldpayDDCForm { + endpoint: url::Url, + method: Method, + form_fields: HashMap, + collection_id: Option, + }, } impl From<(url::Url, Method)> for RedirectForm { diff --git a/crates/hyperswitch_domain_models/src/types.rs b/crates/hyperswitch_domain_models/src/types.rs index eeb63bbb508f..a629f8e6392a 100644 --- a/crates/hyperswitch_domain_models/src/types.rs +++ b/crates/hyperswitch_domain_models/src/types.rs @@ -2,15 +2,15 @@ use crate::{ router_data::{AccessToken, RouterData}, router_flow_types::{ AccessTokenAuth, Authorize, AuthorizeSessionToken, CalculateTax, Capture, - CompleteAuthorize, CreateConnectorCustomer, PSync, PaymentMethodToken, PostSessionTokens, - PreProcessing, RSync, SetupMandate, Void, + CompleteAuthorize, CreateConnectorCustomer, Execute, PSync, PaymentMethodToken, + PostSessionTokens, PreProcessing, RSync, Session, SetupMandate, Void, }, router_request_types::{ AccessTokenRequestData, AuthorizeSessionTokenData, CompleteAuthorizeData, ConnectorCustomerData, PaymentMethodTokenizationData, PaymentsAuthorizeData, PaymentsCancelData, PaymentsCaptureData, PaymentsPostSessionTokensData, - PaymentsPreProcessingData, PaymentsSyncData, PaymentsTaxCalculationData, RefundsData, - SetupMandateRequestData, + PaymentsPreProcessingData, PaymentsSessionData, PaymentsSyncData, + PaymentsTaxCalculationData, RefundsData, SetupMandateRequestData, }, router_response_types::{ PaymentsResponseData, RefundsResponseData, TaxCalculationResponseData, @@ -29,6 +29,7 @@ pub type PaymentsCancelRouterData = RouterData; pub type RefundsRouterData = RouterData; +pub type RefundExecuteRouterData = RouterData; pub type RefundSyncRouterData = RouterData; pub type TokenizationRouterData = RouterData; @@ -41,3 +42,4 @@ pub type PaymentsTaxCalculationRouterData = pub type RefreshTokenRouterData = RouterData; pub type PaymentsPostSessionTokensRouterData = RouterData; +pub type PaymentsSessionRouterData = RouterData; diff --git a/crates/hyperswitch_interfaces/Cargo.toml b/crates/hyperswitch_interfaces/Cargo.toml index 7ab885de3a36..99a06ff2e3a8 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/hyperswitch_interfaces/src/configs.rs b/crates/hyperswitch_interfaces/src/configs.rs index 6f9beb550549..2c631849446d 100644 --- a/crates/hyperswitch_interfaces/src/configs.rs +++ b/crates/hyperswitch_interfaces/src/configs.rs @@ -35,6 +35,7 @@ pub struct Connectors { #[cfg(feature = "dummy_connector")] pub dummyconnector: ConnectorParams, pub ebanx: ConnectorParams, + pub elavon: ConnectorParams, pub fiserv: ConnectorParams, pub fiservemea: ConnectorParams, pub fiuu: ConnectorParamsWithThreeUrls, @@ -46,6 +47,7 @@ pub struct Connectors { pub helcim: ConnectorParams, pub iatapay: ConnectorParams, pub itaubank: ConnectorParams, + pub jpmorgan: ConnectorParams, pub klarna: ConnectorParams, pub mifinity: ConnectorParams, pub mollie: ConnectorParams, diff --git a/crates/kgraph_utils/Cargo.toml b/crates/kgraph_utils/Cargo.toml index 0b7b580e647d..0883e1486915 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 dac22071c36d..26707479b0d6 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 9d58c8b7c0d6..975ff33107fa 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.rs b/crates/openapi/src/openapi.rs index 28a7f44c7a87..75d1bb9f2751 100644 --- a/crates/openapi/src/openapi.rs +++ b/crates/openapi/src/openapi.rs @@ -160,7 +160,6 @@ Never share your secret api keys. Keep them guarded and secure. routes::routing::routing_retrieve_default_config_for_profiles, routes::routing::routing_update_default_config_for_profile, routes::routing::toggle_success_based_routing, - routes::routing::success_based_routing_update_configs, // Routes for blocklist routes::blocklist::remove_entry_from_blocklist, @@ -492,7 +491,6 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payment_methods::PaymentMethodCollectLinkResponse, api_models::refunds::RefundListRequest, api_models::refunds::RefundListResponse, - api_models::refunds::RefundAggregateResponse, api_models::payments::AmountFilter, api_models::mandates::MandateRevokedResponse, api_models::mandates::MandateResponse, @@ -566,6 +564,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::routing::RoutingDictionaryRecord, api_models::routing::RoutingKind, api_models::routing::RoutableConnectorChoice, + api_models::routing::SuccessBasedRoutingFeatures, api_models::routing::LinkedRoutingConfigRetrieveResponse, api_models::routing::RoutingRetrieveResponse, api_models::routing::ProfileDefaultRoutingConfig, @@ -577,11 +576,6 @@ Never share your secret api keys. Keep them guarded and secure. api_models::routing::ConnectorVolumeSplit, api_models::routing::ConnectorSelection, api_models::routing::ToggleSuccessBasedRoutingQuery, - api_models::routing::SuccessBasedRoutingConfig, - api_models::routing::SuccessBasedRoutingConfigParams, - api_models::routing::SuccessBasedRoutingConfigBody, - api_models::routing::CurrentBlockThreshold, - api_models::routing::SuccessBasedRoutingUpdateConfigQuery, api_models::routing::ToggleSuccessBasedRoutingPath, api_models::routing::ast::RoutableChoiceKind, api_models::enums::RoutableConnectors, diff --git a/crates/openapi/src/openapi_v2.rs b/crates/openapi/src/openapi_v2.rs index bf95fbe743aa..40f694b80a23 100644 --- a/crates/openapi/src/openapi_v2.rs +++ b/crates/openapi/src/openapi_v2.rs @@ -123,10 +123,16 @@ Never share your secret api keys. Keep them guarded and secure. //Routes for payments routes::payments::payments_create_intent, + routes::payments::payments_get_intent, + routes::payments::payments_confirm_intent, + + //Routes for refunds + routes::refunds::refunds_create, ), 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, @@ -140,6 +146,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, @@ -147,7 +155,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::organization::OrganizationCreateRequest, api_models::organization::OrganizationUpdateRequest, api_models::organization::OrganizationResponse, - api_models::admin::MerchantAccountCreate, + api_models::admin::MerchantAccountCreateWithoutOrgId, api_models::admin::MerchantAccountUpdate, api_models::admin::MerchantAccountDeleteResponse, api_models::admin::MerchantConnectorDeleteResponse, @@ -310,10 +318,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, @@ -322,7 +326,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::PaymentsSessionRequest, api_models::payments::PaymentsSessionResponse, api_models::payments::PaymentsCreateIntentRequest, - api_models::payments::PaymentsCreateIntentResponse, + api_models::payments::PaymentsIntentResponse, api_models::payments::PazeWalletData, api_models::payments::AmountDetails, api_models::payments::SessionToken, @@ -410,13 +414,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, @@ -427,7 +433,6 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payment_methods::PaymentMethodCollectLinkResponse, api_models::refunds::RefundListRequest, api_models::refunds::RefundListResponse, - api_models::refunds::RefundAggregateResponse, api_models::payments::AmountFilter, api_models::mandates::MandateRevokedResponse, api_models::mandates::MandateResponse, @@ -579,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/merchant_account.rs b/crates/openapi/src/routes/merchant_account.rs index b92285245a43..01571da1de9f 100644 --- a/crates/openapi/src/routes/merchant_account.rs +++ b/crates/openapi/src/routes/merchant_account.rs @@ -51,6 +51,13 @@ pub async fn merchant_account_create() {} #[utoipa::path( post, path = "/v2/merchant_accounts", + params( + ( + "X-Organization-Id" = String, Header, + description = "Organization ID for which the merchant account has to be created.", + example = json!({"X-Organization-Id": "org_abcdefghijklmnop"}) + ), + ), request_body( content = MerchantAccountCreate, examples( @@ -58,7 +65,6 @@ pub async fn merchant_account_create() {} "Create a merchant account with minimal fields" = ( value = json!({ "merchant_name": "Cloth Store", - "organization_id": "org_abcdefghijklmnop" }) ) ), @@ -66,7 +72,6 @@ pub async fn merchant_account_create() {} "Create a merchant account with merchant details" = ( value = json!({ "merchant_name": "Cloth Store", - "organization_id": "org_abcdefghijklmnop", "merchant_details": { "primary_contact_person": "John Doe", "primary_email": "example@company.com" @@ -78,7 +83,6 @@ pub async fn merchant_account_create() {} "Create a merchant account with metadata" = ( value = json!({ "merchant_name": "Cloth Store", - "organization_id": "org_abcdefghijklmnop", "metadata": { "key_1": "John Doe", "key_2": "Trends" diff --git a/crates/openapi/src/routes/payments.rs b/crates/openapi/src/routes/payments.rs index b6a81efda09e..e245c5af68a4 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), @@ -620,7 +620,7 @@ pub fn payments_post_session_tokens() {} ), ), responses( - (status = 200, description = "Payment created", body = PaymentsCreateIntentResponse), + (status = 200, description = "Payment created", body = PaymentsIntentResponse), (status = 400, description = "Missing Mandatory fields") ), tag = "Payments", @@ -629,3 +629,62 @@ pub fn payments_post_session_tokens() {} )] #[cfg(feature = "v2")] pub fn payments_create_intent() {} + +/// Payments - Get Intent +/// +/// **Get a payment intent object when id is passed in path** +/// +/// You will require the 'API - Key' from the Hyperswitch dashboard to make the call. +#[utoipa::path( + get, + path = "/v2/payments/{id}/get-intent", + params (("id" = String, Path, description = "The unique identifier for the Payment Intent")), + responses( + (status = 200, description = "Payment Intent", body = PaymentsIntentResponse), + (status = 404, description = "Payment Intent not found") + ), + tag = "Payments", + operation_id = "Get the Payment Intent details", + security(("api_key" = [])), +)] +#[cfg(feature = "v2")] +pub fn payments_get_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/openapi/src/routes/refunds.rs b/crates/openapi/src/routes/refunds.rs index 5c72fe8b48fe..4e096e243a82 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/openapi/src/routes/routing.rs b/crates/openapi/src/routes/routing.rs index 009708d860d0..0bb79a2bbe47 100644 --- a/crates/openapi/src/routes/routing.rs +++ b/crates/openapi/src/routes/routing.rs @@ -266,7 +266,7 @@ pub async fn routing_update_default_config_for_profile() {} params( ("account_id" = String, Path, description = "Merchant id"), ("profile_id" = String, Path, description = "Profile id under which Dynamic routing needs to be toggled"), - ("status" = bool, Query, description = "Boolean value for mentioning the expected state of dynamic routing"), + ("enable" = SuccessBasedRoutingFeatures, Query, description = "Feature to enable for success based routing"), ), responses( (status = 200, description = "Routing Algorithm created", body = RoutingDictionaryRecord), @@ -281,30 +281,3 @@ pub async fn routing_update_default_config_for_profile() {} security(("api_key" = []), ("jwt_key" = [])) )] pub async fn toggle_success_based_routing() {} - -#[cfg(feature = "v1")] -/// Routing - Update config for success based dynamic routing -/// -/// Update config for success based dynamic routing -#[utoipa::path( - patch, - path = "/account/:account_id/business_profile/:profile_id/dynamic_routing/success_based/config/:algorithm_id", - request_body = SuccessBasedRoutingConfig, - params( - ("account_id" = String, Path, description = "Merchant id"), - ("profile_id" = String, Path, description = "The unique identifier for a profile"), - ("algorithm_id" = String, Path, description = "The unique identifier for routing algorithm"), - ), - responses( - (status = 200, description = "Routing Algorithm updated", body = RoutingDictionaryRecord), - (status = 400, description = "Request body is malformed"), - (status = 500, description = "Internal server error"), - (status = 404, description = "Resource missing"), - (status = 422, description = "Unprocessable request"), - (status = 403, description = "Forbidden"), - ), - tag = "Routing", - operation_id = "Update configs for success based dynamic routing algorithm", - security(("admin_api_key" = [])) -)] -pub async fn success_based_routing_update_configs() {} diff --git a/crates/pm_auth/Cargo.toml b/crates/pm_auth/Cargo.toml index df8136ba8332..3923d44b7fad 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 d2763fa7997b..f6e1f0efc69f 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", "api_models/dynamic_routing"] @@ -115,6 +115,7 @@ tracing-futures = { version = "0.2.5", features = ["tokio"] } unicode-segmentation = "1.11.0" unidecode = "0.3.0" url = { version = "2.5.0", features = ["serde"] } +urlencoding = "2.1.3" utoipa = { version = "4.2.0", features = ["preserve_order", "preserve_path_order", "time"] } uuid = { version = "1.8.0", features = ["v4"] } validator = "0.17.0" diff --git a/crates/router/src/analytics.rs b/crates/router/src/analytics.rs index aa6db56bb348..aba1c2e2efaa 100644 --- a/crates/router/src/analytics.rs +++ b/crates/router/src/analytics.rs @@ -32,7 +32,10 @@ pub mod routes { use crate::{ consts::opensearch::SEARCH_INDEXES, - core::{api_locking, errors::user::UserErrors, verification::utils}, + core::{ + api_locking, currency::get_forex_exchange_rates, errors::user::UserErrors, + verification::utils, + }, db::{user::UserInterface, user_role::ListUserRolesByUserIdPayload}, routes::AppState, services::{ @@ -397,13 +400,13 @@ pub mod routes { org_id: org_id.clone(), merchant_ids: vec![merchant_id.clone()], }; - analytics::payments::get_metrics(&state.pool, &auth, req) + let ex_rates = get_forex_exchange_rates(state.clone()).await?; + analytics::payments::get_metrics(&state.pool, &ex_rates, &auth, req) .await .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -436,13 +439,13 @@ pub mod routes { let auth: AuthInfo = AuthInfo::OrgLevel { org_id: org_id.clone(), }; - analytics::payments::get_metrics(&state.pool, &auth, req) + let ex_rates = get_forex_exchange_rates(state.clone()).await?; + analytics::payments::get_metrics(&state.pool, &ex_rates, &auth, req) .await .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Organization, + permission: Permission::OrganizationAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -482,13 +485,13 @@ pub mod routes { merchant_id: merchant_id.clone(), profile_ids: vec![profile_id.clone()], }; - analytics::payments::get_metrics(&state.pool, &auth, req) + let ex_rates = get_forex_exchange_rates(state.clone()).await?; + analytics::payments::get_metrics(&state.pool, &ex_rates, &auth, req) .await .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -523,13 +526,13 @@ pub mod routes { org_id: org_id.clone(), merchant_ids: vec![merchant_id.clone()], }; - analytics::payment_intents::get_metrics(&state.pool, &auth, req) + let ex_rates = get_forex_exchange_rates(state.clone()).await?; + analytics::payment_intents::get_metrics(&state.pool, &ex_rates, &auth, req) .await .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -562,13 +565,13 @@ pub mod routes { let auth: AuthInfo = AuthInfo::OrgLevel { org_id: org_id.clone(), }; - analytics::payment_intents::get_metrics(&state.pool, &auth, req) + let ex_rates = get_forex_exchange_rates(state.clone()).await?; + analytics::payment_intents::get_metrics(&state.pool, &ex_rates, &auth, req) .await .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Organization, + permission: Permission::OrganizationAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -608,13 +611,13 @@ pub mod routes { merchant_id: merchant_id.clone(), profile_ids: vec![profile_id.clone()], }; - analytics::payment_intents::get_metrics(&state.pool, &auth, req) + let ex_rates = get_forex_exchange_rates(state.clone()).await?; + analytics::payment_intents::get_metrics(&state.pool, &ex_rates, &auth, req) .await .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -654,8 +657,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -693,8 +695,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Organization, + permission: Permission::OrganizationAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -739,8 +740,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -774,8 +774,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -813,8 +812,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -853,8 +851,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -893,8 +890,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -924,8 +920,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -953,8 +948,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Organization, + permission: Permission::OrganizationAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -989,8 +983,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -1018,8 +1011,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -1049,8 +1041,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -1078,8 +1069,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Organization, + permission: Permission::OrganizationAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -1114,8 +1104,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -1139,8 +1128,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -1168,8 +1156,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -1201,8 +1188,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -1235,8 +1221,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -1267,8 +1252,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -1318,8 +1302,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::GenerateReport, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantReportRead, }, api_locking::LockAction::NotApplicable, )) @@ -1367,8 +1350,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::GenerateReport, - minimum_entity_level: EntityType::Organization, + permission: Permission::OrganizationReportRead, }, api_locking::LockAction::NotApplicable, )) @@ -1423,8 +1405,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::GenerateReport, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileReportRead, }, api_locking::LockAction::NotApplicable, )) @@ -1474,8 +1455,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::GenerateReport, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantReportRead, }, api_locking::LockAction::NotApplicable, )) @@ -1523,8 +1503,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::GenerateReport, - minimum_entity_level: EntityType::Organization, + permission: Permission::OrganizationReportRead, }, api_locking::LockAction::NotApplicable, )) @@ -1579,8 +1558,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::GenerateReport, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileReportRead, }, api_locking::LockAction::NotApplicable, )) @@ -1630,8 +1608,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::GenerateReport, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantReportRead, }, api_locking::LockAction::NotApplicable, )) @@ -1679,8 +1656,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::GenerateReport, - minimum_entity_level: EntityType::Organization, + permission: Permission::OrganizationReportRead, }, api_locking::LockAction::NotApplicable, )) @@ -1734,8 +1710,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::GenerateReport, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileReportRead, }, api_locking::LockAction::NotApplicable, )) @@ -1773,8 +1748,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -1798,8 +1772,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Profile, + permission: Permission::MerchantAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -1830,8 +1803,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -1948,8 +1920,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -2065,8 +2036,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -2096,8 +2066,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -2132,8 +2101,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -2161,8 +2129,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Organization, + permission: Permission::OrganizationAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -2202,8 +2169,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -2248,8 +2214,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -2287,8 +2252,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Organization, + permission: Permission::OrganizationAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -2319,8 +2283,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -2349,8 +2312,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Organization, + permission: Permission::OrganizationAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) @@ -2386,8 +2348,7 @@ pub mod routes { .map(ApplicationResponse::Json) }, &auth::JWTAuth { - permission: Permission::Analytics, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileAnalyticsRead, }, api_locking::LockAction::NotApplicable, )) diff --git a/crates/router/src/compatibility/stripe/payment_intents.rs b/crates/router/src/compatibility/stripe/payment_intents.rs index 901ca3c11c27..e447e9b95357 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 e5e68fb4a856..66b43e4ebe90 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/compatibility/stripe/webhooks.rs b/crates/router/src/compatibility/stripe/webhooks.rs index 8445011f569f..ddc291e6b139 100644 --- a/crates/router/src/compatibility/stripe/webhooks.rs +++ b/crates/router/src/compatibility/stripe/webhooks.rs @@ -81,7 +81,7 @@ impl OutgoingWebhookType for StripeOutgoingWebhook { #[derive(Serialize, Debug)] #[serde(tag = "type", content = "object", rename_all = "snake_case")] pub enum StripeWebhookObject { - PaymentIntent(StripePaymentIntentResponse), + PaymentIntent(Box), Refund(StripeRefundResponse), Dispute(StripeDisputeResponse), Mandate(StripeMandateResponse), @@ -327,9 +327,9 @@ impl From for StripeWebhookObject { fn from(value: api::OutgoingWebhookContent) -> Self { match value { api::OutgoingWebhookContent::PaymentDetails(payment) => { - Self::PaymentIntent(payment.into()) + Self::PaymentIntent(Box::new((*payment).into())) } - api::OutgoingWebhookContent::RefundDetails(refund) => Self::Refund(refund.into()), + api::OutgoingWebhookContent::RefundDetails(refund) => Self::Refund((*refund).into()), api::OutgoingWebhookContent::DisputeDetails(dispute) => { Self::Dispute((*dispute).into()) } @@ -337,7 +337,7 @@ impl From for StripeWebhookObject { Self::Mandate((*mandate).into()) } #[cfg(feature = "payouts")] - api::OutgoingWebhookContent::PayoutDetails(payout) => Self::Payout(payout.into()), + api::OutgoingWebhookContent::PayoutDetails(payout) => Self::Payout((*payout).into()), } } } diff --git a/crates/router/src/configs/defaults.rs b/crates/router/src/configs/defaults.rs index e94ad375776e..74f6502159da 100644 --- a/crates/router/src/configs/defaults.rs +++ b/crates/router/src/configs/defaults.rs @@ -2,11 +2,11 @@ use std::collections::{HashMap, HashSet}; use api_models::{enums, payment_methods::RequiredFieldInfo}; -use super::settings::{ConnectorFields, PaymentMethodType, RequiredFieldFinal}; - #[cfg(feature = "payouts")] pub mod payout_required_fields; +pub mod payment_connector_required_fields; + impl Default for super::settings::Server { fn default() -> Self { Self { @@ -138,12528 +138,6 @@ impl Default for super::settings::KvConfig { } } -use super::settings::{ - Mandates, SupportedConnectorsForMandate, SupportedPaymentMethodTypesForMandate, - SupportedPaymentMethodsForMandate, -}; - -impl Default for Mandates { - fn default() -> Self { - Self { - supported_payment_methods: SupportedPaymentMethodsForMandate(HashMap::from([ - ( - enums::PaymentMethod::PayLater, - SupportedPaymentMethodTypesForMandate(HashMap::from([( - enums::PaymentMethodType::Klarna, - SupportedConnectorsForMandate { - connector_list: HashSet::from([enums::Connector::Adyen]), - }, - )])), - ), - ( - enums::PaymentMethod::Wallet, - SupportedPaymentMethodTypesForMandate(HashMap::from([ - ( - enums::PaymentMethodType::GooglePay, - SupportedConnectorsForMandate { - connector_list: HashSet::from([ - enums::Connector::Stripe, - enums::Connector::Adyen, - enums::Connector::Globalpay, - enums::Connector::Multisafepay, - enums::Connector::Bankofamerica, - enums::Connector::Noon, - enums::Connector::Cybersource, - enums::Connector::Wellsfargo, - ]), - }, - ), - ( - enums::PaymentMethodType::ApplePay, - SupportedConnectorsForMandate { - connector_list: HashSet::from([ - enums::Connector::Stripe, - enums::Connector::Adyen, - enums::Connector::Bankofamerica, - enums::Connector::Cybersource, - enums::Connector::Wellsfargo, - ]), - }, - ), - ])), - ), - ( - enums::PaymentMethod::Card, - SupportedPaymentMethodTypesForMandate(HashMap::from([ - ( - enums::PaymentMethodType::Credit, - SupportedConnectorsForMandate { - connector_list: HashSet::from([ - enums::Connector::Aci, - enums::Connector::Adyen, - enums::Connector::Authorizedotnet, - enums::Connector::Globalpay, - enums::Connector::Worldpay, - enums::Connector::Multisafepay, - enums::Connector::Nexinets, - enums::Connector::Noon, - enums::Connector::Payme, - enums::Connector::Stripe, - enums::Connector::Bankofamerica, - enums::Connector::Cybersource, - enums::Connector::Wellsfargo, - ]), - }, - ), - ( - enums::PaymentMethodType::Debit, - SupportedConnectorsForMandate { - connector_list: HashSet::from([ - enums::Connector::Aci, - enums::Connector::Adyen, - enums::Connector::Authorizedotnet, - enums::Connector::Globalpay, - enums::Connector::Worldpay, - enums::Connector::Multisafepay, - enums::Connector::Nexinets, - enums::Connector::Noon, - enums::Connector::Payme, - enums::Connector::Stripe, - ]), - }, - ), - ])), - ), - ])), - update_mandate_supported: SupportedPaymentMethodsForMandate(HashMap::default()), - } - } -} - -impl Default for super::settings::RequiredFields { - fn default() -> Self { - Self(HashMap::from([ - ( - enums::PaymentMethod::Card, - PaymentMethodType(HashMap::from([ - ( - enums::PaymentMethodType::Debit, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Aci, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ] - ), - } - ), - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ] - ), - } - ), - ( - enums::Connector::Airwallex, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Authorizedotnet, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Bambora, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Bankofamerica, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "email".to_string(), - RequiredFieldInfo { - required_field: "email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.state".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserAddressState, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Billwerk, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Bluesnap, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "email".to_string(), - RequiredFieldInfo { - required_field: "email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Boku, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Braintree, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Checkout, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Coinbase, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Cybersource, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common:HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.state".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserAddressState, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Dlocal, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ) - ] - ), - common:HashMap::new(), - } - ), - #[cfg(feature = "dummy_connector")] - ( - enums::Connector::DummyConnector1, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - #[cfg(feature = "dummy_connector")] - ( - enums::Connector::DummyConnector2, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - #[cfg(feature = "dummy_connector")] - ( - enums::Connector::DummyConnector3, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - #[cfg(feature = "dummy_connector")] - ( - enums::Connector::DummyConnector4, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - #[cfg(feature = "dummy_connector")] - ( - enums::Connector::DummyConnector5, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - #[cfg(feature = "dummy_connector")] - ( - enums::Connector::DummyConnector6, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - #[cfg(feature = "dummy_connector")] - ( - enums::Connector::DummyConnector7, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Fiserv, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Fiuu, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Forte, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ] - ), - common:HashMap::new(), - } - ), - ( - enums::Connector::Globalpay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ]), - } - ), - ( - enums::Connector::Helcim, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Iatapay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Mollie, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Multisafepay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate:HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.line2".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line2".to_string(), - display_name: "line2".to_string(), - field_type: enums::FieldType::UserAddressLine2, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Nexinets, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Nmi, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "billing_zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Noon, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ] - ), - } - ), - ( - enums::Connector::Novalnet, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "browser_info.language".to_string(), - RequiredFieldInfo { - required_field: "browser_info.language".to_string(), - display_name: "browser_info_language".to_string(), - field_type: enums::FieldType::BrowserLanguage, - value: None, - } - ), - ( - "browser_info.ip_address".to_string(), - RequiredFieldInfo { - required_field: "browser_info.ip_address".to_string(), - display_name: "browser_info_ip_address".to_string(), - field_type: enums::FieldType::BrowserIp, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.line2".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line2".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine2, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "first_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "last_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email_address".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ] - ), - } - ), - ( - enums::Connector::Nuvei, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Paybox, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "email".to_string(), - RequiredFieldInfo { - required_field: "email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ) - - ] - ), - } - ), - ( - enums::Connector::Payme, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "email".to_string(), - RequiredFieldInfo { - required_field: "email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ] - ), - } - ), - ( - enums::Connector::Paypal, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Payu, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Powertranz, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Rapyd, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Shift4, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Square, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Stax, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common:HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Trustpay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ), - ] - ), - common: HashMap::new() - } - ), - ( - enums::Connector::Tsys, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - common: HashMap::new() - } - ), - ( - enums::Connector::Wellsfargo, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common:HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "email".to_string(), - RequiredFieldInfo { - required_field: "email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.state".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserAddressState, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Worldline, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ) - ]), - common: HashMap::new(), - } - ), - ( - enums::Connector::Worldpay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ) - ]), - common: HashMap::new(), - } - ), - ( - enums::Connector::Zen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "email".to_string(), - RequiredFieldInfo { - required_field: "email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ]), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::Credit, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Aci, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ] - ), - } - ), - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ] - ), - } - ), - ( - enums::Connector::Airwallex, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Authorizedotnet, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Bambora, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Bankofamerica, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "email".to_string(), - RequiredFieldInfo { - required_field: "email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.state".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserAddressState, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ] - ), - } - ), - ( - enums::Connector::Billwerk, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Bluesnap, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "email".to_string(), - RequiredFieldInfo { - required_field: "email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Boku, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Braintree, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Checkout, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Coinbase, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Cybersource, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate:HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.state".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserAddressState, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Dlocal, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ) - ] - ), - common:HashMap::new(), - } - ), - #[cfg(feature = "dummy_connector")] - ( - enums::Connector::DummyConnector1, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - #[cfg(feature = "dummy_connector")] - ( - enums::Connector::DummyConnector2, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - #[cfg(feature = "dummy_connector")] - ( - enums::Connector::DummyConnector3, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - #[cfg(feature = "dummy_connector")] - ( - enums::Connector::DummyConnector4, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - #[cfg(feature = "dummy_connector")] - ( - enums::Connector::DummyConnector5, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - #[cfg(feature = "dummy_connector")] - ( - enums::Connector::DummyConnector6, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - #[cfg(feature = "dummy_connector")] - ( - enums::Connector::DummyConnector7, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Fiserv, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Fiuu, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Forte, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ] - ), - common:HashMap::new(), - } - ), - ( - enums::Connector::Globalpay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ]), - } - ), - ( - enums::Connector::Helcim, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Iatapay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Mollie, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Multisafepay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate:HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.line2".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line2".to_string(), - display_name: "line2".to_string(), - field_type: enums::FieldType::UserAddressLine2, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Nexinets, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Nexixpay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.line2".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line2".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine2, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "first_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "last_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Nmi, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "billing_zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Noon, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ] - ), - } - ), - ( - enums::Connector::Novalnet, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "browser_info.language".to_string(), - RequiredFieldInfo { - required_field: "browser_info.language".to_string(), - display_name: "browser_info_language".to_string(), - field_type: enums::FieldType::BrowserLanguage, - value: None, - } - ), - ( - "browser_info.ip_address".to_string(), - RequiredFieldInfo { - required_field: "browser_info.ip_address".to_string(), - display_name: "browser_info_ip_address".to_string(), - field_type: enums::FieldType::BrowserIp, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.line2".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line2".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine2, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "first_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "last_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email_address".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ] - ), - } - ), - ( - enums::Connector::Nuvei, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ),( - enums::Connector::Paybox, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "email".to_string(), - RequiredFieldInfo { - required_field: "email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ) - - ] - ), - } - ), - ( - enums::Connector::Payme, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "email".to_string(), - RequiredFieldInfo { - required_field: "email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ] - ), - } - ), - ( - enums::Connector::Paypal, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Payu, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Powertranz, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Rapyd, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Shift4, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Square, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Stax, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common:HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Trustpay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ), - ] - ), - common: HashMap::new() - } - ), - ( - enums::Connector::Tsys, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ) - ] - ), - common: HashMap::new() - } - ), - ( - enums::Connector::Wellsfargo, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate:HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "email".to_string(), - RequiredFieldInfo { - required_field: "email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.state".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserAddressState, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ) - ] - ), - } - ), - ( - enums::Connector::Worldline, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "payment_method_data.card.card_cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_cvc".to_string(), - display_name: "card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ) - ]), - common: HashMap::new(), - } - ), - ( - enums::Connector::Worldpay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ) - ]), - common: HashMap::new(), - } - ), - ( - enums::Connector::Zen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "payment_method_data.card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "email".to_string(), - RequiredFieldInfo { - required_field: "email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ]), - common: HashMap::new(), - } - ), - ]), - }, - ), - - ])), - ), - ( - enums::PaymentMethod::BankRedirect, - PaymentMethodType(HashMap::from([ - ( - enums::PaymentMethodType::OpenBankingUk, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Volt, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_last_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ]), - common: HashMap::new(), - } - ), - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap:: from([ - ( - "payment_method_data.bank_redirect.open_banking_uk.issuer".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_redirect.open_banking_uk.issuer".to_string(), - display_name: "issuer".to_string(), - field_type: enums::FieldType::UserBank, - value: None, - } - ) - ]), - common: HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::Trustly, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::OnlineBankingCzechRepublic, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "payment_method_data.bank_redirect.open_banking_czech_republic.issuer".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_redirect.open_banking_czech_republic.issuer".to_string(), - display_name: "issuer".to_string(), - field_type: enums::FieldType::UserBank, - value: None, - } - ) - ]), - common: HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::OnlineBankingFinland, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ]), - common: HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::OnlineBankingPoland, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "payment_method_data.bank_redirect.open_banking_poland.issuer".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_redirect.open_banking_poland.issuer".to_string(), - display_name: "issuer".to_string(), - field_type: enums::FieldType::UserBank, - value: None, - } - ), - - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ]), - common: HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::OnlineBankingSlovakia, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "payment_method_data.bank_redirect.open_banking_slovakia.issuer".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_redirect.open_banking_slovakia.issuer".to_string(), - display_name: "issuer".to_string(), - field_type: enums::FieldType::UserBank, - value: None, - } - ), - ]), - common: HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::OnlineBankingFpx, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "payment_method_data.bank_redirect.open_banking_fpx.issuer".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_redirect.open_banking_fpx.issuer".to_string(), - display_name: "issuer".to_string(), - field_type: enums::FieldType::UserBank, - value: None, - } - ) - ]), - common: HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::OnlineBankingThailand, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "payment_method_data.bank_redirect.open_banking_thailand.issuer".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_redirect.open_banking_thailand.issuer".to_string(), - display_name: "issuer".to_string(), - field_type: enums::FieldType::UserBank, - value: None, - } - ) - ]), - common: HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::Bizum, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::Przelewy24, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ) - ]), - common: HashMap::new(), - } - )]), - }, - ), - ( - enums::PaymentMethodType::BancontactCard, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Mollie, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate: HashMap::from([ - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ) - ]), - non_mandate: HashMap::new(), - common: HashMap::from([ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ]), - } - ), - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ - ( - "payment_method_data.bank_redirect.bancontact_card.card_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_redirect.bancontact_card.card_number".to_string(), - display_name: "card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.bank_redirect.bancontact_card.card_exp_month".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_redirect.bancontact_card.card_exp_month".to_string(), - display_name: "card_exp_month".to_string(), - field_type: enums::FieldType::UserCardExpiryMonth, - value: None, - } - ), - ( - "payment_method_data.bank_redirect.bancontact_card.card_exp_year".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_redirect.bancontact_card.card_exp_year".to_string(), - display_name: "card_exp_year".to_string(), - field_type: enums::FieldType::UserCardExpiryYear, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ]), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::Giropay, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Aci, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserCountry { - options: vec![ - "DE".to_string(), - ]}, - value: None, - } - ) - ]), - common: HashMap::new(), - } - ), - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Globalpay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ - ("billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry { - options: vec![ - "DE".to_string(), - ] - }, - value: None, - } - ) - ]), - } - ), - ( - enums::Connector::Mollie, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Nuvei, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate:HashMap::from([ - ( - "email".to_string(), - RequiredFieldInfo { - required_field: "email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_last_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "DE".to_string(), - ] - }, - value: None, - } - )] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Paypal, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserCountry { - options: vec![ - "DE".to_string(), - ] - }, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ) - ]), - common: HashMap::new(), - } - ), - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ) - ]), - common: HashMap::new(), - } - ), - ( - enums::Connector::Shift4, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Trustpay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry { - options: vec![ - "DE".to_string(), - ] - }, - value: None, - } - ), - ]), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::Ideal, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Aci, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "payment_method_data.bank_redirect.ideal.bank_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_redirect.ideal.bank_name".to_string(), - display_name: "bank_name".to_string(), - field_type: enums::FieldType::UserBank, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserCountry { - options: vec![ - "NL".to_string(), - ] - }, - value: None, - } - ) - ]), - common: HashMap::new(), - } - ), - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ - ( - "payment_method_data.bank_redirect.ideal.bank_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_redirect.ideal.bank_name".to_string(), - display_name: "bank_name".to_string(), - field_type: enums::FieldType::UserBank, - value: None, - } - ), - - ]), - } - ), - ( - enums::Connector::Globalpay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Mollie, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Nexinets, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Nuvei, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "email".to_string(), - RequiredFieldInfo { - required_field: "email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_last_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "NL".to_string(), - ] - }, - value: None, - } - ) - ]), - common: HashMap::new(), - } - ), - ( - enums::Connector::Shift4, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserCountry{ - options: vec![ - "NL".to_string(), - ] - }, - value: None, - } - ) - ]), - common: HashMap::new(), - } - ), - ( - enums::Connector::Paypal, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserCountry{ - options: vec![ - "NL".to_string(), - ] - }, - value: None, - } - ) - ]), - common: HashMap::new(), - } - ), - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate: HashMap::from([ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "billing_email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ) - ]), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Trustpay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "NL".to_string(), - ] - }, - value: None, - } - ), - ]), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::Sofort, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Aci, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ("billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserCountry { - options: vec![ - "ES".to_string(), - "GB".to_string(), - "SE".to_string(), - "AT".to_string(), - "NL".to_string(), - "DE".to_string(), - "CH".to_string(), - "BE".to_string(), - "FR".to_string(), - "FI".to_string(), - "IT".to_string(), - "PL".to_string(), - ] - }, - value: None, - } - ) - ]), - common: HashMap::new(), - } - ), - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Globalpay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ - ("billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry { - options: vec![ - "AT".to_string(), - "BE".to_string(), - "DE".to_string(), - "ES".to_string(), - "IT".to_string(), - "NL".to_string(), - ] - }, - value: None, - } - ) - ]), - } - ), - ( - enums::Connector::Mollie, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Nexinets, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Nuvei, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate:HashMap::from([ - ( - "email".to_string(), - RequiredFieldInfo { - required_field: "email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_last_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ES".to_string(), - "GB".to_string(), - "IT".to_string(), - "DE".to_string(), - "FR".to_string(), - "AT".to_string(), - "BE".to_string(), - "NL".to_string(), - "BE".to_string(), - "SK".to_string(), - ] - }, - value: None, - } - )] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Paypal, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserCountry { - options: vec![ - "ES".to_string(), - "GB".to_string(), - "AT".to_string(), - "NL".to_string(), - "DE".to_string(), - "BE".to_string(), - ] - }, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ) - ]), - common: HashMap::new(), - } - ), - ( - enums::Connector::Shift4, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate: HashMap::from([ - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ) - ]), - non_mandate : HashMap::new(), - common: HashMap::from([ - ("billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserCountry { - options: vec![ - "ES".to_string(), - "AT".to_string(), - "NL".to_string(), - "DE".to_string(), - "BE".to_string(), - ] - }, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "account_holder_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "account_holder_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - )]), - } - ), - ( - enums::Connector::Trustpay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry { - options: vec![ - "ES".to_string(), - "GB".to_string(), - "SE".to_string(), - "AT".to_string(), - "NL".to_string(), - "DE".to_string(), - "CH".to_string(), - "BE".to_string(), - "FR".to_string(), - "FI".to_string(), - "IT".to_string(), - "PL".to_string(), - ] - }, - value: None, - } - ), - ]), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::Eps, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ - ( - "payment_method_data.bank_redirect.eps.bank_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_redirect.eps.bank_name".to_string(), - display_name: "bank_name".to_string(), - field_type: enums::FieldType::UserBank, - value: None, - } - ) - ]), - } - ), - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ]), - common: HashMap::new(), - } - ), - ( - enums::Connector::Aci, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "bank_account_country".to_string(), - field_type: enums::FieldType::UserCountry { - options: vec![ - "AT".to_string(), - ] - }, - value: None, - } - ) - ]), - common: HashMap::new(), - } - ), - ( - enums::Connector::Globalpay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry { - options: vec![ - "AT".to_string(), - ] - }, - value: None, - } - ) - ]) - } - ), - ( - enums::Connector::Mollie, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate:HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Paypal, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "bank_account_country".to_string(), - field_type: enums::FieldType::UserCountry { - options: vec![ - "AT".to_string(), - ] - }, - value: None, - } - ) - ]), - common: HashMap::new(), - } - ), - ( - enums::Connector::Trustpay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "AT".to_string(), - ] - }, - value: None, - } - ), - ]), - common: HashMap::new(), - } - ), - ( - enums::Connector::Shift4, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate:HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Nuvei, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "email".to_string(), - RequiredFieldInfo { - required_field: "email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_last_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "AT".to_string(), - ] - }, - value: None, - } - )] - ), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::Blik, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ - ( - "payment_method_data.bank_redirect.blik.blik_code".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_redirect.blik.blik_code".to_string(), - display_name: "blik_code".to_string(), - field_type: enums::FieldType::UserBlikCode, - value: None, - } - ) - ]), - } - ), - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ - ( - "payment_method_data.bank_redirect.blik.blik_code".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_redirect.blik.blik_code".to_string(), - display_name: "blik_code".to_string(), - field_type: enums::FieldType::UserBlikCode, - value: None, - } - ) - ]), - } - ), - ( - enums::Connector::Trustpay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ - ( - "email".to_string(), - RequiredFieldInfo { - required_field: "email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_last_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ), - ]), - } - ) - ]), - }, - ), - ])), - ), - ( - enums::PaymentMethod::Wallet, - PaymentMethodType(HashMap::from([ - ( - enums::PaymentMethodType::ApplePay, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Bankofamerica, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "email".to_string(), - RequiredFieldInfo { - required_field: "email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_last_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.state".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserAddressState, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Cybersource, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_last_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.state".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserAddressState, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Wellsfargo, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "email".to_string(), - RequiredFieldInfo { - required_field: "email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_last_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.state".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserAddressState, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "shipping.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.first_name".to_string(), - display_name: "shipping_first_name".to_string(), - field_type: enums::FieldType::UserShippingName, - value: None, - } - ), - ( - "shipping.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.last_name".to_string(), - display_name: "shipping_last_name".to_string(), - field_type: enums::FieldType::UserShippingName, - value: None, - } - ), - ( - "shipping.address.city".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserShippingAddressCity, - value: None, - } - ), - ( - "shipping.address.state".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserShippingAddressState, - value: None, - } - ), - ( - "shipping.address.zip".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserShippingAddressPincode, - value: None, - } - ), - ( - "shipping.address.country".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserShippingAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ), - ( - "shipping.address.line1".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserShippingAddressLine1, - value: None, - } - ), - ] - ), - common: HashMap::new(), - } - ), - - ]), - }, - ), - ( - enums::PaymentMethodType::GooglePay, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Bankofamerica, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "email".to_string(), - RequiredFieldInfo { - required_field: "email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_last_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.state".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserAddressState, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Bluesnap, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Noon, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Nuvei, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Airwallex, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Authorizedotnet, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Checkout, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Globalpay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Multisafepay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_last_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.state".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserAddressState, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.line2".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line2".to_string(), - display_name: "line2".to_string(), - field_type: enums::FieldType::UserAddressLine2, - value: None, - } - )]), - common: HashMap::new(), - } - ), - ( - enums::Connector::Cybersource, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_last_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.state".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserAddressState, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ( - enums::Connector::Payu, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Rapyd, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Trustpay, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Wellsfargo, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "email".to_string(), - RequiredFieldInfo { - required_field: "email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_last_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.state".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserAddressState, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "shipping.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.first_name".to_string(), - display_name: "shipping_first_name".to_string(), - field_type: enums::FieldType::UserShippingName, - value: None, - } - ), - ( - "shipping.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.last_name".to_string(), - display_name: "shipping_last_name".to_string(), - field_type: enums::FieldType::UserShippingName, - value: None, - } - ), - ( - "shipping.address.city".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserShippingAddressCity, - value: None, - } - ), - ( - "shipping.address.state".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserShippingAddressState, - value: None, - } - ), - ( - "shipping.address.zip".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserShippingAddressPincode, - value: None, - } - ), - ( - "shipping.address.country".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserShippingAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ), - ( - "shipping.address.line1".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserShippingAddressLine1, - value: None, - } - ), - ] - ), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::WeChatPay, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::AliPay, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::AliPayHk, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::Cashapp, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::MbWay, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - common: HashMap::new(), - non_mandate: HashMap::from([ - ( - "payment_method_data.billing.phone.number".to_string(), - RequiredFieldInfo { - required_field: "billing.phone.number".to_string(), - display_name: "phone_number".to_string(), - field_type: enums::FieldType::UserPhoneNumber, - value: None, - } - ), - ( - "billing.phone.country_code".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.country_code".to_string(), - display_name: "dialing_code".to_string(), - field_type: enums::FieldType::UserPhoneNumberCountryCode, - value: None, - } - ), - ] - ), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::KakaoPay, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::Twint, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::Gcash, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::Vipps, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::Dana, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::Momo, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::Swish, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::TouchNGo, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - // Added shipping fields for the SDK flow to accept it from wallet directly, - // this won't show up in SDK in payment's sheet but will be used in the background - enums::PaymentMethodType::Paypal, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - )] - ), - } - ), - ( - enums::Connector::Braintree, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Paypal, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new( - ), - common: HashMap::from( - [ - ( - "shipping.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.first_name".to_string(), - display_name: "shipping_first_name".to_string(), - field_type: enums::FieldType::UserShippingName, - value: None, - } - ), - ( - "shipping.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.last_name".to_string(), - display_name: "shipping_last_name".to_string(), - field_type: enums::FieldType::UserShippingName, - value: None, - } - ), - ( - "shipping.address.city".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserShippingAddressCity, - value: None, - } - ), - ( - "shipping.address.state".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserShippingAddressState, - value: None, - } - ), - ( - "shipping.address.zip".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserShippingAddressPincode, - value: None, - } - ), - ( - "shipping.address.country".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserShippingAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ), - ( - "shipping.address.line1".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserShippingAddressLine1, - value: None, - } - ), - ] - ), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::Mifinity, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Mifinity, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ - ( - "payment_method_data.wallet.mifinity.date_of_birth".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.wallet.mifinity.date_of_birth".to_string(), - display_name: "date_of_birth".to_string(), - field_type: enums::FieldType::UserDateOfBirth, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "first_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "last_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.phone.number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.number".to_string(), - display_name: "phone".to_string(), - field_type: enums::FieldType::UserPhoneNumber, - value: None, - } - ), - ( - "billing.phone.country_code".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.country_code".to_string(), - display_name: "dialing_code".to_string(), - field_type: enums::FieldType::UserPhoneNumberCountryCode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "nationality".to_string(), - field_type: enums::FieldType::UserCountry{ - options: vec![ - "BR".to_string(), - "CN".to_string(), - "SG".to_string(), - "MY".to_string(), - "DE".to_string(), - "CH".to_string(), - "DK".to_string(), - "GB".to_string(), - "ES".to_string(), - "AD".to_string(), - "GI".to_string(), - "FI".to_string(), - "FR".to_string(), - "GR".to_string(), - "HR".to_string(), - "IT".to_string(), - "JP".to_string(), - "MX".to_string(), - "AR".to_string(), - "CO".to_string(), - "CL".to_string(), - "PE".to_string(), - "VE".to_string(), - "UY".to_string(), - "PY".to_string(), - "BO".to_string(), - "EC".to_string(), - "GT".to_string(), - "HN".to_string(), - "SV".to_string(), - "NI".to_string(), - "CR".to_string(), - "PA".to_string(), - "DO".to_string(), - "CU".to_string(), - "PR".to_string(), - "NL".to_string(), - "NO".to_string(), - "PL".to_string(), - "PT".to_string(), - "SE".to_string(), - "RU".to_string(), - "TR".to_string(), - "TW".to_string(), - "HK".to_string(), - "MO".to_string(), - "AX".to_string(), - "AL".to_string(), - "DZ".to_string(), - "AS".to_string(), - "AO".to_string(), - "AI".to_string(), - "AG".to_string(), - "AM".to_string(), - "AW".to_string(), - "AU".to_string(), - "AT".to_string(), - "AZ".to_string(), - "BS".to_string(), - "BH".to_string(), - "BD".to_string(), - "BB".to_string(), - "BE".to_string(), - "BZ".to_string(), - "BJ".to_string(), - "BM".to_string(), - "BT".to_string(), - "BQ".to_string(), - "BA".to_string(), - "BW".to_string(), - "IO".to_string(), - "BN".to_string(), - "BG".to_string(), - "BF".to_string(), - "BI".to_string(), - "KH".to_string(), - "CM".to_string(), - "CA".to_string(), - "CV".to_string(), - "KY".to_string(), - "CF".to_string(), - "TD".to_string(), - "CX".to_string(), - "CC".to_string(), - "KM".to_string(), - "CG".to_string(), - "CK".to_string(), - "CI".to_string(), - "CW".to_string(), - "CY".to_string(), - "CZ".to_string(), - "DJ".to_string(), - "DM".to_string(), - "EG".to_string(), - "GQ".to_string(), - "ER".to_string(), - "EE".to_string(), - "ET".to_string(), - "FK".to_string(), - "FO".to_string(), - "FJ".to_string(), - "GF".to_string(), - "PF".to_string(), - "TF".to_string(), - "GA".to_string(), - "GM".to_string(), - "GE".to_string(), - "GH".to_string(), - "GL".to_string(), - "GD".to_string(), - "GP".to_string(), - "GU".to_string(), - "GG".to_string(), - "GN".to_string(), - "GW".to_string(), - "GY".to_string(), - "HT".to_string(), - "HM".to_string(), - "VA".to_string(), - "IS".to_string(), - "IN".to_string(), - "ID".to_string(), - "IE".to_string(), - "IM".to_string(), - "IL".to_string(), - "JE".to_string(), - "JO".to_string(), - "KZ".to_string(), - "KE".to_string(), - "KI".to_string(), - "KW".to_string(), - "KG".to_string(), - "LA".to_string(), - "LV".to_string(), - "LB".to_string(), - "LS".to_string(), - "LI".to_string(), - "LT".to_string(), - "LU".to_string(), - "MK".to_string(), - "MG".to_string(), - "MW".to_string(), - "MV".to_string(), - "ML".to_string(), - "MT".to_string(), - "MH".to_string(), - "MQ".to_string(), - "MR".to_string(), - "MU".to_string(), - "YT".to_string(), - "FM".to_string(), - "MD".to_string(), - "MC".to_string(), - "MN".to_string(), - "ME".to_string(), - "MS".to_string(), - "MA".to_string(), - "MZ".to_string(), - "NA".to_string(), - "NR".to_string(), - "NP".to_string(), - "NC".to_string(), - "NZ".to_string(), - "NE".to_string(), - "NG".to_string(), - "NU".to_string(), - "NF".to_string(), - "MP".to_string(), - "OM".to_string(), - "PK".to_string(), - "PW".to_string(), - "PS".to_string(), - "PG".to_string(), - "PH".to_string(), - "PN".to_string(), - "QA".to_string(), - "RE".to_string(), - "RO".to_string(), - "RW".to_string(), - "BL".to_string(), - "SH".to_string(), - "KN".to_string(), - "LC".to_string(), - "MF".to_string(), - "PM".to_string(), - "VC".to_string(), - "WS".to_string(), - "SM".to_string(), - "ST".to_string(), - "SA".to_string(), - "SN".to_string(), - "RS".to_string(), - "SC".to_string(), - "SL".to_string(), - "SX".to_string(), - "SK".to_string(), - "SI".to_string(), - "SB".to_string(), - "SO".to_string(), - "ZA".to_string(), - "GS".to_string(), - "KR".to_string(), - "LK".to_string(), - "SR".to_string(), - "SJ".to_string(), - "SZ".to_string(), - "TH".to_string(), - "TL".to_string(), - "TG".to_string(), - "TK".to_string(), - "TO".to_string(), - "TT".to_string(), - "TN".to_string(), - "TM".to_string(), - "TC".to_string(), - "TV".to_string(), - "UG".to_string(), - "UA".to_string(), - "AE".to_string(), - "UZ".to_string(), - "VU".to_string(), - "VN".to_string(), - "VG".to_string(), - "VI".to_string(), - "WF".to_string(), - "EH".to_string(), - "ZM".to_string(), - ] - }, - value: None, - } - - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email_address".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "payment_method_data.wallet.mifinity.language_preference".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.wallet.mifinity.language_preference".to_string(), - display_name: "language_preference".to_string(), - field_type: enums::FieldType::LanguagePreference{ - options: vec![ - "BR".to_string(), - "PT_BR".to_string(), - "CN".to_string(), - "ZH_CN".to_string(), - "DE".to_string(), - "DK".to_string(), - "DA".to_string(), - "DA_DK".to_string(), - "EN".to_string(), - "ES".to_string(), - "FI".to_string(), - "FR".to_string(), - "GR".to_string(), - "EL".to_string(), - "EL_GR".to_string(), - "HR".to_string(), - "IT".to_string(), - "JP".to_string(), - "JA".to_string(), - "JA_JP".to_string(), - "LA".to_string(), - "ES_LA".to_string(), - "NL".to_string(), - "NO".to_string(), - "PL".to_string(), - "PT".to_string(), - "RU".to_string(), - "SV".to_string(), - "SE".to_string(), - "SV_SE".to_string(), - "ZH".to_string(), - "TW".to_string(), - "ZH_TW".to_string(), - ] - }, - value: None, - } - ), - ]), - } - ), - ]), - } - ), - ])), - ), - ( - enums::PaymentMethod::PayLater, - PaymentMethodType(HashMap::from([ - ( - enums::PaymentMethodType::AfterpayClearpay, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate: HashMap::from([ - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_last_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "GB".to_string(), - "AU".to_string(), - "CA".to_string(), - "US".to_string(), - "NZ".to_string(), - ] - }, - value: None, - } - ), - ( - "billing.address.state".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserAddressState, - value: None, - } - ), - ( - "shipping.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.first_name".to_string(), - display_name: "shipping_first_name".to_string(), - field_type: enums::FieldType::UserShippingName, - value: None, - } - ), - ( - "shipping.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.last_name".to_string(), - display_name: "shipping_last_name".to_string(), - field_type: enums::FieldType::UserShippingName, - value: None, - } - ), - ( - "shipping.address.city".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserShippingAddressCity, - value: None, - } - ), - ( - "shipping.address.state".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserShippingAddressState, - value: None, - } - ), - ( - "shipping.address.zip".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserShippingAddressPincode, - value: None, - } - ), - ( - "shipping.address.country".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserShippingAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ), - ( - "shipping.address.line1".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserShippingAddressLine1, - value: None, - } - ), - ]), - common : HashMap::new(), - } - ), - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate: HashMap::from([ - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_last_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.line2".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line2".to_string(), - display_name: "line2".to_string(), - field_type: enums::FieldType::UserAddressLine2, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "GB".to_string(), - "AU".to_string(), - "CA".to_string(), - "US".to_string(), - "NZ".to_string(), - ] - }, - value: None, - } - ), - ( - "billing.address.state".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserAddressState, - value: None, - } - ), - ( - "shipping.address.city".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserShippingAddressCity, - value: None, - } - ), - ( - "shipping.address.zip".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserShippingAddressPincode, - value: None, - } - ), - ( - "shipping.address.country".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserShippingAddressCountry{ - options: vec![ - "GB".to_string(), - "AU".to_string(), - "CA".to_string(), - "US".to_string(), - "NZ".to_string(), - ] - }, - value: None, - } - ), - ( - "shipping.address.line1".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserShippingAddressLine1, - value: None, - } - ), - ( - "shipping.address.line2".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.line2".to_string(), - display_name: "line2".to_string(), - field_type: enums::FieldType::UserShippingAddressLine2, - value: None, - } - ), - ]), - common : HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::Klarna, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate: HashMap::from([ - ( "payment_method_data.pay_later.klarna.billing_country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.pay_later.klarna.billing_country".to_string(), - display_name: "billing_country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "AU".to_string(), - "AT".to_string(), - "BE".to_string(), - "CA".to_string(), - "CZ".to_string(), - "DK".to_string(), - "FI".to_string(), - "FR".to_string(), - "GR".to_string(), - "DE".to_string(), - "IE".to_string(), - "IT".to_string(), - "NL".to_string(), - "NZ".to_string(), - "NO".to_string(), - "PL".to_string(), - "PT".to_string(), - "RO".to_string(), - "ES".to_string(), - "SE".to_string(), - "CH".to_string(), - "GB".to_string(), - "US".to_string(), - ] - }, - value: None, - }), - ("billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - }) - ]), - common : HashMap::new(), - } - ), - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate: HashMap::new(), - common : HashMap::from([ - ( "payment_method_data.pay_later.klarna.billing_country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.pay_later.klarna.billing_country".to_string(), - display_name: "billing_country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - }), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ]), - } - ), - ( - enums::Connector::Klarna, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "AU".to_string(), - "AT".to_string(), - "BE".to_string(), - "CA".to_string(), - "CZ".to_string(), - "DK".to_string(), - "FI".to_string(), - "FR".to_string(), - "DE".to_string(), - "GR".to_string(), - "IE".to_string(), - "IT".to_string(), - "NL".to_string(), - "NZ".to_string(), - "NO".to_string(), - "PL".to_string(), - "PT".to_string(), - "ES".to_string(), - "SE".to_string(), - "CH".to_string(), - "GB".to_string(), - "US".to_string(), - ] - }, - value: None, - } - ) - ]), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::Affirm, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.state".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserAddressState, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "US".to_string(), - ] - }, - value: None, - } - ), - ( - "billing.phone.number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.number".to_string(), - display_name: "phone_number".to_string(), - field_type: enums::FieldType::UserPhoneNumber, - value: None, - } - ), - ( - "billing.phone.country_code".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.country_code".to_string(), - display_name: "dialing_code".to_string(), - field_type: enums::FieldType::UserPhoneNumberCountryCode, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.line2".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line2".to_string(), - display_name: "line2".to_string(), - field_type: enums::FieldType::UserAddressLine2, - value: None, - } - ), - ( - "shipping.address.line1".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "shipping.address.line2".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.line2".to_string(), - display_name: "line2".to_string(), - field_type: enums::FieldType::UserAddressLine2, - value: None, - } - ), - ( - "shipping.address.zip".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserShippingAddressPincode, - value: None, - } - ), - ( - "shipping.address.city".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserShippingAddressCity, - value: None, - } - ), - ( - "shipping.address.country".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserCountry { - options: vec![ - "US".to_string(), - ]}, - value: None, - } - ), - - ] - ), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::PayBright, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.state".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserAddressState, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "CA".to_string(), - ] - }, - value: None, - } - ), - ( - "payment_method_data.billing.phone.number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.number".to_string(), - display_name: "phone_number".to_string(), - field_type: enums::FieldType::UserPhoneNumber, - value: None, - } - ), - ( - "billing.phone.country_code".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.country_code".to_string(), - display_name: "dialing_code".to_string(), - field_type: enums::FieldType::UserPhoneNumberCountryCode, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.line2".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line2".to_string(), - display_name: "line2".to_string(), - field_type: enums::FieldType::UserAddressLine2, - value: None, - } - ), - ( - "shipping.address.city".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserShippingAddressCity, - value: None, - } - ), - ( - "shipping.address.zip".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserShippingAddressPincode, - value: None, - } - ), - ( - "shipping.address.country".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserShippingAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, - } - ), - ( - "shipping.address.line1".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserShippingAddressLine1, - value: None, - } - ), - ( - "shipping.address.line2".to_string(), - RequiredFieldInfo { - required_field: "shipping.address.line2".to_string(), - display_name: "line2".to_string(), - field_type: enums::FieldType::UserShippingAddressLine2, - value: None, - } - ), - ] - ), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::Walley, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "billing.phone.number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.number".to_string(), - display_name: "phone".to_string(), - field_type: enums::FieldType::UserPhoneNumber, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "DK".to_string(), - "FI".to_string(), - "NO".to_string(), - "SE".to_string(), - ]}, - value: None, - } - ), - ( - "billing.phone.country_code".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.country_code".to_string(), - display_name: "dialing_code".to_string(), - field_type: enums::FieldType::UserPhoneNumberCountryCode, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ] - ), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::Alma, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.state".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserAddressState, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "FR".to_string(), - ] - }, - value: None, - } - ), - ( - "payment_method_data.billing.phone.number".to_string(), - RequiredFieldInfo { - required_field: "billing.phone.number".to_string(), - display_name: "phone_number".to_string(), - field_type: enums::FieldType::UserPhoneNumber, - value: None, - } - ), - ( - "billing.phone.country_code".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.country_code".to_string(), - display_name: "dialing_code".to_string(), - field_type: enums::FieldType::UserPhoneNumberCountryCode, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.line2".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line2".to_string(), - display_name: "line2".to_string(), - field_type: enums::FieldType::UserAddressLine2, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::Atome, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.state".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserAddressState, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "MY".to_string(), - "SG".to_string() - ] - }, - value: None, - } - ), - ( - "payment_method_data.billing.phone.number".to_string(), - RequiredFieldInfo { - required_field: "billing.phone.number".to_string(), - display_name: "phone_number".to_string(), - field_type: enums::FieldType::UserPhoneNumber, - value: None, - } - ), - ( - "billing.phone.country_code".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.country_code".to_string(), - display_name: "dialing_code".to_string(), - field_type: enums::FieldType::UserPhoneNumberCountryCode, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.line2".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line2".to_string(), - display_name: "line2".to_string(), - field_type: enums::FieldType::UserAddressLine2, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ]), - }, - ), - ])), - ), - ( - enums::PaymentMethod::Crypto, - PaymentMethodType(HashMap::from([ - ( - enums::PaymentMethodType::CryptoCurrency, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Cryptopay, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate: HashMap::from([ - ( - "payment_method_data.crypto.pay_currency".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.crypto.pay_currency".to_string(), - display_name: "currency".to_string(), - field_type: enums::FieldType::UserCurrency{ - options: vec![ - "BTC".to_string(), - "LTC".to_string(), - "ETH".to_string(), - "XRP".to_string(), - "XLM".to_string(), - "BCH".to_string(), - "ADA".to_string(), - "SOL".to_string(), - "SHIB".to_string(), - "TRX".to_string(), - "DOGE".to_string(), - "BNB".to_string(), - "USDT".to_string(), - "USDC".to_string(), - "DAI".to_string(), - ] - }, - value: None, - } - ), - ( - "payment_method_data.crypto.network".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.crypto.network".to_string(), - display_name: "network".to_string(), - field_type: enums::FieldType::UserCryptoCurrencyNetwork, - value: None, - } - ), - ]), - common : HashMap::new(), - } - ), - ]), - }, - ), - ])), - ), - ( - enums::PaymentMethod::Voucher, - PaymentMethodType(HashMap::from([ - ( - enums::PaymentMethodType::Boleto, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate : HashMap::from([ - ( - "payment_method_data.voucher.boleto.social_security_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.voucher.boleto.social_security_number".to_string(), - display_name: "social_security_number".to_string(), - field_type: enums::FieldType::Text, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - } - ), - ( - "billing.address.state".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.state".to_string(), - display_name: "state".to_string(), - field_type: enums::FieldType::UserAddressState, - value: None, - } - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "BR".to_string(), - ] - }, - value: None, - } - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - } - ), - ( - "billing.address.line2".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line2".to_string(), - display_name: "line2".to_string(), - field_type: enums::FieldType::UserAddressLine2, - value: None, - } - ), - ]), - common : HashMap::new(), - } - ), - ( - enums::Connector::Zen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::Alfamart, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate : HashMap::from([ - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ) - ]), - common : HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::Indomaret, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate : HashMap::from([ - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ) - ]), - common : HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::Oxxo, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate : HashMap::new(), - common : HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::SevenEleven, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate : HashMap::from([ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.phone.number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.number".to_string(), - display_name: "phone".to_string(), - field_type: enums::FieldType::UserPhoneNumber, - value: None, - } - ), - ( - "billing.phone.country_code".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.country_code".to_string(), - display_name: "dialing_code".to_string(), - field_type: enums::FieldType::UserPhoneNumberCountryCode, - value: None, - } - ) - ] - ), - common : HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::Lawson, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate : HashMap::from([ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.phone.number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.number".to_string(), - display_name: "phone".to_string(), - field_type: enums::FieldType::UserPhoneNumber, - value: None, - } - ), - ( - "billing.phone.country_code".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.country_code".to_string(), - display_name: "dialing_code".to_string(), - field_type: enums::FieldType::UserPhoneNumberCountryCode, - value: None, - } - ), - ] - ), - common : HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::MiniStop, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate : HashMap::from([ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.phone.number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.number".to_string(), - display_name: "phone".to_string(), - field_type: enums::FieldType::UserPhoneNumber, - value: None, - } - ), - ( - "billing.phone.country_code".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.country_code".to_string(), - display_name: "dialing_code".to_string(), - field_type: enums::FieldType::UserPhoneNumberCountryCode, - value: None, - } - ), - ] - ), - common : HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::FamilyMart, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate : HashMap::from([ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.phone.number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.number".to_string(), - display_name: "phone".to_string(), - field_type: enums::FieldType::UserPhoneNumber, - value: None, - } - ), - ( - "billing.phone.country_code".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.country_code".to_string(), - display_name: "dialing_code".to_string(), - field_type: enums::FieldType::UserPhoneNumberCountryCode, - value: None, - } - ), - ] - ), - common : HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::Seicomart, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate : HashMap::from([ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.phone.number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.number".to_string(), - display_name: "phone".to_string(), - field_type: enums::FieldType::UserPhoneNumber, - value: None, - } - ), - ( - "billing.phone.country_code".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.country_code".to_string(), - display_name: "dialing_code".to_string(), - field_type: enums::FieldType::UserPhoneNumberCountryCode, - value: None, - } - ), - ] - ), - common : HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::PayEasy, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate : HashMap::from([ - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.phone.number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.number".to_string(), - display_name: "phone".to_string(), - field_type: enums::FieldType::UserPhoneNumber, - value: None, - } - ), - ( - "billing.phone.country_code".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.country_code".to_string(), - display_name: "dialing_code".to_string(), - field_type: enums::FieldType::UserPhoneNumberCountryCode, - value: None, - } - ), - ] - ), - common : HashMap::new(), - } - ) - ]), - }, - ), - ])), - ), - ( - enums::PaymentMethod::Upi, - PaymentMethodType(HashMap::from([ - ( - enums::PaymentMethodType::UpiCollect, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Razorpay, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate : HashMap::new(), - common : HashMap::from([ - ( - "payment_method_data.upi.upi_collect.vpa_id".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.upi.upi_collect.vpa_id".to_string(), - display_name: "vpa_id".to_string(), - field_type: enums::FieldType::UserVpaId, - value: None, - } - ), - ]), - } - ), - ]), - }, - ), - ])), - ), - ( - enums::PaymentMethod::BankDebit, - PaymentMethodType(HashMap::from([( - enums::PaymentMethodType::Ach, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "owner_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "payment_method_data.bank_debit.ach.account_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_debit.ach.account_number".to_string(), - display_name: "bank_account_number".to_string(), - field_type: enums::FieldType::UserBankAccountNumber, - value: None, - } - ), - ( - "payment_method_data.bank_debit.ach.routing_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_debit.ach.routing_number".to_string(), - display_name: "bank_routing_number".to_string(), - field_type: enums::FieldType::Text, - value: None, - } - ) - ]), - }), - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "owner_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - }), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "owner_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "payment_method_data.bank_debit.ach.account_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_debit.ach.account_number".to_string(), - display_name: "bank_account_number".to_string(), - field_type: enums::FieldType::UserBankAccountNumber, - value: None, - } - ), - ( - "payment_method_data.bank_debit.ach.routing_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_debit.ach.routing_number".to_string(), - display_name: "bank_routing_number".to_string(), - field_type: enums::FieldType::Text, - value: None, - } - ) - ]), - }) - ] - )} - ), - ( - enums::PaymentMethodType::Sepa, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "owner_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "payment_method_data.bank_debit.sepa_bank_debit.iban".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_debit.sepa_bank_debit.iban".to_string(), - display_name: "iban".to_string(), - field_type: enums::FieldType::UserIban, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ) - ]), - } - ), - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "owner_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - }), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "owner_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "payment_method_data.bank_debit.sepa_bank_debit.iban".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_debit.sepa_bank_debit.iban".to_string(), - display_name: "iban".to_string(), - field_type: enums::FieldType::UserIban, - value: None, - } - ) - ]), - } - ), - ( - enums::Connector::Deutschebank, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "owner_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - }), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "owner_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "payment_method_data.bank_debit.sepa_bank_debit.iban".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_debit.sepa_bank_debit.iban".to_string(), - display_name: "iban".to_string(), - field_type: enums::FieldType::UserIban, - value: None, - } - ) - ]), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::Bacs, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "payment_method_data.bank_debit.bacs.account_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_debit.bacs.account_number".to_string(), - display_name: "bank_account_number".to_string(), - field_type: enums::FieldType::UserBankAccountNumber, - value: None, - } - ), - ( - "payment_method_data.bank_debit.bacs.sort_code".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_debit.bacs.sort_code".to_string(), - display_name: "bank_sort_code".to_string(), - field_type: enums::FieldType::Text, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry { - options: vec!["UK".to_string()], - }, - value: None, - }, - ), - ( - "billing.address.zip".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.zip".to_string(), - display_name: "zip".to_string(), - field_type: enums::FieldType::UserAddressPincode, - value: None, - }, - ), - ( - "billing.address.line1".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.line1".to_string(), - display_name: "line1".to_string(), - field_type: enums::FieldType::UserAddressLine1, - value: None, - }, - ) - ]), - } - ), - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "owner_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - }), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "owner_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "payment_method_data.bank_debit.bacs.account_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_debit.bacs.account_number".to_string(), - display_name: "bank_account_number".to_string(), - field_type: enums::FieldType::UserBankAccountNumber, - value: None, - } - ), - ( - "payment_method_data.bank_debit.bacs.sort_code".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_debit.bacs.sort_code".to_string(), - display_name: "bank_sort_code".to_string(), - field_type: enums::FieldType::Text, - value: None, - } - ) - ]), - }) - ]), - }, - ), - ( - enums::PaymentMethodType::Becs, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_first_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "owner_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "payment_method_data.bank_debit.becs.account_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_debit.becs.account_number".to_string(), - display_name: "bank_account_number".to_string(), - field_type: enums::FieldType::UserBankAccountNumber, - value: None, - } - ), - ( - "payment_method_data.bank_debit.becs.bsb_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_debit.becs.bsb_number".to_string(), - display_name: "bsb_number".to_string(), - field_type: enums::FieldType::Text, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ) - ]), - } - ), - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "owner_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - }), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "owner_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "payment_method_data.bank_debit.bacs.account_number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_debit.bacs.account_number".to_string(), - display_name: "bank_account_number".to_string(), - field_type: enums::FieldType::UserBankAccountNumber, - value: None, - } - ), - ( - "payment_method_data.bank_debit.bacs.sort_code".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_debit.bacs.sort_code".to_string(), - display_name: "bank_sort_code".to_string(), - field_type: enums::FieldType::Text, - value: None, - } - ) - ]), - }) - ]), - }, - ), - ]))), - ( - enums::PaymentMethod::BankTransfer, - PaymentMethodType(HashMap::from([( - enums::PaymentMethodType::Multibanco, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ) - ]), - common: HashMap::new(), - } - ), - ])}), - (enums::PaymentMethodType::LocalBankTransfer, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Zsl, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "CN".to_string(), - ] - }, - value: None, - } - ), - ( - "billing.address.city".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.city".to_string(), - display_name: "city".to_string(), - field_type: enums::FieldType::UserAddressCity, - value: None, - }, - ), - ]), - common: HashMap::new(), - } - ), - ])}), - (enums::PaymentMethodType::Ach, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ) - ]) - } - ), - ])}), - (enums::PaymentMethodType::Pix, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Itaubank, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from( - [ - ( - "payment_method_data.bank_transfer.pix.pix_key".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_transfer.pix.pix_key".to_string(), - display_name: "pix_key".to_string(), - field_type: enums::FieldType::UserPixKey, - value: None, - } - ), - ( - "payment_method_data.bank_transfer.pix.cnpj".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_transfer.pix.cnpj".to_string(), - display_name: "cnpj".to_string(), - field_type: enums::FieldType::UserCnpj, - value: None, - } - ), - ( - "payment_method_data.bank_transfer.pix.cpf".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.bank_transfer.pix.cpf".to_string(), - display_name: "cpf".to_string(), - field_type: enums::FieldType::UserCpf, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ] - ), - } - ), - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ])}), - ( - enums::PaymentMethodType::PermataBankTransfer, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate : HashMap::from([ - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ) - ]), - common : HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::BcaBankTransfer, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate : HashMap::from([ - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ) - ]), - common : HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::BniVa, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate : HashMap::from([ - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ) - ]), - common : HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::BriVa, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate : HashMap::from([ - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ) - ]), - common : HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::CimbVa, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate : HashMap::from([ - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ) - ]), - common : HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::DanamonVa, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate : HashMap::from([ - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ) - ]), - common : HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::MandiriVa, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate : HashMap::from([ - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ) - ]), - common : HashMap::new(), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::Sepa, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate : HashMap::new(), - common : HashMap::from([ - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.country".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.country".to_string(), - display_name: "country".to_string(), - field_type: enums::FieldType::UserAddressCountry { - options: vec![ - "BE".to_string(), - "DE".to_string(), - "ES".to_string(), - "FR".to_string(), - "IE".to_string(), - "NL".to_string(), - ], - }, - value: None, - }, - ), - ]), - } - ) - ]), - }, - ), - ( - enums::PaymentMethodType::Bacs, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Stripe, - RequiredFieldFinal { - mandate : HashMap::new(), - non_mandate : HashMap::new(), - common : HashMap::from([ - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "card_holder_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ) - ]), - } - ) - ]), - }, - ), - ]))), - ( - enums::PaymentMethod::GiftCard, - PaymentMethodType(HashMap::from([ - ( - enums::PaymentMethodType::PaySafeCard, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::Givex, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from([ - - ( - "payment_method_data.gift_card.number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.gift_card.number".to_string(), - display_name: "gift_card_number".to_string(), - field_type: enums::FieldType::UserCardNumber, - value: None, - } - ), - ( - "payment_method_data.gift_card.cvc".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.gift_card.cvc".to_string(), - display_name: "gift_card_cvc".to_string(), - field_type: enums::FieldType::UserCardCvc, - value: None, - } - ), - ]), - common: HashMap::new(), - } - ), - ]), - }, - ), - ])) - ), - ( - enums::PaymentMethod::CardRedirect, - PaymentMethodType(HashMap::from([ - ( - enums::PaymentMethodType::Benefit, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "first_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "last_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.phone.number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.number".to_string(), - display_name: "phone".to_string(), - field_type: enums::FieldType::UserPhoneNumber, - value: None, - } - ), - ( - "billing.phone.country_code".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.country_code".to_string(), - display_name: "dialing_code".to_string(), - field_type: enums::FieldType::UserPhoneNumberCountryCode, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::Knet, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::from( - [( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "first_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "last_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - } - ), - ( - "billing.phone.number".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.number".to_string(), - display_name: "phone".to_string(), - field_type: enums::FieldType::UserPhoneNumber, - value: None, - } - ), - ( - "billing.phone.country_code".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.phone.country_code".to_string(), - display_name: "dialing_code".to_string(), - field_type: enums::FieldType::UserPhoneNumberCountryCode, - value: None, - } - ), - ( - "billing.email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.email".to_string(), - display_name: "email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - } - ) - ] - ), - common: HashMap::new(), - } - ), - ]), - }, - ), - ( - enums::PaymentMethodType::MomoAtm, - ConnectorFields { - fields: HashMap::from([ - ( - enums::Connector::Adyen, - RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::new(), - } - ), - ]), - }, - ) - ])) - ) - ])) - } -} - #[allow(clippy::derivable_impls)] impl Default for super::settings::ApiKeys { fn default() -> Self { diff --git a/crates/router/src/configs/defaults/payment_connector_required_fields.rs b/crates/router/src/configs/defaults/payment_connector_required_fields.rs new file mode 100644 index 000000000000..28ddeec1fcd3 --- /dev/null +++ b/crates/router/src/configs/defaults/payment_connector_required_fields.rs @@ -0,0 +1,12562 @@ +use std::collections::{HashMap, HashSet}; + +use api_models::{enums, payment_methods::RequiredFieldInfo}; + +use crate::settings::{ + self, ConnectorFields, Mandates, PaymentMethodType, RequiredFieldFinal, + SupportedConnectorsForMandate, SupportedPaymentMethodTypesForMandate, + SupportedPaymentMethodsForMandate, +}; + +impl Default for Mandates { + fn default() -> Self { + Self { + supported_payment_methods: SupportedPaymentMethodsForMandate(HashMap::from([ + ( + enums::PaymentMethod::PayLater, + SupportedPaymentMethodTypesForMandate(HashMap::from([( + enums::PaymentMethodType::Klarna, + SupportedConnectorsForMandate { + connector_list: HashSet::from([enums::Connector::Adyen]), + }, + )])), + ), + ( + enums::PaymentMethod::Wallet, + SupportedPaymentMethodTypesForMandate(HashMap::from([ + ( + enums::PaymentMethodType::GooglePay, + SupportedConnectorsForMandate { + connector_list: HashSet::from([ + enums::Connector::Stripe, + enums::Connector::Adyen, + enums::Connector::Globalpay, + enums::Connector::Multisafepay, + enums::Connector::Bankofamerica, + enums::Connector::Noon, + enums::Connector::Cybersource, + enums::Connector::Wellsfargo, + ]), + }, + ), + ( + enums::PaymentMethodType::ApplePay, + SupportedConnectorsForMandate { + connector_list: HashSet::from([ + enums::Connector::Stripe, + enums::Connector::Adyen, + enums::Connector::Bankofamerica, + enums::Connector::Cybersource, + enums::Connector::Wellsfargo, + ]), + }, + ), + ])), + ), + ( + enums::PaymentMethod::Card, + SupportedPaymentMethodTypesForMandate(HashMap::from([ + ( + enums::PaymentMethodType::Credit, + SupportedConnectorsForMandate { + connector_list: HashSet::from([ + enums::Connector::Aci, + enums::Connector::Adyen, + enums::Connector::Authorizedotnet, + enums::Connector::Globalpay, + enums::Connector::Worldpay, + enums::Connector::Multisafepay, + enums::Connector::Nexinets, + enums::Connector::Noon, + enums::Connector::Payme, + enums::Connector::Stripe, + enums::Connector::Bankofamerica, + enums::Connector::Cybersource, + enums::Connector::Wellsfargo, + ]), + }, + ), + ( + enums::PaymentMethodType::Debit, + SupportedConnectorsForMandate { + connector_list: HashSet::from([ + enums::Connector::Aci, + enums::Connector::Adyen, + enums::Connector::Authorizedotnet, + enums::Connector::Globalpay, + enums::Connector::Worldpay, + enums::Connector::Multisafepay, + enums::Connector::Nexinets, + enums::Connector::Noon, + enums::Connector::Payme, + enums::Connector::Stripe, + ]), + }, + ), + ])), + ), + ])), + update_mandate_supported: SupportedPaymentMethodsForMandate(HashMap::default()), + } + } +} + +impl Default for settings::RequiredFields { + fn default() -> Self { + Self(HashMap::from([ + ( + enums::PaymentMethod::Card, + PaymentMethodType(HashMap::from([ + ( + enums::PaymentMethodType::Debit, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Aci, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ] + ), + } + ), + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ] + ), + } + ), + ( + enums::Connector::Airwallex, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Fiuu, + RequiredFieldFinal { + mandate: HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ) + ]), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Authorizedotnet, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Bambora, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Bankofamerica, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "email".to_string(), + RequiredFieldInfo { + required_field: "email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Billwerk, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Bluesnap, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "email".to_string(), + RequiredFieldInfo { + required_field: "email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Boku, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Braintree, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Checkout, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Coinbase, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Cybersource, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common:HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Dlocal, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ) + ] + ), + common:HashMap::new(), + } + ), + #[cfg(feature = "dummy_connector")] + ( + enums::Connector::DummyConnector1, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + #[cfg(feature = "dummy_connector")] + ( + enums::Connector::DummyConnector2, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + #[cfg(feature = "dummy_connector")] + ( + enums::Connector::DummyConnector3, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + #[cfg(feature = "dummy_connector")] + ( + enums::Connector::DummyConnector4, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + #[cfg(feature = "dummy_connector")] + ( + enums::Connector::DummyConnector5, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + #[cfg(feature = "dummy_connector")] + ( + enums::Connector::DummyConnector6, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + #[cfg(feature = "dummy_connector")] + ( + enums::Connector::DummyConnector7, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Fiserv, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Fiuu, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Forte, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ] + ), + common:HashMap::new(), + } + ), + ( + enums::Connector::Globalpay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ]), + } + ), + ( + enums::Connector::Helcim, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Iatapay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Mollie, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Multisafepay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate:HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.line2".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line2".to_string(), + display_name: "line2".to_string(), + field_type: enums::FieldType::UserAddressLine2, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Nexinets, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Nmi, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "billing_zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Noon, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ] + ), + } + ), + ( + enums::Connector::Novalnet, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "browser_info.language".to_string(), + RequiredFieldInfo { + required_field: "browser_info.language".to_string(), + display_name: "browser_info_language".to_string(), + field_type: enums::FieldType::BrowserLanguage, + value: None, + } + ), + ( + "browser_info.ip_address".to_string(), + RequiredFieldInfo { + required_field: "browser_info.ip_address".to_string(), + display_name: "browser_info_ip_address".to_string(), + field_type: enums::FieldType::BrowserIp, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.line2".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line2".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine2, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "first_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "last_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email_address".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ] + ), + } + ), + ( + enums::Connector::Nuvei, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Paybox, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "email".to_string(), + RequiredFieldInfo { + required_field: "email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ) + + ] + ), + } + ), + ( + enums::Connector::Payme, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "email".to_string(), + RequiredFieldInfo { + required_field: "email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ] + ), + } + ), + ( + enums::Connector::Paypal, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Payu, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Powertranz, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Rapyd, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Shift4, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Square, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Stax, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common:HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Trustpay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ), + ] + ), + common: HashMap::new() + } + ), + ( + enums::Connector::Tsys, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + common: HashMap::new() + } + ), + ( + enums::Connector::Wellsfargo, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common:HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "email".to_string(), + RequiredFieldInfo { + required_field: "email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Worldline, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ) + ]), + common: HashMap::new(), + } + ), + ( + enums::Connector::Worldpay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ) + ]), + common: HashMap::new(), + } + ), + ( + enums::Connector::Zen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "email".to_string(), + RequiredFieldInfo { + required_field: "email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ]), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::Credit, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Aci, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ] + ), + } + ), + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ] + ), + } + ), + ( + enums::Connector::Airwallex, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Fiuu, + RequiredFieldFinal { + mandate: HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ) + ]), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Authorizedotnet, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Bambora, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Bankofamerica, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "email".to_string(), + RequiredFieldInfo { + required_field: "email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ] + ), + } + ), + ( + enums::Connector::Billwerk, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Bluesnap, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "email".to_string(), + RequiredFieldInfo { + required_field: "email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Boku, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Braintree, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Checkout, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Coinbase, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Cybersource, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate:HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Dlocal, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ) + ] + ), + common:HashMap::new(), + } + ), + #[cfg(feature = "dummy_connector")] + ( + enums::Connector::DummyConnector1, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + #[cfg(feature = "dummy_connector")] + ( + enums::Connector::DummyConnector2, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + #[cfg(feature = "dummy_connector")] + ( + enums::Connector::DummyConnector3, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + #[cfg(feature = "dummy_connector")] + ( + enums::Connector::DummyConnector4, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + #[cfg(feature = "dummy_connector")] + ( + enums::Connector::DummyConnector5, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + #[cfg(feature = "dummy_connector")] + ( + enums::Connector::DummyConnector6, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + #[cfg(feature = "dummy_connector")] + ( + enums::Connector::DummyConnector7, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Fiserv, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Fiuu, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Forte, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ] + ), + common:HashMap::new(), + } + ), + ( + enums::Connector::Globalpay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ]), + } + ), + ( + enums::Connector::Helcim, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Iatapay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Mollie, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Multisafepay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate:HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.line2".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line2".to_string(), + display_name: "line2".to_string(), + field_type: enums::FieldType::UserAddressLine2, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Nexinets, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Nexixpay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.line2".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line2".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine2, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "first_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "last_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Nmi, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "billing_zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Noon, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ] + ), + } + ), + ( + enums::Connector::Novalnet, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "browser_info.language".to_string(), + RequiredFieldInfo { + required_field: "browser_info.language".to_string(), + display_name: "browser_info_language".to_string(), + field_type: enums::FieldType::BrowserLanguage, + value: None, + } + ), + ( + "browser_info.ip_address".to_string(), + RequiredFieldInfo { + required_field: "browser_info.ip_address".to_string(), + display_name: "browser_info_ip_address".to_string(), + field_type: enums::FieldType::BrowserIp, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.line2".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line2".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine2, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "first_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "last_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email_address".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ] + ), + } + ), + ( + enums::Connector::Nuvei, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ),( + enums::Connector::Paybox, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "email".to_string(), + RequiredFieldInfo { + required_field: "email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ) + + ] + ), + } + ), + ( + enums::Connector::Payme, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "email".to_string(), + RequiredFieldInfo { + required_field: "email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ] + ), + } + ), + ( + enums::Connector::Paypal, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Payu, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Powertranz, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Rapyd, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Shift4, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Square, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Stax, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common:HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Trustpay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ), + ] + ), + common: HashMap::new() + } + ), + ( + enums::Connector::Tsys, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ) + ] + ), + common: HashMap::new() + } + ), + ( + enums::Connector::Wellsfargo, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate:HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "email".to_string(), + RequiredFieldInfo { + required_field: "email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ) + ] + ), + } + ), + ( + enums::Connector::Worldline, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "payment_method_data.card.card_cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_cvc".to_string(), + display_name: "card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ) + ]), + common: HashMap::new(), + } + ), + ( + enums::Connector::Worldpay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ) + ]), + common: HashMap::new(), + } + ), + ( + enums::Connector::Zen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "payment_method_data.card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "email".to_string(), + RequiredFieldInfo { + required_field: "email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ]), + common: HashMap::new(), + } + ), + ]), + }, + ), + + ])), + ), + ( + enums::PaymentMethod::BankRedirect, + PaymentMethodType(HashMap::from([ + ( + enums::PaymentMethodType::OpenBankingUk, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Volt, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_last_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ]), + common: HashMap::new(), + } + ), + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap:: from([ + ( + "payment_method_data.bank_redirect.open_banking_uk.issuer".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_redirect.open_banking_uk.issuer".to_string(), + display_name: "issuer".to_string(), + field_type: enums::FieldType::UserBank, + value: None, + } + ) + ]), + common: HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::Trustly, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::OnlineBankingCzechRepublic, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "payment_method_data.bank_redirect.open_banking_czech_republic.issuer".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_redirect.open_banking_czech_republic.issuer".to_string(), + display_name: "issuer".to_string(), + field_type: enums::FieldType::UserBank, + value: None, + } + ) + ]), + common: HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::OnlineBankingFinland, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ]), + common: HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::OnlineBankingPoland, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "payment_method_data.bank_redirect.open_banking_poland.issuer".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_redirect.open_banking_poland.issuer".to_string(), + display_name: "issuer".to_string(), + field_type: enums::FieldType::UserBank, + value: None, + } + ), + + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ]), + common: HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::OnlineBankingSlovakia, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "payment_method_data.bank_redirect.open_banking_slovakia.issuer".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_redirect.open_banking_slovakia.issuer".to_string(), + display_name: "issuer".to_string(), + field_type: enums::FieldType::UserBank, + value: None, + } + ), + ]), + common: HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::OnlineBankingFpx, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "payment_method_data.bank_redirect.open_banking_fpx.issuer".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_redirect.open_banking_fpx.issuer".to_string(), + display_name: "issuer".to_string(), + field_type: enums::FieldType::UserBank, + value: None, + } + ) + ]), + common: HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::OnlineBankingThailand, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "payment_method_data.bank_redirect.open_banking_thailand.issuer".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_redirect.open_banking_thailand.issuer".to_string(), + display_name: "issuer".to_string(), + field_type: enums::FieldType::UserBank, + value: None, + } + ) + ]), + common: HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::Bizum, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::Przelewy24, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ) + ]), + common: HashMap::new(), + } + )]), + }, + ), + ( + enums::PaymentMethodType::BancontactCard, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Mollie, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ) + ]), + non_mandate: HashMap::new(), + common: HashMap::from([ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ]), + } + ), + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ + ( + "payment_method_data.bank_redirect.bancontact_card.card_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_redirect.bancontact_card.card_number".to_string(), + display_name: "card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.bank_redirect.bancontact_card.card_exp_month".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_redirect.bancontact_card.card_exp_month".to_string(), + display_name: "card_exp_month".to_string(), + field_type: enums::FieldType::UserCardExpiryMonth, + value: None, + } + ), + ( + "payment_method_data.bank_redirect.bancontact_card.card_exp_year".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_redirect.bancontact_card.card_exp_year".to_string(), + display_name: "card_exp_year".to_string(), + field_type: enums::FieldType::UserCardExpiryYear, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ]), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::Giropay, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Aci, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserCountry { + options: vec![ + "DE".to_string(), + ]}, + value: None, + } + ) + ]), + common: HashMap::new(), + } + ), + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Globalpay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ + ("billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry { + options: vec![ + "DE".to_string(), + ] + }, + value: None, + } + ) + ]), + } + ), + ( + enums::Connector::Mollie, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Nuvei, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate:HashMap::from([ + ( + "email".to_string(), + RequiredFieldInfo { + required_field: "email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_last_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "DE".to_string(), + ] + }, + value: None, + } + )] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Paypal, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserCountry { + options: vec![ + "DE".to_string(), + ] + }, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ) + ]), + common: HashMap::new(), + } + ), + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ) + ]), + common: HashMap::new(), + } + ), + ( + enums::Connector::Shift4, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Trustpay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry { + options: vec![ + "DE".to_string(), + ] + }, + value: None, + } + ), + ]), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::Ideal, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Aci, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "payment_method_data.bank_redirect.ideal.bank_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_redirect.ideal.bank_name".to_string(), + display_name: "bank_name".to_string(), + field_type: enums::FieldType::UserBank, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserCountry { + options: vec![ + "NL".to_string(), + ] + }, + value: None, + } + ) + ]), + common: HashMap::new(), + } + ), + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ + ( + "payment_method_data.bank_redirect.ideal.bank_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_redirect.ideal.bank_name".to_string(), + display_name: "bank_name".to_string(), + field_type: enums::FieldType::UserBank, + value: None, + } + ), + + ]), + } + ), + ( + enums::Connector::Globalpay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Mollie, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Nexinets, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Nuvei, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "email".to_string(), + RequiredFieldInfo { + required_field: "email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_last_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "NL".to_string(), + ] + }, + value: None, + } + ) + ]), + common: HashMap::new(), + } + ), + ( + enums::Connector::Shift4, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserCountry{ + options: vec![ + "NL".to_string(), + ] + }, + value: None, + } + ) + ]), + common: HashMap::new(), + } + ), + ( + enums::Connector::Paypal, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserCountry{ + options: vec![ + "NL".to_string(), + ] + }, + value: None, + } + ) + ]), + common: HashMap::new(), + } + ), + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::from([ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "billing_email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ) + ]), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Trustpay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "NL".to_string(), + ] + }, + value: None, + } + ), + ]), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::Sofort, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Aci, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ("billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserCountry { + options: vec![ + "ES".to_string(), + "GB".to_string(), + "SE".to_string(), + "AT".to_string(), + "NL".to_string(), + "DE".to_string(), + "CH".to_string(), + "BE".to_string(), + "FR".to_string(), + "FI".to_string(), + "IT".to_string(), + "PL".to_string(), + ] + }, + value: None, + } + ) + ]), + common: HashMap::new(), + } + ), + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Globalpay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ + ("billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry { + options: vec![ + "AT".to_string(), + "BE".to_string(), + "DE".to_string(), + "ES".to_string(), + "IT".to_string(), + "NL".to_string(), + ] + }, + value: None, + } + ) + ]), + } + ), + ( + enums::Connector::Mollie, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Nexinets, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Nuvei, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate:HashMap::from([ + ( + "email".to_string(), + RequiredFieldInfo { + required_field: "email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_last_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ES".to_string(), + "GB".to_string(), + "IT".to_string(), + "DE".to_string(), + "FR".to_string(), + "AT".to_string(), + "BE".to_string(), + "NL".to_string(), + "BE".to_string(), + "SK".to_string(), + ] + }, + value: None, + } + )] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Paypal, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserCountry { + options: vec![ + "ES".to_string(), + "GB".to_string(), + "AT".to_string(), + "NL".to_string(), + "DE".to_string(), + "BE".to_string(), + ] + }, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ) + ]), + common: HashMap::new(), + } + ), + ( + enums::Connector::Shift4, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ) + ]), + non_mandate : HashMap::new(), + common: HashMap::from([ + ("billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserCountry { + options: vec![ + "ES".to_string(), + "AT".to_string(), + "NL".to_string(), + "DE".to_string(), + "BE".to_string(), + ] + }, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "account_holder_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "account_holder_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + )]), + } + ), + ( + enums::Connector::Trustpay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry { + options: vec![ + "ES".to_string(), + "GB".to_string(), + "SE".to_string(), + "AT".to_string(), + "NL".to_string(), + "DE".to_string(), + "CH".to_string(), + "BE".to_string(), + "FR".to_string(), + "FI".to_string(), + "IT".to_string(), + "PL".to_string(), + ] + }, + value: None, + } + ), + ]), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::Eps, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ + ( + "payment_method_data.bank_redirect.eps.bank_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_redirect.eps.bank_name".to_string(), + display_name: "bank_name".to_string(), + field_type: enums::FieldType::UserBank, + value: None, + } + ) + ]), + } + ), + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ]), + common: HashMap::new(), + } + ), + ( + enums::Connector::Aci, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "bank_account_country".to_string(), + field_type: enums::FieldType::UserCountry { + options: vec![ + "AT".to_string(), + ] + }, + value: None, + } + ) + ]), + common: HashMap::new(), + } + ), + ( + enums::Connector::Globalpay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry { + options: vec![ + "AT".to_string(), + ] + }, + value: None, + } + ) + ]) + } + ), + ( + enums::Connector::Mollie, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate:HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Paypal, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "bank_account_country".to_string(), + field_type: enums::FieldType::UserCountry { + options: vec![ + "AT".to_string(), + ] + }, + value: None, + } + ) + ]), + common: HashMap::new(), + } + ), + ( + enums::Connector::Trustpay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "AT".to_string(), + ] + }, + value: None, + } + ), + ]), + common: HashMap::new(), + } + ), + ( + enums::Connector::Shift4, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate:HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Nuvei, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "email".to_string(), + RequiredFieldInfo { + required_field: "email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_last_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "AT".to_string(), + ] + }, + value: None, + } + )] + ), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::Blik, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ + ( + "payment_method_data.bank_redirect.blik.blik_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_redirect.blik.blik_code".to_string(), + display_name: "blik_code".to_string(), + field_type: enums::FieldType::UserBlikCode, + value: None, + } + ) + ]), + } + ), + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ + ( + "payment_method_data.bank_redirect.blik.blik_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_redirect.blik.blik_code".to_string(), + display_name: "blik_code".to_string(), + field_type: enums::FieldType::UserBlikCode, + value: None, + } + ) + ]), + } + ), + ( + enums::Connector::Trustpay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ + ( + "email".to_string(), + RequiredFieldInfo { + required_field: "email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_last_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ), + ]), + } + ) + ]), + }, + ), + ])), + ), + ( + enums::PaymentMethod::Wallet, + PaymentMethodType(HashMap::from([ + ( + enums::PaymentMethodType::ApplePay, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Bankofamerica, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "email".to_string(), + RequiredFieldInfo { + required_field: "email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_last_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Cybersource, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_last_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Wellsfargo, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "email".to_string(), + RequiredFieldInfo { + required_field: "email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_last_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "shipping.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.first_name".to_string(), + display_name: "shipping_first_name".to_string(), + field_type: enums::FieldType::UserShippingName, + value: None, + } + ), + ( + "shipping.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.last_name".to_string(), + display_name: "shipping_last_name".to_string(), + field_type: enums::FieldType::UserShippingName, + value: None, + } + ), + ( + "shipping.address.city".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserShippingAddressCity, + value: None, + } + ), + ( + "shipping.address.state".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserShippingAddressState, + value: None, + } + ), + ( + "shipping.address.zip".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserShippingAddressPincode, + value: None, + } + ), + ( + "shipping.address.country".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserShippingAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ), + ( + "shipping.address.line1".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserShippingAddressLine1, + value: None, + } + ), + ] + ), + common: HashMap::new(), + } + ), + + ]), + }, + ), + ( + enums::PaymentMethodType::GooglePay, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Bankofamerica, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "email".to_string(), + RequiredFieldInfo { + required_field: "email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_last_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Bluesnap, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Noon, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Nuvei, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Airwallex, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Authorizedotnet, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Checkout, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Globalpay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Multisafepay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_last_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.line2".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line2".to_string(), + display_name: "line2".to_string(), + field_type: enums::FieldType::UserAddressLine2, + value: None, + } + )]), + common: HashMap::new(), + } + ), + ( + enums::Connector::Cybersource, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_last_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ( + enums::Connector::Payu, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Rapyd, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Trustpay, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Wellsfargo, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "email".to_string(), + RequiredFieldInfo { + required_field: "email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_last_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "shipping.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.first_name".to_string(), + display_name: "shipping_first_name".to_string(), + field_type: enums::FieldType::UserShippingName, + value: None, + } + ), + ( + "shipping.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.last_name".to_string(), + display_name: "shipping_last_name".to_string(), + field_type: enums::FieldType::UserShippingName, + value: None, + } + ), + ( + "shipping.address.city".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserShippingAddressCity, + value: None, + } + ), + ( + "shipping.address.state".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserShippingAddressState, + value: None, + } + ), + ( + "shipping.address.zip".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserShippingAddressPincode, + value: None, + } + ), + ( + "shipping.address.country".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserShippingAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ), + ( + "shipping.address.line1".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserShippingAddressLine1, + value: None, + } + ), + ] + ), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::WeChatPay, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::AliPay, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::AliPayHk, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::Cashapp, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::MbWay, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + common: HashMap::new(), + non_mandate: HashMap::from([ + ( + "payment_method_data.billing.phone.number".to_string(), + RequiredFieldInfo { + required_field: "billing.phone.number".to_string(), + display_name: "phone_number".to_string(), + field_type: enums::FieldType::UserPhoneNumber, + value: None, + } + ), + ( + "billing.phone.country_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.country_code".to_string(), + display_name: "dialing_code".to_string(), + field_type: enums::FieldType::UserPhoneNumberCountryCode, + value: None, + } + ), + ] + ), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::KakaoPay, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::Twint, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::Gcash, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::Vipps, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::Dana, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::Momo, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::Swish, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::TouchNGo, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + // Added shipping fields for the SDK flow to accept it from wallet directly, + // this won't show up in SDK in payment's sheet but will be used in the background + enums::PaymentMethodType::Paypal, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + )] + ), + } + ), + ( + enums::Connector::Braintree, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Paypal, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new( + ), + common: HashMap::from( + [ + ( + "shipping.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.first_name".to_string(), + display_name: "shipping_first_name".to_string(), + field_type: enums::FieldType::UserShippingName, + value: None, + } + ), + ( + "shipping.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.last_name".to_string(), + display_name: "shipping_last_name".to_string(), + field_type: enums::FieldType::UserShippingName, + value: None, + } + ), + ( + "shipping.address.city".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserShippingAddressCity, + value: None, + } + ), + ( + "shipping.address.state".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserShippingAddressState, + value: None, + } + ), + ( + "shipping.address.zip".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserShippingAddressPincode, + value: None, + } + ), + ( + "shipping.address.country".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserShippingAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ), + ( + "shipping.address.line1".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserShippingAddressLine1, + value: None, + } + ), + ] + ), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::Mifinity, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Mifinity, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ + ( + "payment_method_data.wallet.mifinity.date_of_birth".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.wallet.mifinity.date_of_birth".to_string(), + display_name: "date_of_birth".to_string(), + field_type: enums::FieldType::UserDateOfBirth, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "first_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "last_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.phone.number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.number".to_string(), + display_name: "phone".to_string(), + field_type: enums::FieldType::UserPhoneNumber, + value: None, + } + ), + ( + "billing.phone.country_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.country_code".to_string(), + display_name: "dialing_code".to_string(), + field_type: enums::FieldType::UserPhoneNumberCountryCode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "nationality".to_string(), + field_type: enums::FieldType::UserCountry{ + options: vec![ + "BR".to_string(), + "CN".to_string(), + "SG".to_string(), + "MY".to_string(), + "DE".to_string(), + "CH".to_string(), + "DK".to_string(), + "GB".to_string(), + "ES".to_string(), + "AD".to_string(), + "GI".to_string(), + "FI".to_string(), + "FR".to_string(), + "GR".to_string(), + "HR".to_string(), + "IT".to_string(), + "JP".to_string(), + "MX".to_string(), + "AR".to_string(), + "CO".to_string(), + "CL".to_string(), + "PE".to_string(), + "VE".to_string(), + "UY".to_string(), + "PY".to_string(), + "BO".to_string(), + "EC".to_string(), + "GT".to_string(), + "HN".to_string(), + "SV".to_string(), + "NI".to_string(), + "CR".to_string(), + "PA".to_string(), + "DO".to_string(), + "CU".to_string(), + "PR".to_string(), + "NL".to_string(), + "NO".to_string(), + "PL".to_string(), + "PT".to_string(), + "SE".to_string(), + "RU".to_string(), + "TR".to_string(), + "TW".to_string(), + "HK".to_string(), + "MO".to_string(), + "AX".to_string(), + "AL".to_string(), + "DZ".to_string(), + "AS".to_string(), + "AO".to_string(), + "AI".to_string(), + "AG".to_string(), + "AM".to_string(), + "AW".to_string(), + "AU".to_string(), + "AT".to_string(), + "AZ".to_string(), + "BS".to_string(), + "BH".to_string(), + "BD".to_string(), + "BB".to_string(), + "BE".to_string(), + "BZ".to_string(), + "BJ".to_string(), + "BM".to_string(), + "BT".to_string(), + "BQ".to_string(), + "BA".to_string(), + "BW".to_string(), + "IO".to_string(), + "BN".to_string(), + "BG".to_string(), + "BF".to_string(), + "BI".to_string(), + "KH".to_string(), + "CM".to_string(), + "CA".to_string(), + "CV".to_string(), + "KY".to_string(), + "CF".to_string(), + "TD".to_string(), + "CX".to_string(), + "CC".to_string(), + "KM".to_string(), + "CG".to_string(), + "CK".to_string(), + "CI".to_string(), + "CW".to_string(), + "CY".to_string(), + "CZ".to_string(), + "DJ".to_string(), + "DM".to_string(), + "EG".to_string(), + "GQ".to_string(), + "ER".to_string(), + "EE".to_string(), + "ET".to_string(), + "FK".to_string(), + "FO".to_string(), + "FJ".to_string(), + "GF".to_string(), + "PF".to_string(), + "TF".to_string(), + "GA".to_string(), + "GM".to_string(), + "GE".to_string(), + "GH".to_string(), + "GL".to_string(), + "GD".to_string(), + "GP".to_string(), + "GU".to_string(), + "GG".to_string(), + "GN".to_string(), + "GW".to_string(), + "GY".to_string(), + "HT".to_string(), + "HM".to_string(), + "VA".to_string(), + "IS".to_string(), + "IN".to_string(), + "ID".to_string(), + "IE".to_string(), + "IM".to_string(), + "IL".to_string(), + "JE".to_string(), + "JO".to_string(), + "KZ".to_string(), + "KE".to_string(), + "KI".to_string(), + "KW".to_string(), + "KG".to_string(), + "LA".to_string(), + "LV".to_string(), + "LB".to_string(), + "LS".to_string(), + "LI".to_string(), + "LT".to_string(), + "LU".to_string(), + "MK".to_string(), + "MG".to_string(), + "MW".to_string(), + "MV".to_string(), + "ML".to_string(), + "MT".to_string(), + "MH".to_string(), + "MQ".to_string(), + "MR".to_string(), + "MU".to_string(), + "YT".to_string(), + "FM".to_string(), + "MD".to_string(), + "MC".to_string(), + "MN".to_string(), + "ME".to_string(), + "MS".to_string(), + "MA".to_string(), + "MZ".to_string(), + "NA".to_string(), + "NR".to_string(), + "NP".to_string(), + "NC".to_string(), + "NZ".to_string(), + "NE".to_string(), + "NG".to_string(), + "NU".to_string(), + "NF".to_string(), + "MP".to_string(), + "OM".to_string(), + "PK".to_string(), + "PW".to_string(), + "PS".to_string(), + "PG".to_string(), + "PH".to_string(), + "PN".to_string(), + "QA".to_string(), + "RE".to_string(), + "RO".to_string(), + "RW".to_string(), + "BL".to_string(), + "SH".to_string(), + "KN".to_string(), + "LC".to_string(), + "MF".to_string(), + "PM".to_string(), + "VC".to_string(), + "WS".to_string(), + "SM".to_string(), + "ST".to_string(), + "SA".to_string(), + "SN".to_string(), + "RS".to_string(), + "SC".to_string(), + "SL".to_string(), + "SX".to_string(), + "SK".to_string(), + "SI".to_string(), + "SB".to_string(), + "SO".to_string(), + "ZA".to_string(), + "GS".to_string(), + "KR".to_string(), + "LK".to_string(), + "SR".to_string(), + "SJ".to_string(), + "SZ".to_string(), + "TH".to_string(), + "TL".to_string(), + "TG".to_string(), + "TK".to_string(), + "TO".to_string(), + "TT".to_string(), + "TN".to_string(), + "TM".to_string(), + "TC".to_string(), + "TV".to_string(), + "UG".to_string(), + "UA".to_string(), + "AE".to_string(), + "UZ".to_string(), + "VU".to_string(), + "VN".to_string(), + "VG".to_string(), + "VI".to_string(), + "WF".to_string(), + "EH".to_string(), + "ZM".to_string(), + ] + }, + value: None, + } + + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email_address".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "payment_method_data.wallet.mifinity.language_preference".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.wallet.mifinity.language_preference".to_string(), + display_name: "language_preference".to_string(), + field_type: enums::FieldType::LanguagePreference{ + options: vec![ + "BR".to_string(), + "PT_BR".to_string(), + "CN".to_string(), + "ZH_CN".to_string(), + "DE".to_string(), + "DK".to_string(), + "DA".to_string(), + "DA_DK".to_string(), + "EN".to_string(), + "ES".to_string(), + "FI".to_string(), + "FR".to_string(), + "GR".to_string(), + "EL".to_string(), + "EL_GR".to_string(), + "HR".to_string(), + "IT".to_string(), + "JP".to_string(), + "JA".to_string(), + "JA_JP".to_string(), + "LA".to_string(), + "ES_LA".to_string(), + "NL".to_string(), + "NO".to_string(), + "PL".to_string(), + "PT".to_string(), + "RU".to_string(), + "SV".to_string(), + "SE".to_string(), + "SV_SE".to_string(), + "ZH".to_string(), + "TW".to_string(), + "ZH_TW".to_string(), + ] + }, + value: None, + } + ), + ]), + } + ), + ]), + } + ), + ])), + ), + ( + enums::PaymentMethod::PayLater, + PaymentMethodType(HashMap::from([ + ( + enums::PaymentMethodType::AfterpayClearpay, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_last_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "GB".to_string(), + "AU".to_string(), + "CA".to_string(), + "US".to_string(), + "NZ".to_string(), + ] + }, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ( + "shipping.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.first_name".to_string(), + display_name: "shipping_first_name".to_string(), + field_type: enums::FieldType::UserShippingName, + value: None, + } + ), + ( + "shipping.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.last_name".to_string(), + display_name: "shipping_last_name".to_string(), + field_type: enums::FieldType::UserShippingName, + value: None, + } + ), + ( + "shipping.address.city".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserShippingAddressCity, + value: None, + } + ), + ( + "shipping.address.state".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserShippingAddressState, + value: None, + } + ), + ( + "shipping.address.zip".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserShippingAddressPincode, + value: None, + } + ), + ( + "shipping.address.country".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserShippingAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ), + ( + "shipping.address.line1".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserShippingAddressLine1, + value: None, + } + ), + ]), + common : HashMap::new(), + } + ), + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_last_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.line2".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line2".to_string(), + display_name: "line2".to_string(), + field_type: enums::FieldType::UserAddressLine2, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "GB".to_string(), + "AU".to_string(), + "CA".to_string(), + "US".to_string(), + "NZ".to_string(), + ] + }, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ( + "shipping.address.city".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserShippingAddressCity, + value: None, + } + ), + ( + "shipping.address.zip".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserShippingAddressPincode, + value: None, + } + ), + ( + "shipping.address.country".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserShippingAddressCountry{ + options: vec![ + "GB".to_string(), + "AU".to_string(), + "CA".to_string(), + "US".to_string(), + "NZ".to_string(), + ] + }, + value: None, + } + ), + ( + "shipping.address.line1".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserShippingAddressLine1, + value: None, + } + ), + ( + "shipping.address.line2".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.line2".to_string(), + display_name: "line2".to_string(), + field_type: enums::FieldType::UserShippingAddressLine2, + value: None, + } + ), + ]), + common : HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::Klarna, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate: HashMap::from([ + ( "payment_method_data.pay_later.klarna.billing_country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.pay_later.klarna.billing_country".to_string(), + display_name: "billing_country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "AU".to_string(), + "AT".to_string(), + "BE".to_string(), + "CA".to_string(), + "CZ".to_string(), + "DK".to_string(), + "FI".to_string(), + "FR".to_string(), + "GR".to_string(), + "DE".to_string(), + "IE".to_string(), + "IT".to_string(), + "NL".to_string(), + "NZ".to_string(), + "NO".to_string(), + "PL".to_string(), + "PT".to_string(), + "RO".to_string(), + "ES".to_string(), + "SE".to_string(), + "CH".to_string(), + "GB".to_string(), + "US".to_string(), + ] + }, + value: None, + }), + ("billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + }) + ]), + common : HashMap::new(), + } + ), + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate: HashMap::new(), + common : HashMap::from([ + ( "payment_method_data.pay_later.klarna.billing_country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.pay_later.klarna.billing_country".to_string(), + display_name: "billing_country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + }), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ]), + } + ), + ( + enums::Connector::Klarna, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "AU".to_string(), + "AT".to_string(), + "BE".to_string(), + "CA".to_string(), + "CZ".to_string(), + "DK".to_string(), + "FI".to_string(), + "FR".to_string(), + "DE".to_string(), + "GR".to_string(), + "IE".to_string(), + "IT".to_string(), + "NL".to_string(), + "NZ".to_string(), + "NO".to_string(), + "PL".to_string(), + "PT".to_string(), + "ES".to_string(), + "SE".to_string(), + "CH".to_string(), + "GB".to_string(), + "US".to_string(), + ] + }, + value: None, + } + ) + ]), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::Affirm, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "US".to_string(), + ] + }, + value: None, + } + ), + ( + "billing.phone.number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.number".to_string(), + display_name: "phone_number".to_string(), + field_type: enums::FieldType::UserPhoneNumber, + value: None, + } + ), + ( + "billing.phone.country_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.country_code".to_string(), + display_name: "dialing_code".to_string(), + field_type: enums::FieldType::UserPhoneNumberCountryCode, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.line2".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line2".to_string(), + display_name: "line2".to_string(), + field_type: enums::FieldType::UserAddressLine2, + value: None, + } + ), + ( + "shipping.address.line1".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "shipping.address.line2".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.line2".to_string(), + display_name: "line2".to_string(), + field_type: enums::FieldType::UserAddressLine2, + value: None, + } + ), + ( + "shipping.address.zip".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserShippingAddressPincode, + value: None, + } + ), + ( + "shipping.address.city".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserShippingAddressCity, + value: None, + } + ), + ( + "shipping.address.country".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserCountry { + options: vec![ + "US".to_string(), + ]}, + value: None, + } + ), + + ] + ), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::PayBright, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "CA".to_string(), + ] + }, + value: None, + } + ), + ( + "payment_method_data.billing.phone.number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.number".to_string(), + display_name: "phone_number".to_string(), + field_type: enums::FieldType::UserPhoneNumber, + value: None, + } + ), + ( + "billing.phone.country_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.country_code".to_string(), + display_name: "dialing_code".to_string(), + field_type: enums::FieldType::UserPhoneNumberCountryCode, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.line2".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line2".to_string(), + display_name: "line2".to_string(), + field_type: enums::FieldType::UserAddressLine2, + value: None, + } + ), + ( + "shipping.address.city".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserShippingAddressCity, + value: None, + } + ), + ( + "shipping.address.zip".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserShippingAddressPincode, + value: None, + } + ), + ( + "shipping.address.country".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserShippingAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ), + ( + "shipping.address.line1".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserShippingAddressLine1, + value: None, + } + ), + ( + "shipping.address.line2".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.line2".to_string(), + display_name: "line2".to_string(), + field_type: enums::FieldType::UserShippingAddressLine2, + value: None, + } + ), + ] + ), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::Walley, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "billing.phone.number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.number".to_string(), + display_name: "phone".to_string(), + field_type: enums::FieldType::UserPhoneNumber, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "DK".to_string(), + "FI".to_string(), + "NO".to_string(), + "SE".to_string(), + ]}, + value: None, + } + ), + ( + "billing.phone.country_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.country_code".to_string(), + display_name: "dialing_code".to_string(), + field_type: enums::FieldType::UserPhoneNumberCountryCode, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ] + ), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::Alma, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "FR".to_string(), + ] + }, + value: None, + } + ), + ( + "payment_method_data.billing.phone.number".to_string(), + RequiredFieldInfo { + required_field: "billing.phone.number".to_string(), + display_name: "phone_number".to_string(), + field_type: enums::FieldType::UserPhoneNumber, + value: None, + } + ), + ( + "billing.phone.country_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.country_code".to_string(), + display_name: "dialing_code".to_string(), + field_type: enums::FieldType::UserPhoneNumberCountryCode, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.line2".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line2".to_string(), + display_name: "line2".to_string(), + field_type: enums::FieldType::UserAddressLine2, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::Atome, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "MY".to_string(), + "SG".to_string() + ] + }, + value: None, + } + ), + ( + "payment_method_data.billing.phone.number".to_string(), + RequiredFieldInfo { + required_field: "billing.phone.number".to_string(), + display_name: "phone_number".to_string(), + field_type: enums::FieldType::UserPhoneNumber, + value: None, + } + ), + ( + "billing.phone.country_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.country_code".to_string(), + display_name: "dialing_code".to_string(), + field_type: enums::FieldType::UserPhoneNumberCountryCode, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.line2".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line2".to_string(), + display_name: "line2".to_string(), + field_type: enums::FieldType::UserAddressLine2, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ]), + }, + ), + ])), + ), + ( + enums::PaymentMethod::Crypto, + PaymentMethodType(HashMap::from([ + ( + enums::PaymentMethodType::CryptoCurrency, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Cryptopay, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate: HashMap::from([ + ( + "payment_method_data.crypto.pay_currency".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.crypto.pay_currency".to_string(), + display_name: "currency".to_string(), + field_type: enums::FieldType::UserCurrency{ + options: vec![ + "BTC".to_string(), + "LTC".to_string(), + "ETH".to_string(), + "XRP".to_string(), + "XLM".to_string(), + "BCH".to_string(), + "ADA".to_string(), + "SOL".to_string(), + "SHIB".to_string(), + "TRX".to_string(), + "DOGE".to_string(), + "BNB".to_string(), + "USDT".to_string(), + "USDC".to_string(), + "DAI".to_string(), + ] + }, + value: None, + } + ), + ( + "payment_method_data.crypto.network".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.crypto.network".to_string(), + display_name: "network".to_string(), + field_type: enums::FieldType::UserCryptoCurrencyNetwork, + value: None, + } + ), + ]), + common : HashMap::new(), + } + ), + ]), + }, + ), + ])), + ), + ( + enums::PaymentMethod::Voucher, + PaymentMethodType(HashMap::from([ + ( + enums::PaymentMethodType::Boleto, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate : HashMap::from([ + ( + "payment_method_data.voucher.boleto.social_security_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.voucher.boleto.social_security_number".to_string(), + display_name: "social_security_number".to_string(), + field_type: enums::FieldType::Text, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "BR".to_string(), + ] + }, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.line2".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line2".to_string(), + display_name: "line2".to_string(), + field_type: enums::FieldType::UserAddressLine2, + value: None, + } + ), + ]), + common : HashMap::new(), + } + ), + ( + enums::Connector::Zen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::Alfamart, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate : HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ) + ]), + common : HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::Indomaret, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate : HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ) + ]), + common : HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::Oxxo, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate : HashMap::new(), + common : HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::SevenEleven, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate : HashMap::from([ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.phone.number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.number".to_string(), + display_name: "phone".to_string(), + field_type: enums::FieldType::UserPhoneNumber, + value: None, + } + ), + ( + "billing.phone.country_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.country_code".to_string(), + display_name: "dialing_code".to_string(), + field_type: enums::FieldType::UserPhoneNumberCountryCode, + value: None, + } + ) + ] + ), + common : HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::Lawson, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate : HashMap::from([ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.phone.number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.number".to_string(), + display_name: "phone".to_string(), + field_type: enums::FieldType::UserPhoneNumber, + value: None, + } + ), + ( + "billing.phone.country_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.country_code".to_string(), + display_name: "dialing_code".to_string(), + field_type: enums::FieldType::UserPhoneNumberCountryCode, + value: None, + } + ), + ] + ), + common : HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::MiniStop, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate : HashMap::from([ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.phone.number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.number".to_string(), + display_name: "phone".to_string(), + field_type: enums::FieldType::UserPhoneNumber, + value: None, + } + ), + ( + "billing.phone.country_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.country_code".to_string(), + display_name: "dialing_code".to_string(), + field_type: enums::FieldType::UserPhoneNumberCountryCode, + value: None, + } + ), + ] + ), + common : HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::FamilyMart, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate : HashMap::from([ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.phone.number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.number".to_string(), + display_name: "phone".to_string(), + field_type: enums::FieldType::UserPhoneNumber, + value: None, + } + ), + ( + "billing.phone.country_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.country_code".to_string(), + display_name: "dialing_code".to_string(), + field_type: enums::FieldType::UserPhoneNumberCountryCode, + value: None, + } + ), + ] + ), + common : HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::Seicomart, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate : HashMap::from([ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.phone.number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.number".to_string(), + display_name: "phone".to_string(), + field_type: enums::FieldType::UserPhoneNumber, + value: None, + } + ), + ( + "billing.phone.country_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.country_code".to_string(), + display_name: "dialing_code".to_string(), + field_type: enums::FieldType::UserPhoneNumberCountryCode, + value: None, + } + ), + ] + ), + common : HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::PayEasy, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate : HashMap::from([ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.phone.number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.number".to_string(), + display_name: "phone".to_string(), + field_type: enums::FieldType::UserPhoneNumber, + value: None, + } + ), + ( + "billing.phone.country_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.country_code".to_string(), + display_name: "dialing_code".to_string(), + field_type: enums::FieldType::UserPhoneNumberCountryCode, + value: None, + } + ), + ] + ), + common : HashMap::new(), + } + ) + ]), + }, + ), + ])), + ), + ( + enums::PaymentMethod::Upi, + PaymentMethodType(HashMap::from([ + ( + enums::PaymentMethodType::UpiCollect, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Razorpay, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate : HashMap::new(), + common : HashMap::from([ + ( + "payment_method_data.upi.upi_collect.vpa_id".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.upi.upi_collect.vpa_id".to_string(), + display_name: "vpa_id".to_string(), + field_type: enums::FieldType::UserVpaId, + value: None, + } + ), + ]), + } + ), + ]), + }, + ), + ])), + ), + ( + enums::PaymentMethod::BankDebit, + PaymentMethodType(HashMap::from([( + enums::PaymentMethodType::Ach, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "owner_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "payment_method_data.bank_debit.ach.account_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.ach.account_number".to_string(), + display_name: "bank_account_number".to_string(), + field_type: enums::FieldType::UserBankAccountNumber, + value: None, + } + ), + ( + "payment_method_data.bank_debit.ach.routing_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.ach.routing_number".to_string(), + display_name: "bank_routing_number".to_string(), + field_type: enums::FieldType::Text, + value: None, + } + ) + ]), + }), + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "owner_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + }), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "owner_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "payment_method_data.bank_debit.ach.account_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.ach.account_number".to_string(), + display_name: "bank_account_number".to_string(), + field_type: enums::FieldType::UserBankAccountNumber, + value: None, + } + ), + ( + "payment_method_data.bank_debit.ach.routing_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.ach.routing_number".to_string(), + display_name: "bank_routing_number".to_string(), + field_type: enums::FieldType::Text, + value: None, + } + ) + ]), + }) + ] + )} + ), + ( + enums::PaymentMethodType::Sepa, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "owner_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "payment_method_data.bank_debit.sepa_bank_debit.iban".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.sepa_bank_debit.iban".to_string(), + display_name: "iban".to_string(), + field_type: enums::FieldType::UserIban, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ) + ]), + } + ), + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "owner_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + }), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "owner_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "payment_method_data.bank_debit.sepa_bank_debit.iban".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.sepa_bank_debit.iban".to_string(), + display_name: "iban".to_string(), + field_type: enums::FieldType::UserIban, + value: None, + } + ) + ]), + } + ), + ( + enums::Connector::Deutschebank, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "owner_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + }), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "owner_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "payment_method_data.bank_debit.sepa_bank_debit.iban".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.sepa_bank_debit.iban".to_string(), + display_name: "iban".to_string(), + field_type: enums::FieldType::UserIban, + value: None, + } + ) + ]), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::Bacs, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "payment_method_data.bank_debit.bacs.account_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.bacs.account_number".to_string(), + display_name: "bank_account_number".to_string(), + field_type: enums::FieldType::UserBankAccountNumber, + value: None, + } + ), + ( + "payment_method_data.bank_debit.bacs.sort_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.bacs.sort_code".to_string(), + display_name: "bank_sort_code".to_string(), + field_type: enums::FieldType::Text, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry { + options: vec!["UK".to_string()], + }, + value: None, + }, + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + }, + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + }, + ) + ]), + } + ), + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "owner_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + }), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "owner_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "payment_method_data.bank_debit.bacs.account_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.bacs.account_number".to_string(), + display_name: "bank_account_number".to_string(), + field_type: enums::FieldType::UserBankAccountNumber, + value: None, + } + ), + ( + "payment_method_data.bank_debit.bacs.sort_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.bacs.sort_code".to_string(), + display_name: "bank_sort_code".to_string(), + field_type: enums::FieldType::Text, + value: None, + } + ) + ]), + }) + ]), + }, + ), + ( + enums::PaymentMethodType::Becs, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "owner_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "payment_method_data.bank_debit.becs.account_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.becs.account_number".to_string(), + display_name: "bank_account_number".to_string(), + field_type: enums::FieldType::UserBankAccountNumber, + value: None, + } + ), + ( + "payment_method_data.bank_debit.becs.bsb_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.becs.bsb_number".to_string(), + display_name: "bsb_number".to_string(), + field_type: enums::FieldType::Text, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ) + ]), + } + ), + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "owner_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + }), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "owner_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "payment_method_data.bank_debit.bacs.account_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.bacs.account_number".to_string(), + display_name: "bank_account_number".to_string(), + field_type: enums::FieldType::UserBankAccountNumber, + value: None, + } + ), + ( + "payment_method_data.bank_debit.bacs.sort_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.bacs.sort_code".to_string(), + display_name: "bank_sort_code".to_string(), + field_type: enums::FieldType::Text, + value: None, + } + ) + ]), + }) + ]), + }, + ), + ]))), + ( + enums::PaymentMethod::BankTransfer, + PaymentMethodType(HashMap::from([( + enums::PaymentMethodType::Multibanco, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ) + ]), + common: HashMap::new(), + } + ), + ])}), + (enums::PaymentMethodType::LocalBankTransfer, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Zsl, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "CN".to_string(), + ] + }, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + }, + ), + ]), + common: HashMap::new(), + } + ), + ])}), + (enums::PaymentMethodType::Ach, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ) + ]) + } + ), + ])}), + (enums::PaymentMethodType::Pix, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Itaubank, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from( + [ + ( + "payment_method_data.bank_transfer.pix.pix_key".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_transfer.pix.pix_key".to_string(), + display_name: "pix_key".to_string(), + field_type: enums::FieldType::UserPixKey, + value: None, + } + ), + ( + "payment_method_data.bank_transfer.pix.cnpj".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_transfer.pix.cnpj".to_string(), + display_name: "cnpj".to_string(), + field_type: enums::FieldType::UserCnpj, + value: None, + } + ), + ( + "payment_method_data.bank_transfer.pix.cpf".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_transfer.pix.cpf".to_string(), + display_name: "cpf".to_string(), + field_type: enums::FieldType::UserCpf, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ] + ), + } + ), + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ])}), + ( + enums::PaymentMethodType::PermataBankTransfer, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate : HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ) + ]), + common : HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::BcaBankTransfer, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate : HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ) + ]), + common : HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::BniVa, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate : HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ) + ]), + common : HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::BriVa, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate : HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ) + ]), + common : HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::CimbVa, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate : HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ) + ]), + common : HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::DanamonVa, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate : HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ) + ]), + common : HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::MandiriVa, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate : HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ) + ]), + common : HashMap::new(), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::Sepa, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate : HashMap::new(), + common : HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry { + options: vec![ + "BE".to_string(), + "DE".to_string(), + "ES".to_string(), + "FR".to_string(), + "IE".to_string(), + "NL".to_string(), + ], + }, + value: None, + }, + ), + ]), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::Bacs, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate : HashMap::new(), + common : HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ) + ]), + } + ) + ]), + }, + ), + ]))), + ( + enums::PaymentMethod::GiftCard, + PaymentMethodType(HashMap::from([ + ( + enums::PaymentMethodType::PaySafeCard, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::Givex, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + + ( + "payment_method_data.gift_card.number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.gift_card.number".to_string(), + display_name: "gift_card_number".to_string(), + field_type: enums::FieldType::UserCardNumber, + value: None, + } + ), + ( + "payment_method_data.gift_card.cvc".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.gift_card.cvc".to_string(), + display_name: "gift_card_cvc".to_string(), + field_type: enums::FieldType::UserCardCvc, + value: None, + } + ), + ]), + common: HashMap::new(), + } + ), + ]), + }, + ), + ])) + ), + ( + enums::PaymentMethod::CardRedirect, + PaymentMethodType(HashMap::from([ + ( + enums::PaymentMethodType::Benefit, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "first_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "last_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.phone.number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.number".to_string(), + display_name: "phone".to_string(), + field_type: enums::FieldType::UserPhoneNumber, + value: None, + } + ), + ( + "billing.phone.country_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.country_code".to_string(), + display_name: "dialing_code".to_string(), + field_type: enums::FieldType::UserPhoneNumberCountryCode, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::Knet, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "first_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "last_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.phone.number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.number".to_string(), + display_name: "phone".to_string(), + field_type: enums::FieldType::UserPhoneNumber, + value: None, + } + ), + ( + "billing.phone.country_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.phone.country_code".to_string(), + display_name: "dialing_code".to_string(), + field_type: enums::FieldType::UserPhoneNumberCountryCode, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ) + ] + ), + common: HashMap::new(), + } + ), + ]), + }, + ), + ( + enums::PaymentMethodType::MomoAtm, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ), + ]), + }, + ) + ])) + ) + ])) + } +} diff --git a/crates/router/src/configs/settings.rs b/crates/router/src/configs/settings.rs index 149ee2b84562..f675aad11a72 100644 --- a/crates/router/src/configs/settings.rs +++ b/crates/router/src/configs/settings.rs @@ -141,8 +141,12 @@ impl Multitenancy { pub fn get_tenants(&self) -> &HashMap { &self.tenants.0 } - pub fn get_tenant_names(&self) -> Vec { - self.tenants.0.keys().cloned().collect() + pub fn get_tenant_ids(&self) -> Vec { + self.tenants + .0 + .values() + .map(|tenant| tenant.tenant_id.clone()) + .collect() } pub fn get_tenant(&self, tenant_id: &str) -> Option<&Tenant> { self.tenants.0.get(tenant_id) @@ -154,13 +158,12 @@ pub struct DecisionConfig { pub base_url: String, } -#[derive(Debug, Deserialize, Clone, Default)] -#[serde(transparent)] +#[derive(Debug, Clone, Default)] pub struct TenantConfig(pub HashMap); -#[derive(Debug, Deserialize, Clone, Default)] +#[derive(Debug, Clone, Default)] pub struct Tenant { - pub name: String, + pub tenant_id: String, pub base_url: String, pub schema: String, pub redis_key_prefix: String, @@ -553,6 +556,7 @@ pub struct UserSettings { pub two_factor_auth_expiry_in_secs: i64, pub totp_issuer_name: String, pub base_url: String, + pub force_two_factor_auth: bool, } #[derive(Debug, Deserialize, Clone)] @@ -1102,6 +1106,38 @@ where })? } +impl<'de> Deserialize<'de> for TenantConfig { + fn deserialize>(deserializer: D) -> Result { + #[derive(Deserialize)] + struct Inner { + base_url: String, + schema: String, + redis_key_prefix: String, + clickhouse_database: String, + } + + let hashmap = >::deserialize(deserializer)?; + + Ok(Self( + hashmap + .into_iter() + .map(|(key, value)| { + ( + key.clone(), + Tenant { + tenant_id: key, + base_url: value.base_url, + schema: value.schema, + redis_key_prefix: value.redis_key_prefix, + clickhouse_database: value.clickhouse_database, + }, + ) + }) + .collect(), + )) + } +} + #[cfg(test)] mod hashmap_deserialization_test { #![allow(clippy::unwrap_used)] diff --git a/crates/router/src/connector.rs b/crates/router/src/connector.rs index c0c64d76415a..c35856354de0 100644 --- a/crates/router/src/connector.rs +++ b/crates/router/src/connector.rs @@ -1,7 +1,6 @@ pub mod aci; pub mod adyen; pub mod adyenplatform; -pub mod airwallex; pub mod authorizedotnet; pub mod bamboraapac; pub mod bankofamerica; @@ -14,7 +13,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; @@ -22,27 +20,21 @@ pub mod iatapay; pub mod itaubank; 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; pub mod rapyd; -pub mod razorpay; pub mod riskified; -pub mod shift4; pub mod signifyd; pub mod stripe; pub mod threedsecureio; @@ -51,34 +43,33 @@ pub mod utils; pub mod wellsfargo; pub mod wellsfargopayout; pub mod wise; -pub mod worldpay; -pub mod zen; -pub mod zsl; pub use hyperswitch_connectors::connectors::{ - bambora, bambora::Bambora, billwerk, billwerk::Billwerk, bitpay, bitpay::Bitpay, cashtocode, - 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, + airwallex, airwallex::Airwallex, bambora, bambora::Bambora, billwerk, billwerk::Billwerk, + bitpay, bitpay::Bitpay, cashtocode, cashtocode::Cashtocode, coinbase, coinbase::Coinbase, + cryptopay, cryptopay::Cryptopay, deutschebank, deutschebank::Deutschebank, digitalvirgo, + digitalvirgo::Digitalvirgo, dlocal, dlocal::Dlocal, elavon, elavon::Elavon, fiserv, + fiserv::Fiserv, fiservemea, fiservemea::Fiservemea, fiuu, fiuu::Fiuu, forte, forte::Forte, + globepay, globepay::Globepay, helcim, helcim::Helcim, jpmorgan, jpmorgan::Jpmorgan, mollie, + mollie::Mollie, multisafepay, multisafepay::Multisafepay, nexinets, nexinets::Nexinets, + nexixpay, nexixpay::Nexixpay, novalnet, novalnet::Novalnet, payeezy, payeezy::Payeezy, payu, + payu::Payu, powertranz, powertranz::Powertranz, razorpay, razorpay::Razorpay, shift4, + shift4::Shift4, square, square::Square, stax, stax::Stax, taxjar, taxjar::Taxjar, thunes, + thunes::Thunes, tsys, tsys::Tsys, volt, volt::Volt, worldline, worldline::Worldline, worldpay, + worldpay::Worldpay, zen, zen::Zen, zsl, zsl::Zsl, }; #[cfg(feature = "dummy_connector")] pub use self::dummyconnector::DummyConnector; 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, - 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, + aci::Aci, adyen::Adyen, adyenplatform::Adyenplatform, authorizedotnet::Authorizedotnet, + bamboraapac::Bamboraapac, bankofamerica::Bankofamerica, bluesnap::Bluesnap, boku::Boku, + braintree::Braintree, checkout::Checkout, cybersource::Cybersource, datatrans::Datatrans, + ebanx::Ebanx, globalpay::Globalpay, gocardless::Gocardless, gpayments::Gpayments, + iatapay::Iatapay, itaubank::Itaubank, klarna::Klarna, mifinity::Mifinity, 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, riskified::Riskified, signifyd::Signifyd, stripe::Stripe, + threedsecureio::Threedsecureio, trustpay::Trustpay, wellsfargo::Wellsfargo, + wellsfargopayout::Wellsfargopayout, wise::Wise, }; diff --git a/crates/router/src/connector/aci/transformers.rs b/crates/router/src/connector/aci/transformers.rs index 5e803b593ee4..77598f7be381 100644 --- a/crates/router/src/connector/aci/transformers.rs +++ b/crates/router/src/connector/aci/transformers.rs @@ -749,6 +749,7 @@ impl connector_mandate_id: Some(id.expose()), payment_method_id: None, mandate_metadata: None, + connector_mandate_request_reference_id: None, }); Ok(Self { @@ -763,8 +764,8 @@ impl }, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id.clone()), - redirection_data, - mandate_reference, + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(mandate_reference), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.id), diff --git a/crates/router/src/connector/adyen/transformers.rs b/crates/router/src/connector/adyen/transformers.rs index ca13e57e401f..95ac2a67a533 100644 --- a/crates/router/src/connector/adyen/transformers.rs +++ b/crates/router/src/connector/adyen/transformers.rs @@ -14,7 +14,7 @@ use time::{Duration, OffsetDateTime, PrimitiveDateTime}; use crate::{connector::utils::PayoutsData, types::api::payouts, utils::OptionExt}; use crate::{ connector::utils::{ - self, AddressDetailsData, BrowserInformationData, CardData, MandateReferenceData, + self, missing_field_err, AddressDetailsData, BrowserInformationData, CardData, PaymentsAuthorizeRequestData, PhoneDetailsData, RouterData, }, consts, @@ -1770,8 +1770,8 @@ fn get_line_items(item: &AdyenRouterData<&types::PaymentsAuthorizeRouterData>) - .iter() .enumerate() .map(|(i, data)| LineItem { - amount_including_tax: Some(MinorUnit::new(data.amount)), - amount_excluding_tax: Some(MinorUnit::new(data.amount)), + amount_including_tax: Some(data.amount), + amount_excluding_tax: Some(data.amount), description: Some(data.product_name.clone()), id: Some(format!("Items #{i}")), tax_amount: None, @@ -2573,7 +2573,9 @@ impl<'a> None => PaymentType::Scheme, }, stored_payment_method_id: Secret::new( - connector_mandate_ids.get_connector_mandate_id()?, + connector_mandate_ids + .get_connector_mandate_id() + .ok_or_else(missing_field_err("mandate_id"))?, ), }; Ok::, Self::Error>(AdyenPaymentMethod::Mandate(Box::new( @@ -3273,8 +3275,8 @@ impl TryFrom> resource_id: types::ResponseId::ConnectorTransactionId( item.response.payment_psp_reference, ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.reference), @@ -3308,8 +3310,8 @@ impl Ok(Self { response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.psp_reference), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -3365,6 +3367,7 @@ pub fn get_adyen_response( connector_mandate_id: Some(mandate_id.expose()), payment_method_id: None, mandate_metadata: None, + connector_mandate_request_reference_id: None, }); let network_txn_id = response.additional_data.and_then(|additional_data| { additional_data @@ -3374,8 +3377,8 @@ pub fn get_adyen_response( let payments_response_data = types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(response.psp_reference), - redirection_data: None, - mandate_reference, + redirection_data: Box::new(None), + mandate_reference: Box::new(mandate_reference), connector_metadata: None, network_txn_id, connector_response_reference_id: Some(response.merchant_reference), @@ -3438,8 +3441,8 @@ pub fn get_webhook_response( .payment_reference .unwrap_or(response.transaction_id), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(response.merchant_reference_id), @@ -3508,8 +3511,8 @@ pub fn get_redirection_response( Some(psp) => types::ResponseId::ConnectorTransactionId(psp.to_string()), None => types::ResponseId::NoResponseId, }, - redirection_data, - mandate_reference: None, + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(None), connector_metadata, network_txn_id: None, connector_response_reference_id: response @@ -3566,8 +3569,8 @@ pub fn get_present_to_shopper_response( Some(psp) => types::ResponseId::ConnectorTransactionId(psp.to_string()), None => types::ResponseId::NoResponseId, }, - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata, network_txn_id: None, connector_response_reference_id: response @@ -3623,8 +3626,8 @@ pub fn get_qr_code_response( Some(psp) => types::ResponseId::ConnectorTransactionId(psp.to_string()), None => types::ResponseId::NoResponseId, }, - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata, network_txn_id: None, connector_response_reference_id: response @@ -3666,8 +3669,8 @@ pub fn get_redirection_error_response( // We don't get connector transaction id for redirections in Adyen. let payments_response_data = types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::NoResponseId, - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: response @@ -4036,8 +4039,8 @@ impl TryFrom> status: storage_enums::AttemptStatus::Pending, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(connector_transaction_id), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.reference), diff --git a/crates/router/src/connector/authorizedotnet/transformers.rs b/crates/router/src/connector/authorizedotnet/transformers.rs index 903470ae952a..c9427683d883 100644 --- a/crates/router/src/connector/authorizedotnet/transformers.rs +++ b/crates/router/src/connector/authorizedotnet/transformers.rs @@ -388,20 +388,20 @@ impl status: enums::AttemptStatus::Charged, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::NoResponseId, - redirection_data: None, - mandate_reference: item.response.customer_profile_id.map( + redirection_data: Box::new(None), + mandate_reference: Box::new(item.response.customer_profile_id.map( |customer_profile_id| types::MandateReference { - connector_mandate_id: item - .response - .customer_payment_profile_id_list - .first() - .map(|payment_profile_id| { - format!("{customer_profile_id}-{payment_profile_id}") - }), + connector_mandate_id: + item.response.customer_payment_profile_id_list.first().map( + |payment_profile_id| { + format!("{customer_profile_id}-{payment_profile_id}") + }, + ), payment_method_id: None, mandate_metadata: None, + connector_mandate_request_reference_id: None, }, - ), + )), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -648,7 +648,7 @@ impl ), ) -> Result { let mandate_id = connector_mandate_id - .connector_mandate_id + .get_connector_mandate_id() .ok_or(errors::ConnectorError::MissingConnectorMandateID)?; Ok(Self { transaction_type: TransactionType::try_from(item.router_data.request.capture_method)?, @@ -1114,6 +1114,7 @@ impl ), payment_method_id: None, mandate_metadata: None, + connector_mandate_request_reference_id: None, } }); @@ -1125,8 +1126,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( transaction_response.transaction_id.clone(), ), - redirection_data, - mandate_reference, + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(mandate_reference), connector_metadata: metadata, network_txn_id: transaction_response .network_trans_id @@ -1198,8 +1199,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( transaction_response.transaction_id.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: metadata, network_txn_id: transaction_response .network_trans_id @@ -1528,8 +1529,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( transaction.transaction_id.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(transaction.transaction_id.clone()), diff --git a/crates/router/src/connector/bamboraapac/transformers.rs b/crates/router/src/connector/bamboraapac/transformers.rs index 819c918338e7..1a254c052a49 100644 --- a/crates/router/src/connector/bamboraapac/transformers.rs +++ b/crates/router/src/connector/bamboraapac/transformers.rs @@ -39,14 +39,14 @@ pub fn get_payment_body( let transaction_data = get_transaction_body(req)?; let body = format!( r#" - + ]]> @@ -281,6 +281,7 @@ impl connector_mandate_id, payment_method_id: None, mandate_metadata: None, + connector_mandate_request_reference_id: None, }) } else { None @@ -293,8 +294,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( connector_transaction_id.to_owned(), ), - redirection_data: None, - mandate_reference, + redirection_data: Box::new(None), + mandate_reference: Box::new(mandate_reference), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(connector_transaction_id), @@ -354,12 +355,12 @@ pub fn get_setup_mandate_body(req: &types::SetupMandateRouterData) -> Result - {} + {} {} {} {} 2 - {} + {} {} ]]> @@ -460,12 +461,13 @@ impl status: enums::AttemptStatus::Charged, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::NoResponseId, - redirection_data: None, - mandate_reference: Some(types::MandateReference { + redirection_data: Box::new(None), + mandate_reference: Box::new(Some(types::MandateReference { connector_mandate_id: Some(connector_mandate_id), payment_method_id: None, mandate_metadata: None, - }), + connector_mandate_request_reference_id: None, + })), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -501,7 +503,7 @@ pub fn get_capture_body( let auth_details = BamboraapacAuthType::try_from(&req.router_data.connector_auth_type)?; let body = format!( r#" - @@ -514,8 +516,8 @@ pub fn get_capture_body( {} {} - - ]]> + + ]]> @@ -610,8 +612,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( connector_transaction_id.to_owned(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata, network_txn_id: None, connector_response_reference_id: Some(connector_transaction_id), @@ -663,7 +665,7 @@ pub fn get_refund_body( let auth_details = BamboraapacAuthType::try_from(&req.router_data.connector_auth_type)?; let body = format!( r#" - @@ -677,9 +679,9 @@ pub fn get_refund_body( {} {} - + - ]]> + ]]> @@ -792,7 +794,7 @@ pub fn get_payment_sync_body(req: &types::PaymentsSyncRouterData) -> Result @@ -810,8 +812,8 @@ pub fn get_payment_sync_body(req: &types::PaymentsSyncRouterData) -> Result{} {} - - ]]> + + ]]> @@ -909,8 +911,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( connector_transaction_id.to_owned(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(connector_transaction_id), @@ -961,7 +963,7 @@ pub fn get_refund_sync_body(req: &types::RefundSyncRouterData) -> Result let body = format!( r#" - @@ -979,8 +981,8 @@ pub fn get_refund_sync_body(req: &types::RefundSyncRouterData) -> Result {} {} - - ]]> + + ]]> diff --git a/crates/router/src/connector/bankofamerica/transformers.rs b/crates/router/src/connector/bankofamerica/transformers.rs index ad75328322de..c6490cd61398 100644 --- a/crates/router/src/connector/bankofamerica/transformers.rs +++ b/crates/router/src/connector/bankofamerica/transformers.rs @@ -362,6 +362,7 @@ impl .map(|payment_instrument| payment_instrument.id.expose()), payment_method_id: None, mandate_metadata: None, + connector_mandate_request_reference_id: None, } }); let mut mandate_status = @@ -412,8 +413,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( info_response.id.clone(), ), - redirection_data: None, - mandate_reference, + redirection_data: Box::new(None), + mandate_reference: Box::new(mandate_reference), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some( @@ -1512,12 +1513,13 @@ fn get_payment_response( .map(|payment_instrument| payment_instrument.id.expose()), payment_method_id: None, mandate_metadata: None, + connector_mandate_request_reference_id: None, }); Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(info_response.id.clone()), - redirection_data: None, - mandate_reference, + redirection_data: Box::new(None), + mandate_reference: Box::new(mandate_reference), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some( @@ -1829,8 +1831,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( item.response.id.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: item @@ -1852,8 +1854,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( item.response.id.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.id), diff --git a/crates/router/src/connector/bluesnap.rs b/crates/router/src/connector/bluesnap.rs index e6f01700c6d7..468f68dc340c 100644 --- a/crates/router/src/connector/bluesnap.rs +++ b/crates/router/src/connector/bluesnap.rs @@ -741,10 +741,10 @@ impl ConnectorIntegration resource_id: types::ResponseId::ConnectorTransactionId( item.response.transaction_id.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.transaction_id), diff --git a/crates/router/src/connector/boku/transformers.rs b/crates/router/src/connector/boku/transformers.rs index bc9eb4e37220..777b795a438d 100644 --- a/crates/router/src/connector/boku/transformers.rs +++ b/crates/router/src/connector/boku/transformers.rs @@ -301,8 +301,8 @@ impl TryFrom } else { Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(transaction_data.id), - redirection_data: None, - mandate_reference: transaction_data.payment_method.as_ref().map(|pm| { - MandateReference { + redirection_data: Box::new(None), + mandate_reference: Box::new(transaction_data.payment_method.as_ref().map( + |pm| MandateReference { connector_mandate_id: Some(pm.id.clone().expose()), payment_method_id: None, mandate_metadata: None, - } - }), + connector_mandate_request_reference_id: None, + }, + )), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -464,12 +465,12 @@ impl status: enums::AttemptStatus::AuthenticationPending, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::NoResponseId, - redirection_data: Some(get_braintree_redirect_form( + redirection_data: Box::new(Some(get_braintree_redirect_form( *client_token_data, item.data.get_payment_method_token()?, item.data.request.payment_method_data.clone(), - )?), - mandate_reference: None, + )?)), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -614,14 +615,15 @@ impl } else { Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(transaction_data.id), - redirection_data: None, - mandate_reference: transaction_data.payment_method.as_ref().map(|pm| { - MandateReference { + redirection_data: Box::new(None), + mandate_reference: Box::new(transaction_data.payment_method.as_ref().map( + |pm| MandateReference { connector_mandate_id: Some(pm.id.clone().expose()), payment_method_id: None, mandate_metadata: None, - } - }), + connector_mandate_request_reference_id: None, + }, + )), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -639,12 +641,12 @@ impl status: enums::AttemptStatus::AuthenticationPending, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::NoResponseId, - redirection_data: Some(get_braintree_redirect_form( + redirection_data: Box::new(Some(get_braintree_redirect_form( *client_token_data, item.data.get_payment_method_token()?, item.data.request.payment_method_data.clone(), - )?), - mandate_reference: None, + )?)), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -696,14 +698,15 @@ impl } else { Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(transaction_data.id), - redirection_data: None, - mandate_reference: transaction_data.payment_method.as_ref().map(|pm| { - MandateReference { + redirection_data: Box::new(None), + mandate_reference: Box::new(transaction_data.payment_method.as_ref().map( + |pm| MandateReference { connector_mandate_id: Some(pm.id.clone().expose()), payment_method_id: None, mandate_metadata: None, - } - }), + connector_mandate_request_reference_id: None, + }, + )), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -760,14 +763,15 @@ impl } else { Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(transaction_data.id), - redirection_data: None, - mandate_reference: transaction_data.payment_method.as_ref().map(|pm| { - MandateReference { + redirection_data: Box::new(None), + mandate_reference: Box::new(transaction_data.payment_method.as_ref().map( + |pm| MandateReference { connector_mandate_id: Some(pm.id.clone().expose()), payment_method_id: None, mandate_metadata: None, - } - }), + connector_mandate_request_reference_id: None, + }, + )), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -1274,8 +1278,8 @@ impl TryFrom> } else { Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(transaction_data.id), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -1384,8 +1388,8 @@ impl } else { Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::NoResponseId, - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -1489,8 +1493,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( edge_data.node.id.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, diff --git a/crates/router/src/connector/checkout/transformers.rs b/crates/router/src/connector/checkout/transformers.rs index 3e951b3ac864..686a9d57ac3b 100644 --- a/crates/router/src/connector/checkout/transformers.rs +++ b/crates/router/src/connector/checkout/transformers.rs @@ -688,8 +688,8 @@ impl TryFrom> }; let payments_response_data = types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id.clone()), - redirection_data, - mandate_reference: None, + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(None), connector_metadata: Some(connector_meta), network_txn_id: None, connector_response_reference_id: Some( @@ -741,8 +741,8 @@ impl TryFrom> }; let payments_response_data = types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id.clone()), - redirection_data, - mandate_reference: None, + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some( @@ -819,8 +819,8 @@ impl TryFrom> Ok(Self { response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(response.action_id.clone()), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -920,8 +920,8 @@ impl TryFrom> Ok(Self { response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(resource_id), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: Some(connector_meta), network_txn_id: None, connector_response_reference_id: item.response.reference, diff --git a/crates/router/src/connector/cybersource/transformers.rs b/crates/router/src/connector/cybersource/transformers.rs index da7682586145..b99d0cb3283a 100644 --- a/crates/router/src/connector/cybersource/transformers.rs +++ b/crates/router/src/connector/cybersource/transformers.rs @@ -1117,12 +1117,16 @@ fn build_bill_to( Ok(address_details .and_then(|addr| { addr.address.as_ref().map(|addr| BillTo { - first_name: addr.first_name.clone(), - last_name: addr.last_name.clone(), - address1: addr.line1.clone(), - locality: addr.city.clone(), - administrative_area: addr.to_state_code_as_optional().ok().flatten(), - postal_code: addr.zip.clone(), + first_name: addr.first_name.remove_new_line(), + last_name: addr.last_name.remove_new_line(), + address1: addr.line1.remove_new_line(), + locality: addr.city.remove_new_line(), + administrative_area: addr + .to_state_code_as_optional() + .ok() + .flatten() + .remove_new_line(), + postal_code: addr.zip.remove_new_line(), country: addr.country, email, }) @@ -2555,12 +2559,13 @@ fn get_payment_response( .map(|payment_instrument| payment_instrument.id.expose()), payment_method_id: None, mandate_metadata: None, + connector_mandate_request_reference_id: None, }); Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(info_response.id.clone()), - redirection_data: None, - mandate_reference, + redirection_data: Box::new(None), + mandate_reference: Box::new(mandate_reference), connector_metadata: None, network_txn_id: info_response.processor_information.as_ref().and_then( |processor_information| processor_information.network_transaction_id.clone(), @@ -2647,18 +2652,20 @@ impl status: enums::AttemptStatus::AuthenticationPending, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::NoResponseId, - redirection_data: Some(services::RedirectForm::CybersourceAuthSetup { - access_token: info_response - .consumer_authentication_information - .access_token, - ddc_url: info_response - .consumer_authentication_information - .device_data_collection_url, - reference_id: info_response - .consumer_authentication_information - .reference_id, - }), - mandate_reference: None, + redirection_data: Box::new(Some( + services::RedirectForm::CybersourceAuthSetup { + access_token: info_response + .consumer_authentication_information + .access_token, + ddc_url: info_response + .consumer_authentication_information + .device_data_collection_url, + reference_id: info_response + .consumer_authentication_information + .reference_id, + }, + )), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some( @@ -3066,8 +3073,8 @@ impl status, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::NoResponseId, - redirection_data, - mandate_reference: None, + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(None), connector_metadata: Some(serde_json::json!({ "three_ds_data": three_ds_data })), @@ -3281,6 +3288,7 @@ impl .map(|payment_instrument| payment_instrument.id.expose()), payment_method_id: None, mandate_metadata: None, + connector_mandate_request_reference_id: None, }); let mut mandate_status = enums::AttemptStatus::foreign_from(( item.response @@ -3311,8 +3319,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( item.response.id.clone(), ), - redirection_data: None, - mandate_reference, + redirection_data: Box::new(None), + mandate_reference: Box::new(mandate_reference), connector_metadata: None, network_txn_id: item.response.processor_information.as_ref().and_then( |processor_information| { @@ -3449,8 +3457,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( item.response.id.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: item @@ -3471,8 +3479,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( item.response.id.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.id), @@ -4050,3 +4058,22 @@ fn get_cybersource_card_type(card_network: common_enums::CardNetwork) -> Option< common_enums::CardNetwork::Interac | common_enums::CardNetwork::RuPay => None, } } + +pub trait RemoveNewLine { + fn remove_new_line(&self) -> Self; +} + +impl RemoveNewLine for Option> { + fn remove_new_line(&self) -> Self { + self.clone().map(|masked_value| { + let new_string = masked_value.expose().replace("\n", " "); + Secret::new(new_string) + }) + } +} + +impl RemoveNewLine for Option { + fn remove_new_line(&self) -> Self { + self.clone().map(|value| value.replace("\n", " ")) + } +} diff --git a/crates/router/src/connector/datatrans/transformers.rs b/crates/router/src/connector/datatrans/transformers.rs index b28504a1d83c..e9dcfd87071e 100644 --- a/crates/router/src/connector/datatrans/transformers.rs +++ b/crates/router/src/connector/datatrans/transformers.rs @@ -293,8 +293,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( response.transaction_id.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -411,8 +411,8 @@ impl TryFrom> status: enums::AttemptStatus::from(response), response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id, - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, diff --git a/crates/router/src/connector/dummyconnector/transformers.rs b/crates/router/src/connector/dummyconnector/transformers.rs index 2cf5960bf753..79caa3d0a767 100644 --- a/crates/router/src/connector/dummyconnector/transformers.rs +++ b/crates/router/src/connector/dummyconnector/transformers.rs @@ -253,8 +253,8 @@ impl TryFrom Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(response.id), - redirection_data, - mandate_reference, + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(mandate_reference), connector_metadata: None, network_txn_id: None, connector_response_reference_id: response.reference, @@ -472,7 +473,7 @@ fn get_mandate_details(item: &types::PaymentsAuthorizeRouterData) -> Result connector_mandate_ids.connector_mandate_id, + )) => connector_mandate_ids.get_connector_mandate_id(), _ => None, } }); diff --git a/crates/router/src/connector/gocardless/transformers.rs b/crates/router/src/connector/gocardless/transformers.rs index c0360a94a517..6a8fe01eede5 100644 --- a/crates/router/src/connector/gocardless/transformers.rs +++ b/crates/router/src/connector/gocardless/transformers.rs @@ -516,6 +516,7 @@ impl connector_mandate_id: Some(item.response.mandates.id.clone().expose()), payment_method_id: None, mandate_metadata: None, + connector_mandate_request_reference_id: None, }); Ok(Self { response: Ok(types::PaymentsResponseData::TransactionResponse { @@ -523,8 +524,8 @@ impl connector_response_reference_id: None, incremental_authorization_allowed: None, resource_id: ResponseId::NoResponseId, - redirection_data: None, - mandate_reference, + redirection_data: Box::new(None), + mandate_reference: Box::new(mandate_reference), network_txn_id: None, charge_id: None, }), @@ -669,13 +670,14 @@ impl connector_mandate_id: Some(item.data.request.get_connector_mandate_id()?), payment_method_id: None, mandate_metadata: None, + connector_mandate_request_reference_id: None, }; Ok(Self { status: enums::AttemptStatus::from(item.response.payments.status), response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: ResponseId::ConnectorTransactionId(item.response.payments.id), - redirection_data: None, - mandate_reference: Some(mandate_reference), + redirection_data: Box::new(None), + mandate_reference: Box::new(Some(mandate_reference)), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -710,8 +712,8 @@ impl status: enums::AttemptStatus::from(item.response.payments.status), response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: ResponseId::ConnectorTransactionId(item.response.payments.id), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, diff --git a/crates/router/src/connector/iatapay/transformers.rs b/crates/router/src/connector/iatapay/transformers.rs index de92168036cf..ec94b322fe71 100644 --- a/crates/router/src/connector/iatapay/transformers.rs +++ b/crates/router/src/connector/iatapay/transformers.rs @@ -382,8 +382,8 @@ fn get_iatpay_response( types::PaymentsResponseData::TransactionResponse { resource_id: id, - redirection_data, - mandate_reference: None, + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(None), connector_metadata, network_txn_id: None, connector_response_reference_id: connector_response_reference_id.clone(), @@ -393,8 +393,8 @@ fn get_iatpay_response( } None => types::PaymentsResponseData::TransactionResponse { resource_id: id.clone(), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: connector_response_reference_id.clone(), diff --git a/crates/router/src/connector/itaubank/transformers.rs b/crates/router/src/connector/itaubank/transformers.rs index 41c41408381c..15dfb1ce2401 100644 --- a/crates/router/src/connector/itaubank/transformers.rs +++ b/crates/router/src/connector/itaubank/transformers.rs @@ -280,8 +280,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( item.response.txid.to_owned(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata, network_txn_id: None, connector_response_reference_id: Some(item.response.txid), @@ -368,8 +368,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( item.response.txid.to_owned(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata, network_txn_id: None, connector_response_reference_id: Some(item.response.txid), diff --git a/crates/router/src/connector/klarna.rs b/crates/router/src/connector/klarna.rs index 0c362d26edfe..07bc6bd014c9 100644 --- a/crates/router/src/connector/klarna.rs +++ b/crates/router/src/connector/klarna.rs @@ -1,9 +1,11 @@ pub mod transformers; -use std::fmt::Debug; use api_models::enums; use base64::Engine; -use common_utils::request::RequestContent; +use common_utils::{ + request::RequestContent, + types::{AmountConvertor, MinorUnit, MinorUnitForConnector}, +}; use error_stack::{report, ResultExt}; use masking::PeekInterface; use router_env::logger; @@ -29,8 +31,18 @@ use crate::{ utils::BytesExt, }; -#[derive(Debug, Clone)] -pub struct Klarna; +#[derive(Clone)] +pub struct Klarna { + amount_converter: &'static (dyn AmountConvertor + Sync), +} + +impl Klarna { + pub fn new() -> &'static Self { + &Self { + amount_converter: &MinorUnitForConnector, + } + } +} impl ConnectorCommon for Klarna { fn id(&self) -> &'static str { @@ -215,12 +227,12 @@ impl req: &types::PaymentsSessionRouterData, _connectors: &settings::Connectors, ) -> CustomResult { - let connector_router_data = klarna::KlarnaRouterData::try_from(( - &self.get_currency_unit(), + let amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_amount, req.request.currency, - req.request.amount, - req, - ))?; + )?; + let connector_router_data = klarna::KlarnaRouterData::from((amount, req)); let connector_req = klarna::KlarnaSessionRequest::try_from(&connector_router_data)?; // encode only for for urlencoded things. @@ -342,12 +354,12 @@ impl req: &types::PaymentsCaptureRouterData, _connectors: &settings::Connectors, ) -> CustomResult { - let connector_router_data = klarna::KlarnaRouterData::try_from(( - &self.get_currency_unit(), + let amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_amount_to_capture, req.request.currency, - req.request.amount_to_capture, - req, - ))?; + )?; + let connector_router_data = klarna::KlarnaRouterData::from((amount, req)); let connector_req = klarna::KlarnaCaptureRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -670,12 +682,12 @@ impl req: &types::PaymentsAuthorizeRouterData, _connectors: &settings::Connectors, ) -> CustomResult { - let connector_router_data = klarna::KlarnaRouterData::try_from(( - &self.get_currency_unit(), + let amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_amount, req.request.currency, - req.request.amount, - req, - ))?; + )?; + let connector_router_data = klarna::KlarnaRouterData::from((amount, req)); let connector_req = klarna::KlarnaPaymentsRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) @@ -847,12 +859,12 @@ impl services::ConnectorIntegration, _connectors: &settings::Connectors, ) -> CustomResult { - let connector_router_data = klarna::KlarnaRouterData::try_from(( - &self.get_currency_unit(), + let amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_refund_amount, req.request.currency, - req.request.refund_amount, - req, - ))?; + )?; + let connector_router_data = klarna::KlarnaRouterData::from((amount, req)); let connector_req = klarna::KlarnaRefundRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } diff --git a/crates/router/src/connector/klarna/transformers.rs b/crates/router/src/connector/klarna/transformers.rs index e6f0bab9c2c8..62a5cef0bcae 100644 --- a/crates/router/src/connector/klarna/transformers.rs +++ b/crates/router/src/connector/klarna/transformers.rs @@ -1,5 +1,5 @@ use api_models::payments; -use common_utils::pii; +use common_utils::{pii, types::MinorUnit}; use error_stack::{report, ResultExt}; use hyperswitch_domain_models::router_data::KlarnaSdkResponse; use masking::{ExposeInterface, Secret}; @@ -15,25 +15,16 @@ use crate::{ #[derive(Debug, Serialize)] pub struct KlarnaRouterData { - amount: i64, + amount: MinorUnit, router_data: T, } -impl TryFrom<(&api::CurrencyUnit, enums::Currency, i64, T)> for KlarnaRouterData { - type Error = error_stack::Report; - - fn try_from( - (_currency_unit, _currency, amount, router_data): ( - &api::CurrencyUnit, - enums::Currency, - i64, - T, - ), - ) -> Result { - Ok(Self { +impl From<(MinorUnit, T)> for KlarnaRouterData { + fn from((amount, router_data): (MinorUnit, T)) -> Self { + Self { amount, router_data, - }) + } } } @@ -74,7 +65,7 @@ impl TryFrom<&Option> for KlarnaConnectorMetadataObject { pub struct KlarnaPaymentsRequest { auto_capture: bool, order_lines: Vec, - order_amount: i64, + order_amount: MinorUnit, purchase_country: enums::CountryAlpha2, purchase_currency: enums::Currency, merchant_reference1: Option, @@ -110,7 +101,7 @@ pub struct KlarnaSessionRequest { intent: KlarnaSessionIntent, purchase_country: enums::CountryAlpha2, purchase_currency: enums::Currency, - order_amount: i64, + order_amount: MinorUnit, order_lines: Vec, shipping_address: Option, } @@ -157,7 +148,7 @@ impl TryFrom<&KlarnaRouterData<&types::PaymentsSessionRouterData>> for KlarnaSes name: data.product_name.clone(), quantity: data.quantity, unit_price: data.amount, - total_amount: i64::from(data.quantity) * (data.amount), + total_amount: data.amount * data.quantity, }) .collect(), shipping_address: get_address_info(item.router_data.get_optional_shipping()) @@ -210,7 +201,7 @@ impl TryFrom<&KlarnaRouterData<&types::PaymentsAuthorizeRouterData>> for KlarnaP name: data.product_name.clone(), quantity: data.quantity, unit_price: data.amount, - total_amount: i64::from(data.quantity) * (data.amount), + total_amount: data.amount * data.quantity, }) .collect(), merchant_reference1: Some(item.router_data.connector_request_reference_id.clone()), @@ -272,8 +263,8 @@ impl TryFrom> resource_id: types::ResponseId::ConnectorTransactionId( item.response.order_id.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.order_id.clone()), @@ -294,8 +285,8 @@ impl TryFrom> pub struct OrderLines { name: String, quantity: u16, - unit_price: i64, - total_amount: i64, + unit_price: MinorUnit, + total_amount: MinorUnit, } #[derive(Debug, Serialize)] @@ -394,8 +385,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( item.response.order_id.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: item @@ -412,7 +403,7 @@ impl #[derive(Debug, Serialize)] pub struct KlarnaCaptureRequest { - captured_amount: i64, + captured_amount: MinorUnit, reference: Option, } @@ -474,8 +465,8 @@ impl Ok(Self { response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(resource_id), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: Some(connector_meta), network_txn_id: None, connector_response_reference_id: None, @@ -490,7 +481,7 @@ impl #[derive(Default, Debug, Serialize)] pub struct KlarnaRefundRequest { - refunded_amount: i64, + refunded_amount: MinorUnit, reference: Option, } diff --git a/crates/router/src/connector/mifinity/transformers.rs b/crates/router/src/connector/mifinity/transformers.rs index 03c63d667959..6ff52bb7eb1b 100644 --- a/crates/router/src/connector/mifinity/transformers.rs +++ b/crates/router/src/connector/mifinity/transformers.rs @@ -259,10 +259,10 @@ impl status: enums::AttemptStatus::AuthenticationPending, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(trace_id.clone()), - redirection_data: Some(services::RedirectForm::Mifinity { + redirection_data: Box::new(Some(services::RedirectForm::Mifinity { initialization_token, - }), - mandate_reference: None, + })), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(trace_id), @@ -276,8 +276,8 @@ impl status: enums::AttemptStatus::AuthenticationPending, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::NoResponseId, - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -345,8 +345,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( transaction_reference, ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -360,8 +360,8 @@ impl status: enums::AttemptStatus::from(status), response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::NoResponseId, - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -376,8 +376,8 @@ impl status: item.data.status, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::NoResponseId, - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, diff --git a/crates/router/src/connector/nmi/transformers.rs b/crates/router/src/connector/nmi/transformers.rs index af2a9fe56bb1..0ec9cc948883 100644 --- a/crates/router/src/connector/nmi/transformers.rs +++ b/crates/router/src/connector/nmi/transformers.rs @@ -185,7 +185,7 @@ impl Response::Approved => ( Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::NoResponseId, - redirection_data: Some(services::RedirectForm::Nmi { + redirection_data: Box::new(Some(services::RedirectForm::Nmi { amount: utils::to_currency_base_unit_asf64( amount_data, currency_data.to_owned(), @@ -206,8 +206,8 @@ impl }, )?, order_id: item.data.connector_request_reference_id.clone(), - }), - mandate_reference: None, + })), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.transactionid), @@ -360,8 +360,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( item.response.transactionid, ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.orderid), @@ -743,8 +743,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( item.response.transactionid.to_owned(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.orderid), @@ -838,8 +838,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( item.response.transactionid.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.orderid), @@ -895,8 +895,8 @@ impl TryFrom> resource_id: types::ResponseId::ConnectorTransactionId( item.response.transactionid.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.orderid), @@ -946,8 +946,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( item.response.transactionid.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.orderid), @@ -997,8 +997,8 @@ impl TryFrom connector_mandate_id: Some(subscription_data.identifier.expose()), payment_method_id: None, mandate_metadata: None, + connector_mandate_request_reference_id: None, }); Ok(Self { status, @@ -596,8 +597,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( order.id.to_string(), ), - redirection_data, - mandate_reference, + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(mandate_reference), connector_metadata: None, network_txn_id: None, connector_response_reference_id, diff --git a/crates/router/src/connector/nuvei/transformers.rs b/crates/router/src/connector/nuvei/transformers.rs index d1d7122f49ef..209d1a7476f6 100644 --- a/crates/router/src/connector/nuvei/transformers.rs +++ b/crates/router/src/connector/nuvei/transformers.rs @@ -1598,15 +1598,18 @@ where .map_or(response.order_id.clone(), Some) // For paypal there will be no transaction_id, only order_id will be present .map(types::ResponseId::ConnectorTransactionId) .ok_or(errors::ConnectorError::MissingConnectorTransactionID)?, - redirection_data, - mandate_reference: response - .payment_option - .and_then(|po| po.user_payment_option_id) - .map(|id| types::MandateReference { - connector_mandate_id: Some(id), - payment_method_id: None, - mandate_metadata: None, - }), + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new( + response + .payment_option + .and_then(|po| po.user_payment_option_id) + .map(|id| types::MandateReference { + connector_mandate_id: Some(id), + payment_method_id: None, + mandate_metadata: None, + connector_mandate_request_reference_id: None, + }), + ), // we don't need to save session token for capture, void flow so ignoring if it is not present connector_metadata: if let Some(token) = response.session_token { Some( diff --git a/crates/router/src/connector/opayo/transformers.rs b/crates/router/src/connector/opayo/transformers.rs index 44069f3650b1..44445a3d7d94 100644 --- a/crates/router/src/connector/opayo/transformers.rs +++ b/crates/router/src/connector/opayo/transformers.rs @@ -144,8 +144,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( item.response.transaction_id.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.transaction_id), diff --git a/crates/router/src/connector/opennode/transformers.rs b/crates/router/src/connector/opennode/transformers.rs index 8f1579ac1ff4..1e8239d377bb 100644 --- a/crates/router/src/connector/opennode/transformers.rs +++ b/crates/router/src/connector/opennode/transformers.rs @@ -138,8 +138,8 @@ impl let response_data = if attempt_status != OpennodePaymentStatus::Underpaid { Ok(types::PaymentsResponseData::TransactionResponse { resource_id: connector_id, - redirection_data: Some(redirection_data), - mandate_reference: None, + redirection_data: Box::new(Some(redirection_data)), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: item.response.data.order_id, diff --git a/crates/router/src/connector/paybox.rs b/crates/router/src/connector/paybox.rs index a251679be85b..dd54e185dac3 100644 --- a/crates/router/src/connector/paybox.rs +++ b/crates/router/src/connector/paybox.rs @@ -11,7 +11,7 @@ use super::utils::{ }; use crate::{ configs::settings, - connector::utils, + connector::{utils, utils::PaymentMethodDataType}, core::{ errors::{self, CustomResult}, payments, @@ -60,6 +60,13 @@ impl api::PaymentsCompleteAuthorize for Paybox {} impl ConnectorIntegration for Paybox { + fn build_request( + &self, + _req: &types::PaymentsCancelRouterData, + _connectors: &settings::Connectors, + ) -> CustomResult, errors::ConnectorError> { + Err(errors::ConnectorError::NotImplemented("Cancel/Void flow".to_string()).into()) + } } impl @@ -151,6 +158,14 @@ impl ConnectorValidation for Paybox { ), } } + fn validate_mandate_payment( + &self, + pm_type: Option, + pm_data: types::domain::payments::PaymentMethodData, + ) -> CustomResult<(), errors::ConnectorError> { + let mandate_supported_pmd = std::collections::HashSet::from([PaymentMethodDataType::Card]); + connector_utils::is_mandate_supported(pm_data, pm_type, mandate_supported_pmd, self.id()) + } } impl ConnectorIntegration diff --git a/crates/router/src/connector/paybox/transformers.rs b/crates/router/src/connector/paybox/transformers.rs index d02f75693c48..4e1270f419c8 100644 --- a/crates/router/src/connector/paybox/transformers.rs +++ b/crates/router/src/connector/paybox/transformers.rs @@ -1,3 +1,4 @@ +use api_models::payments::AdditionalPaymentData; use bytes::Bytes; use common_utils::{ date_time::DateFormat, errors::CustomResult, ext_traits::ValueExt, types::MinorUnit, @@ -8,7 +9,7 @@ use hyperswitch_domain_models::{ router_data::ConnectorAuthType, router_response_types::RedirectForm, }; use hyperswitch_interfaces::consts; -use masking::{PeekInterface, Secret}; +use masking::{ExposeInterface, PeekInterface, Secret}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use crate::{ @@ -16,7 +17,7 @@ use crate::{ self, PaymentsAuthorizeRequestData, PaymentsCompleteAuthorizeRequestData, RouterData, }, core::errors, - types::{self, api, domain, storage::enums}, + types::{self, api, domain, storage::enums, MandateReference}, }; pub struct PayboxRouterData { @@ -42,6 +43,10 @@ const SUCCESS_CODE: &str = "00000"; const VERSION_PAYBOX: &str = "00104"; const PAY_ORIGIN_INTERNET: &str = "024"; const THREE_DS_FAIL_CODE: &str = "00000000"; +const RECURRING_ORIGIN: &str = "027"; +const MANDATE_REQUEST: &str = "00056"; +const MANDATE_AUTH_ONLY: &str = "00051"; +const MANDATE_AUTH_AND_CAPTURE_ONLY: &str = "00053"; type Error = error_stack::Report; @@ -50,6 +55,13 @@ type Error = error_stack::Report; pub enum PayboxPaymentsRequest { Card(PaymentsRequest), CardThreeDs(ThreeDSPaymentsRequest), + Mandate(MandatePaymentRequest), +} + +#[derive(Debug, Serialize)] +pub struct CardMandateInfo { + pub card_exp_month: Secret, + pub card_exp_year: Secret, } #[derive(Debug, Serialize)] @@ -99,6 +111,10 @@ pub struct PaymentsRequest { #[serde(rename = "ID3D")] #[serde(skip_serializing_if = "Option::is_none")] pub three_ds_data: Option>, + + #[serde(rename = "REFABONNE")] + #[serde(skip_serializing_if = "Option::is_none")] + pub customer_id: Option>, } #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "PascalCase")] @@ -367,8 +383,10 @@ impl TryFrom<&PayboxRouterData<&types::PaymentsAuthorizeRouterData>> for PayboxP let auth_data: PayboxAuthType = PayboxAuthType::try_from(&item.router_data.connector_auth_type) .change_context(errors::ConnectorError::FailedToObtainAuthType)?; - let transaction_type = - get_transaction_type(item.router_data.request.capture_method)?; + let transaction_type = get_transaction_type( + item.router_data.request.capture_method, + item.router_data.request.is_mandate_payment(), + )?; let currency = diesel_models::enums::Currency::iso_4217(&item.router_data.request.currency) .to_string(); @@ -420,18 +438,80 @@ impl TryFrom<&PayboxRouterData<&types::PaymentsAuthorizeRouterData>> for PayboxP rank: auth_data.rang, key: auth_data.cle, three_ds_data: None, + customer_id: match item.router_data.request.is_mandate_payment() { + true => { + let reference_id = item + .router_data + .connector_mandate_request_reference_id + .clone() + .ok_or_else(|| { + errors::ConnectorError::MissingRequiredField { + field_name: "connector_mandate_request_reference_id", + } + })?; + Some(Secret::new(reference_id)) + } + false => None, + }, })) } } + domain::PaymentMethodData::MandatePayment => { + let mandate_data = extract_card_mandate_info( + item.router_data + .request + .additional_payment_method_data + .clone(), + )?; + Ok(Self::Mandate(MandatePaymentRequest::try_from(( + item, + mandate_data, + ))?)) + } _ => Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()), } } } -fn get_transaction_type(capture_method: Option) -> Result { - match capture_method { - Some(enums::CaptureMethod::Automatic) | None => Ok(AUTH_AND_CAPTURE_REQUEST.to_string()), - Some(enums::CaptureMethod::Manual) => Ok(AUTH_REQUEST.to_string()), +fn extract_card_mandate_info( + additional_payment_method_data: Option, +) -> Result { + match additional_payment_method_data { + Some(AdditionalPaymentData::Card(card_data)) => Ok(CardMandateInfo { + card_exp_month: card_data.card_exp_month.clone().ok_or_else(|| { + errors::ConnectorError::MissingRequiredField { + field_name: "card_exp_month", + } + })?, + card_exp_year: card_data.card_exp_year.clone().ok_or_else(|| { + errors::ConnectorError::MissingRequiredField { + field_name: "card_exp_year", + } + })?, + }), + _ => Err(errors::ConnectorError::MissingRequiredFields { + field_names: vec!["card_exp_month", "card_exp_year"], + } + .into()), + } +} + +fn get_transaction_type( + capture_method: Option, + is_mandate_request: bool, +) -> Result { + match (capture_method, is_mandate_request) { + (Some(enums::CaptureMethod::Automatic), false) | (None, false) => { + Ok(AUTH_AND_CAPTURE_REQUEST.to_string()) + } + (Some(enums::CaptureMethod::Automatic), true) | (None, true) => { + Err(errors::ConnectorError::NotSupported { + message: "Capture Not allowed in case of Creating the Subscriber".to_string(), + connector: "Paybox", + })? + } + (Some(enums::CaptureMethod::Manual), false) => Ok(AUTH_REQUEST.to_string()), + (Some(enums::CaptureMethod::Manual), true) => Ok(MANDATE_REQUEST.to_string()), _ => Err(errors::ConnectorError::CaptureMethodNotSupported)?, } } @@ -499,6 +579,11 @@ pub struct TransactionResponse { #[serde(rename = "COMMENTAIRE")] pub response_message: String, + #[serde(rename = "PORTEUR")] + pub carrier_id: Option>, + + #[serde(rename = "REFABONNE")] + pub customer_id: Option>, } pub fn parse_url_encoded_to_struct( @@ -597,8 +682,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( response.paybox_order_id, ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: Some(serde_json::json!(PayboxMeta { connector_request_id: response.transaction_number.clone() })), @@ -657,8 +742,16 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( response.paybox_order_id, ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(response.carrier_id.as_ref().map( + |pm: &Secret| MandateReference { + connector_mandate_id: Some(pm.clone().expose()), + payment_method_id: None, + mandate_metadata: None, + connector_mandate_request_reference_id: + response.customer_id.map(|secret| secret.expose()), + }, + )), connector_metadata: Some(serde_json::json!(PayboxMeta { connector_request_id: response.transaction_number.clone() })), @@ -686,10 +779,10 @@ impl status: enums::AttemptStatus::AuthenticationPending, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::NoResponseId, - redirection_data: Some(RedirectForm::Html { + redirection_data: Box::new(Some(RedirectForm::Html { html_data: data.peek().to_string(), - }), - mandate_reference: None, + })), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -731,8 +824,8 @@ impl TryFrom resource_id: types::ResponseId::ConnectorTransactionId( response.paybox_order_id, ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(response.carrier_id.as_ref().map(|pm| { + MandateReference { + connector_mandate_id: Some(pm.clone().expose()), + payment_method_id: None, + mandate_metadata: None, + connector_mandate_request_reference_id: response + .customer_id + .map(|secret| secret.expose()), + } + })), connector_metadata: Some(serde_json::json!(PayboxMeta { connector_request_id: response.transaction_number.clone() })), @@ -973,8 +1075,10 @@ impl TryFrom<&PayboxRouterData<&types::PaymentsCompleteAuthorizeRouterData>> for let auth_data: PayboxAuthType = PayboxAuthType::try_from(&item.router_data.connector_auth_type) .change_context(errors::ConnectorError::FailedToObtainAuthType)?; - let transaction_type = - get_transaction_type(item.router_data.request.capture_method)?; + let transaction_type = get_transaction_type( + item.router_data.request.capture_method, + item.router_data.request.is_mandate_payment(), + )?; let currency = diesel_models::enums::Currency::iso_4217(&item.router_data.request.currency) .to_string(); @@ -1004,9 +1108,128 @@ impl TryFrom<&PayboxRouterData<&types::PaymentsCompleteAuthorizeRouterData>> for || Some(Secret::new(THREE_DS_FAIL_CODE.to_string())), |data| Some(data.clone()), ), + customer_id: match item.router_data.request.is_mandate_payment() { + true => Some(Secret::new(item.router_data.payment_id.clone())), + false => None, + }, }) } _ => Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()), } } } + +#[derive(Debug, Serialize)] +pub struct MandatePaymentRequest { + #[serde(rename = "DATEQ")] + pub date: String, + + #[serde(rename = "TYPE")] + pub transaction_type: String, + + #[serde(rename = "NUMQUESTION")] + pub paybox_request_number: String, + + #[serde(rename = "MONTANT")] + pub amount: MinorUnit, + + #[serde(rename = "REFERENCE")] + pub description_reference: String, + + #[serde(rename = "VERSION")] + pub version: String, + + #[serde(rename = "DEVISE")] + pub currency: String, + + #[serde(rename = "ACTIVITE")] + pub activity: String, + + #[serde(rename = "SITE")] + pub site: Secret, + + #[serde(rename = "RANG")] + pub rank: Secret, + + #[serde(rename = "CLE")] + pub key: Secret, + + #[serde(rename = "DATEVAL")] + pub cc_exp_date: Secret, + + #[serde(rename = "REFABONNE")] + pub customer_id: Secret, + + #[serde(rename = "PORTEUR")] + pub carrier_id: Secret, +} + +impl + TryFrom<( + &PayboxRouterData<&types::PaymentsAuthorizeRouterData>, + CardMandateInfo, + )> for MandatePaymentRequest +{ + type Error = error_stack::Report; + fn try_from( + (item, card_mandate_info): ( + &PayboxRouterData<&types::PaymentsAuthorizeRouterData>, + CardMandateInfo, + ), + ) -> Result { + let auth_data: PayboxAuthType = + PayboxAuthType::try_from(&item.router_data.connector_auth_type) + .change_context(errors::ConnectorError::FailedToObtainAuthType)?; + let transaction_type = match item.router_data.request.capture_method { + Some(enums::CaptureMethod::Automatic) | None => { + Ok(MANDATE_AUTH_AND_CAPTURE_ONLY.to_string()) + } + Some(enums::CaptureMethod::Manual) => Ok(MANDATE_AUTH_ONLY.to_string()), + _ => Err(errors::ConnectorError::CaptureMethodNotSupported), + }?; + let currency = diesel_models::enums::Currency::iso_4217(&item.router_data.request.currency) + .to_string(); + let format_time = common_utils::date_time::format_date( + common_utils::date_time::now(), + DateFormat::DDMMYYYYHHmmss, + ) + .change_context(errors::ConnectorError::RequestEncodingFailed)?; + Ok(Self { + date: format_time.clone(), + transaction_type, + paybox_request_number: get_paybox_request_number()?, + amount: item.router_data.request.minor_amount, + description_reference: item.router_data.connector_request_reference_id.clone(), + version: VERSION_PAYBOX.to_string(), + currency, + activity: RECURRING_ORIGIN.to_string(), + site: auth_data.site, + rank: auth_data.rang, + key: auth_data.cle, + customer_id: Secret::new( + item.router_data + .request + .get_connector_mandate_request_reference_id()?, + ), + carrier_id: Secret::new(item.router_data.request.get_connector_mandate_id()?), + cc_exp_date: get_card_expiry_month_year_2_digit( + card_mandate_info.card_exp_month.clone(), + card_mandate_info.card_exp_year.clone(), + )?, + }) + } +} + +fn get_card_expiry_month_year_2_digit( + card_exp_month: Secret, + card_exp_year: Secret, +) -> Result, errors::ConnectorError> { + Ok(Secret::new(format!( + "{}{}", + card_exp_month.peek(), + card_exp_year + .peek() + .get(card_exp_year.peek().len() - 2..) + .ok_or(errors::ConnectorError::RequestEncodingFailed)? + ))) +} diff --git a/crates/router/src/connector/payme/transformers.rs b/crates/router/src/connector/payme/transformers.rs index 4eac0a6f94d4..2f8b78e281ad 100644 --- a/crates/router/src/connector/payme/transformers.rs +++ b/crates/router/src/connector/payme/transformers.rs @@ -246,12 +246,15 @@ impl TryFrom<&PaymePaySaleResponse> for types::PaymentsResponseData { }; Ok(Self::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(value.payme_sale_id.clone()), - redirection_data, - mandate_reference: value.buyer_key.clone().map(|buyer_key| MandateReference { - connector_mandate_id: Some(buyer_key.expose()), - payment_method_id: None, - mandate_metadata: None, - }), + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(value.buyer_key.clone().map(|buyer_key| { + MandateReference { + connector_mandate_id: Some(buyer_key.expose()), + payment_method_id: None, + mandate_metadata: None, + connector_mandate_request_reference_id: None, + } + })), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -316,9 +319,9 @@ impl From<&SaleQuery> for types::PaymentsResponseData { fn from(value: &SaleQuery) -> Self { Self::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(value.sale_payme_id.clone()), - redirection_data: None, + redirection_data: Box::new(None), // mandate reference will be updated with webhooks only. That has been handled with PaymePaySaleResponse struct - mandate_reference: None, + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -536,8 +539,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( item.response.payme_sale_id.to_owned(), ), - redirection_data: Some(services::RedirectForm::Payme), - mandate_reference: None, + redirection_data: Box::new(Some(services::RedirectForm::Payme)), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -1110,8 +1113,8 @@ impl TryFrom> // Since we are not receiving payme_sale_id, we are not populating the transaction response Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::NoResponseId, - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, diff --git a/crates/router/src/connector/paypal.rs b/crates/router/src/connector/paypal.rs index 274aab8e5047..48a35c78cc25 100644 --- a/crates/router/src/connector/paypal.rs +++ b/crates/router/src/connector/paypal.rs @@ -5,7 +5,7 @@ use base64::Engine; use common_utils::{ ext_traits::ByteSliceExt, request::RequestContent, - types::{AmountConvertor, StringMajorUnit, StringMajorUnitForConnector}, + types::{AmountConvertor, MinorUnit, StringMajorUnit, StringMajorUnitForConnector}, }; use diesel_models::enums; use error_stack::ResultExt; @@ -17,7 +17,8 @@ use transformers as paypal; use self::transformers::{auth_headers, PaypalAuthResponse, PaypalMeta, PaypalWebhookEventType}; use super::utils::{ - ConnectorErrorType, PaymentsAuthorizeRequestData, PaymentsCompleteAuthorizeRequestData, + ConnectorErrorType, PaymentMethodDataType, PaymentsAuthorizeRequestData, + PaymentsCompleteAuthorizeRequestData, }; use crate::{ configs::settings, @@ -332,6 +333,18 @@ impl ConnectorValidation for Paypal { ), } } + fn validate_mandate_payment( + &self, + pm_type: Option, + pm_data: domain::PaymentMethodData, + ) -> CustomResult<(), errors::ConnectorError> { + let mandate_supported_pmd = std::collections::HashSet::from([ + PaymentMethodDataType::Card, + PaymentMethodDataType::PaypalRedirect, + PaymentMethodDataType::PaypalSdk, + ]); + connector_utils::is_mandate_supported(pm_data, pm_type, mandate_supported_pmd, self.id()) + } } impl @@ -484,7 +497,8 @@ impl ConnectorIntegration CustomResult { let order_amount = connector_utils::convert_amount( self.amount_converter, - req.request.amount, + req.request.order_amount, req.request.currency, )?; let amount = connector_utils::convert_amount( self.amount_converter, - req.request.net_amount, + req.request.amount, req.request.currency, )?; let order_tax_amount = connector_utils::convert_amount( @@ -823,8 +853,14 @@ impl req.request.order_tax_amount, req.request.currency, )?; + let shipping_cost = connector_utils::convert_amount( + self.amount_converter, + req.request.shipping_cost.unwrap_or(MinorUnit::zero()), + req.request.currency, + )?; let connector_router_data = paypal::PaypalRouterData::try_from(( amount, + Some(shipping_cost), Some(order_tax_amount), Some(order_amount), req, @@ -915,7 +951,13 @@ impl ConnectorIntegration { pub amount: StringMajorUnit, + pub shipping_cost: Option, pub order_tax_amount: Option, pub order_amount: Option, pub router_data: T, @@ -38,20 +40,23 @@ impl StringMajorUnit, Option, Option, + Option, T, )> for PaypalRouterData { type Error = error_stack::Report; fn try_from( - (amount, order_tax_amount, order_amount, item): ( + (amount, shipping_cost, order_tax_amount, order_amount, item): ( StringMajorUnit, Option, Option, + Option, T, ), ) -> Result { Ok(Self { amount, + shipping_cost, order_tax_amount, order_amount, router_data: item, @@ -107,24 +112,47 @@ impl From<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for OrderReque value: item.amount.clone(), }, tax_total: None, + shipping: Some(OrderAmount { + currency_code: item.router_data.request.currency, + value: item + .shipping_cost + .clone() + .unwrap_or(StringMajorUnit::zero()), + }), }, } } } -impl From<&PaypalRouterData<&types::PaymentsPostSessionTokensRouterData>> for OrderRequestAmount { - fn from(item: &PaypalRouterData<&types::PaymentsPostSessionTokensRouterData>) -> Self { - Self { +impl TryFrom<&PaypalRouterData<&types::PaymentsPostSessionTokensRouterData>> + for OrderRequestAmount +{ + type Error = error_stack::Report; + fn try_from( + item: &PaypalRouterData<&types::PaymentsPostSessionTokensRouterData>, + ) -> Result { + Ok(Self { currency_code: item.router_data.request.currency, value: item.amount.clone(), breakdown: AmountBreakdown { item_total: OrderAmount { currency_code: item.router_data.request.currency, - value: item.amount.clone(), + value: item.order_amount.clone().ok_or( + errors::ConnectorError::MissingRequiredField { + field_name: "order_amount", + }, + )?, }, tax_total: None, + shipping: Some(OrderAmount { + currency_code: item.router_data.request.currency, + value: item + .shipping_cost + .clone() + .unwrap_or(StringMajorUnit::zero()), + }), }, - } + }) } } @@ -153,6 +181,13 @@ impl TryFrom<&PaypalRouterData<&types::SdkSessionUpdateRouterData>> for OrderReq }, )?, }), + shipping: Some(OrderAmount { + currency_code: item.router_data.request.currency, + value: item + .shipping_cost + .clone() + .unwrap_or(StringMajorUnit::zero()), + }), }, }) } @@ -162,6 +197,7 @@ impl TryFrom<&PaypalRouterData<&types::SdkSessionUpdateRouterData>> for OrderReq pub struct AmountBreakdown { item_total: OrderAmount, tax_total: Option, + shipping: Option, } #[derive(Default, Debug, Serialize, Eq, PartialEq)] @@ -206,9 +242,12 @@ impl From<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for ItemDetail } } -impl From<&PaypalRouterData<&types::PaymentsPostSessionTokensRouterData>> for ItemDetails { - fn from(item: &PaypalRouterData<&types::PaymentsPostSessionTokensRouterData>) -> Self { - Self { +impl TryFrom<&PaypalRouterData<&types::PaymentsPostSessionTokensRouterData>> for ItemDetails { + type Error = error_stack::Report; + fn try_from( + item: &PaypalRouterData<&types::PaymentsPostSessionTokensRouterData>, + ) -> Result { + Ok(Self { name: format!( "Payment for invoice {}", item.router_data.connector_request_reference_id @@ -216,10 +255,14 @@ impl From<&PaypalRouterData<&types::PaymentsPostSessionTokensRouterData>> for It quantity: ORDER_QUANTITY, unit_amount: OrderAmount { currency_code: item.router_data.request.currency, - value: item.amount.clone(), + value: item.order_amount.clone().ok_or( + errors::ConnectorError::MissingRequiredField { + field_name: "order_amount", + }, + )?, }, tax: None, - } + }) } } @@ -254,7 +297,7 @@ impl TryFrom<&PaypalRouterData<&types::SdkSessionUpdateRouterData>> for ItemDeta } } -#[derive(Default, Debug, Serialize, Eq, PartialEq)] +#[derive(Default, Debug, Serialize, Eq, PartialEq, Deserialize)] pub struct Address { address_line_1: Option>, postal_code: Option>, @@ -338,18 +381,30 @@ pub struct ShippingName { } #[derive(Debug, Serialize)] -pub struct CardRequest { +pub struct CardRequestStruct { billing_address: Option
, expiry: Option>, - name: Secret, + name: Option>, number: Option, security_code: Option>, - attributes: Option, + attributes: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct VaultStruct { + vault_id: Secret, } #[derive(Debug, Serialize)] -pub struct ThreeDsSetting { - verification: ThreeDsMethod, +#[serde(untagged)] +pub enum CardRequest { + CardRequestStruct(CardRequestStruct), + CardVaultStruct(VaultStruct), +} +#[derive(Debug, Serialize)] +pub struct CardRequestAttributes { + vault: Option, + verification: Option, } #[derive(Debug, Serialize)] @@ -393,8 +448,55 @@ pub enum ShippingPreference { } #[derive(Debug, Serialize)] -pub struct PaypalRedirectionRequest { +#[serde(untagged)] +pub enum PaypalRedirectionRequest { + PaypalRedirectionStruct(PaypalRedirectionStruct), + PaypalVaultStruct(VaultStruct), +} + +#[derive(Debug, Serialize)] +pub struct PaypalRedirectionStruct { experience_context: ContextStruct, + attributes: Option, +} +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct Attributes { + vault: PaypalVault, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct PaypalRedirectionResponse { + attributes: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct AttributeResponse { + vault: PaypalVaultResponse, +} +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct PaypalVault { + store_in_vault: StoreInVault, + usage_type: UsageType, +} +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct PaypalVaultResponse { + id: String, + status: String, + customer: CustomerId, +} +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct CustomerId { + id: String, +} +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum StoreInVault { + OnSuccess, +} +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum UsageType { + Merchant, } #[derive(Debug, Serialize)] @@ -407,6 +509,16 @@ pub enum PaymentSourceItem { Giropay(RedirectRequest), Sofort(RedirectRequest), } +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct CardVaultResponse { + attributes: Option, +} +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "lowercase")] +pub enum PaymentSourceItemResponse { + Card(CardVaultResponse), + Paypal(PaypalRedirectionResponse), +} #[derive(Debug, Serialize)] pub struct PaypalPaymentsRequest { @@ -549,12 +661,12 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsPostSessionTokensRouterData>> PaypalAuthType::try_from(&item.router_data.connector_auth_type)?; let payee = get_payee(&paypal_auth); - let amount = OrderRequestAmount::from(item); + let amount = OrderRequestAmount::try_from(item)?; let connector_request_reference_id = item.router_data.connector_request_reference_id.clone(); let shipping_address = ShippingAddress::from(item); - let item_details = vec![ItemDetails::from(item)]; + let item_details = vec![ItemDetails::try_from(item)?]; let purchase_units = vec![PurchaseUnitRequest { reference_id: Some(connector_request_reference_id.clone()), @@ -565,14 +677,28 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsPostSessionTokensRouterData>> shipping: Some(shipping_address), items: item_details, }]; - let payment_source = Some(PaymentSourceItem::Paypal(PaypalRedirectionRequest { - experience_context: ContextStruct { - return_url: None, - cancel_url: None, - shipping_preference: ShippingPreference::GetFromFile, - user_action: Some(UserAction::PayNow), - }, - })); + let payment_source = Some(PaymentSourceItem::Paypal( + PaypalRedirectionRequest::PaypalRedirectionStruct(PaypalRedirectionStruct { + experience_context: ContextStruct { + return_url: item.router_data.request.router_return_url.clone(), + cancel_url: item.router_data.request.router_return_url.clone(), + shipping_preference: ShippingPreference::GetFromFile, + user_action: Some(UserAction::PayNow), + }, + attributes: match item.router_data.request.setup_future_usage { + Some(setup_future_usage) => match setup_future_usage { + enums::FutureUsage::OffSession => Some(Attributes { + vault: PaypalVault { + store_in_vault: StoreInVault::OnSuccess, + usage_type: UsageType::Merchant, + }, + }), + enums::FutureUsage::OnSession => None, + }, + None => None, + }, + }), + )); Ok(Self { intent, @@ -653,26 +779,36 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP let card = item.router_data.request.get_card()?; let expiry = Some(card.get_expiry_date_as_yyyymm("-")); - let attributes = match item.router_data.auth_type { - enums::AuthenticationType::ThreeDs => Some(ThreeDsSetting { - verification: ThreeDsMethod { - method: ThreeDsType::ScaAlways, - }, + let verification = match item.router_data.auth_type { + enums::AuthenticationType::ThreeDs => Some(ThreeDsMethod { + method: ThreeDsType::ScaAlways, }), enums::AuthenticationType::NoThreeDs => None, }; - let payment_source = Some(PaymentSourceItem::Card(CardRequest { - billing_address: get_address_info(item.router_data.get_optional_billing()), - expiry, - name: item - .router_data - .get_optional_billing_full_name() - .unwrap_or(Secret::new("".to_string())), - number: Some(ccard.card_number.clone()), - security_code: Some(ccard.card_cvc.clone()), - attributes, - })); + let payment_source = Some(PaymentSourceItem::Card(CardRequest::CardRequestStruct( + CardRequestStruct { + billing_address: get_address_info(item.router_data.get_optional_billing()), + expiry, + name: item.router_data.get_optional_billing_full_name(), + number: Some(ccard.card_number.clone()), + security_code: Some(ccard.card_cvc.clone()), + attributes: Some(CardRequestAttributes { + vault: match item.router_data.request.setup_future_usage { + Some(setup_future_usage) => match setup_future_usage { + enums::FutureUsage::OffSession => Some(PaypalVault { + store_in_vault: StoreInVault::OnSuccess, + usage_type: UsageType::Merchant, + }), + + enums::FutureUsage::OnSession => None, + }, + None => None, + }, + verification, + }), + }, + ))); Ok(Self { intent, @@ -682,23 +818,46 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP } domain::PaymentMethodData::Wallet(ref wallet_data) => match wallet_data { domain::WalletData::PaypalRedirect(_) => { - let payment_source = - Some(PaymentSourceItem::Paypal(PaypalRedirectionRequest { - experience_context: ContextStruct { - return_url: item.router_data.request.complete_authorize_url.clone(), - cancel_url: item.router_data.request.complete_authorize_url.clone(), - shipping_preference: if item - .router_data - .get_optional_shipping_country() - .is_some() - { - ShippingPreference::SetProvidedAddress - } else { - ShippingPreference::GetFromFile + let payment_source = Some(PaymentSourceItem::Paypal( + PaypalRedirectionRequest::PaypalRedirectionStruct( + PaypalRedirectionStruct { + experience_context: ContextStruct { + return_url: item + .router_data + .request + .complete_authorize_url + .clone(), + cancel_url: item + .router_data + .request + .complete_authorize_url + .clone(), + shipping_preference: if item + .router_data + .get_optional_shipping() + .is_some() + { + ShippingPreference::SetProvidedAddress + } else { + ShippingPreference::GetFromFile + }, + user_action: Some(UserAction::PayNow), + }, + attributes: match item.router_data.request.setup_future_usage { + Some(setup_future_usage) => match setup_future_usage { + enums::FutureUsage::OffSession => Some(Attributes { + vault: PaypalVault { + store_in_vault: StoreInVault::OnSuccess, + usage_type: UsageType::Merchant, + }, + }), + enums::FutureUsage::OnSession => None, + }, + None => None, }, - user_action: Some(UserAction::PayNow), }, - })); + ), + )); Ok(Self { intent, @@ -707,15 +866,30 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP }) } domain::WalletData::PaypalSdk(_) => { - let payment_source = - Some(PaymentSourceItem::Paypal(PaypalRedirectionRequest { - experience_context: ContextStruct { - return_url: None, - cancel_url: None, - shipping_preference: ShippingPreference::GetFromFile, - user_action: Some(UserAction::PayNow), + let payment_source = Some(PaymentSourceItem::Paypal( + PaypalRedirectionRequest::PaypalRedirectionStruct( + PaypalRedirectionStruct { + experience_context: ContextStruct { + return_url: None, + cancel_url: None, + shipping_preference: ShippingPreference::GetFromFile, + user_action: Some(UserAction::PayNow), + }, + attributes: match item.router_data.request.setup_future_usage { + Some(setup_future_usage) => match setup_future_usage { + enums::FutureUsage::OffSession => Some(Attributes { + vault: PaypalVault { + store_in_vault: StoreInVault::OnSuccess, + usage_type: UsageType::Merchant, + }, + }), + enums::FutureUsage::OnSession => None, + }, + None => None, + }, }, - })); + ), + )); Ok(Self { intent, @@ -786,10 +960,132 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP Self::try_from(giftcard_data.as_ref()) } domain::PaymentMethodData::MandatePayment => { - Err(errors::ConnectorError::NotImplemented( - utils::get_unimplemented_payment_method_error_message("Paypal"), - ) - .into()) + let payment_method_type = item + .router_data + .get_recurring_mandate_payment_data()? + .payment_method_type + .ok_or_else(missing_field_err("payment_method_type"))?; + + let connector_mandate_id = item.router_data.request.connector_mandate_id().ok_or( + errors::ConnectorError::MissingRequiredField { + field_name: "connector_mandate_id", + }, + )?; + + let payment_source = match payment_method_type { + enums::PaymentMethodType::Credit => Ok(Some(PaymentSourceItem::Card( + CardRequest::CardVaultStruct(VaultStruct { + vault_id: connector_mandate_id.into(), + }), + ))), + enums::PaymentMethodType::Paypal => Ok(Some(PaymentSourceItem::Paypal( + PaypalRedirectionRequest::PaypalVaultStruct(VaultStruct { + vault_id: connector_mandate_id.into(), + }), + ))), + enums::PaymentMethodType::Ach + | enums::PaymentMethodType::Affirm + | enums::PaymentMethodType::AfterpayClearpay + | enums::PaymentMethodType::Alfamart + | enums::PaymentMethodType::AliPay + | enums::PaymentMethodType::AliPayHk + | enums::PaymentMethodType::Alma + | enums::PaymentMethodType::ApplePay + | enums::PaymentMethodType::Atome + | enums::PaymentMethodType::Bacs + | enums::PaymentMethodType::BancontactCard + | enums::PaymentMethodType::Becs + | enums::PaymentMethodType::Benefit + | enums::PaymentMethodType::Bizum + | enums::PaymentMethodType::Blik + | enums::PaymentMethodType::Boleto + | enums::PaymentMethodType::BcaBankTransfer + | enums::PaymentMethodType::BniVa + | enums::PaymentMethodType::BriVa + | enums::PaymentMethodType::CardRedirect + | enums::PaymentMethodType::CimbVa + | enums::PaymentMethodType::ClassicReward + | enums::PaymentMethodType::CryptoCurrency + | enums::PaymentMethodType::Cashapp + | enums::PaymentMethodType::Dana + | enums::PaymentMethodType::DanamonVa + | enums::PaymentMethodType::Debit + | enums::PaymentMethodType::DuitNow + | enums::PaymentMethodType::Efecty + | enums::PaymentMethodType::Eps + | enums::PaymentMethodType::Fps + | enums::PaymentMethodType::Evoucher + | enums::PaymentMethodType::Giropay + | enums::PaymentMethodType::Givex + | enums::PaymentMethodType::GooglePay + | enums::PaymentMethodType::GoPay + | enums::PaymentMethodType::Gcash + | enums::PaymentMethodType::Ideal + | enums::PaymentMethodType::Interac + | enums::PaymentMethodType::Indomaret + | enums::PaymentMethodType::Klarna + | enums::PaymentMethodType::KakaoPay + | enums::PaymentMethodType::LocalBankRedirect + | enums::PaymentMethodType::MandiriVa + | enums::PaymentMethodType::Knet + | enums::PaymentMethodType::MbWay + | enums::PaymentMethodType::MobilePay + | enums::PaymentMethodType::Momo + | enums::PaymentMethodType::MomoAtm + | enums::PaymentMethodType::Multibanco + | enums::PaymentMethodType::OnlineBankingThailand + | enums::PaymentMethodType::OnlineBankingCzechRepublic + | enums::PaymentMethodType::OnlineBankingFinland + | enums::PaymentMethodType::OnlineBankingFpx + | enums::PaymentMethodType::OnlineBankingPoland + | enums::PaymentMethodType::OnlineBankingSlovakia + | enums::PaymentMethodType::OpenBankingPIS + | enums::PaymentMethodType::Oxxo + | enums::PaymentMethodType::PagoEfectivo + | enums::PaymentMethodType::PermataBankTransfer + | enums::PaymentMethodType::OpenBankingUk + | enums::PaymentMethodType::PayBright + | enums::PaymentMethodType::Pix + | enums::PaymentMethodType::PaySafeCard + | enums::PaymentMethodType::Przelewy24 + | enums::PaymentMethodType::PromptPay + | enums::PaymentMethodType::Pse + | enums::PaymentMethodType::RedCompra + | enums::PaymentMethodType::RedPagos + | enums::PaymentMethodType::SamsungPay + | enums::PaymentMethodType::Sepa + | enums::PaymentMethodType::Sofort + | enums::PaymentMethodType::Swish + | enums::PaymentMethodType::TouchNGo + | enums::PaymentMethodType::Trustly + | enums::PaymentMethodType::Twint + | enums::PaymentMethodType::UpiCollect + | enums::PaymentMethodType::UpiIntent + | enums::PaymentMethodType::Vipps + | enums::PaymentMethodType::VietQr + | enums::PaymentMethodType::Venmo + | enums::PaymentMethodType::Walley + | enums::PaymentMethodType::WeChatPay + | enums::PaymentMethodType::SevenEleven + | enums::PaymentMethodType::Lawson + | enums::PaymentMethodType::MiniStop + | enums::PaymentMethodType::FamilyMart + | enums::PaymentMethodType::Seicomart + | enums::PaymentMethodType::PayEasy + | enums::PaymentMethodType::LocalBankTransfer + | enums::PaymentMethodType::Mifinity + | enums::PaymentMethodType::Paze => { + Err(errors::ConnectorError::NotImplemented( + utils::get_unimplemented_payment_method_error_message("paypal"), + )) + } + }; + + Ok(Self { + intent, + purchase_units, + payment_source: payment_source?, + }) } domain::PaymentMethodData::Reward | domain::PaymentMethodData::RealTimePayment(_) @@ -1215,6 +1511,7 @@ pub struct PaypalOrdersResponse { intent: PaypalPaymentIntent, status: PaypalOrderStatus, purchase_units: Vec, + payment_source: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -1235,6 +1532,7 @@ pub struct PaypalRedirectResponse { status: PaypalOrderStatus, purchase_units: Vec, links: Vec, + payment_source: Option, } // Note: Don't change order of deserialization of variant, priority is in descending order @@ -1388,8 +1686,23 @@ impl status, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: order_id, - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(Some(MandateReference { + connector_mandate_id: match item.response.payment_source.clone() { + Some(paypal_source) => match paypal_source { + PaymentSourceItemResponse::Paypal(paypal_source) => { + paypal_source.attributes.map(|attr| attr.vault.id) + } + PaymentSourceItemResponse::Card(card) => { + card.attributes.map(|attr| attr.vault.id) + } + }, + None => None, + }, + payment_method_id: None, + mandate_metadata: None, + connector_mandate_request_reference_id: None, + })), connector_metadata: Some(connector_meta), network_txn_id: None, connector_response_reference_id: purchase_units @@ -1511,11 +1824,11 @@ impl status, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id.clone()), - redirection_data: Some(services::RedirectForm::from(( + redirection_data: Box::new(Some(services::RedirectForm::from(( link.ok_or(errors::ConnectorError::ResponseDeserializationFailed)?, services::Method::Get, - ))), - mandate_reference: None, + )))), + mandate_reference: Box::new(None), connector_metadata: Some(connector_meta), network_txn_id: None, connector_response_reference_id: Some( @@ -1566,11 +1879,11 @@ impl status, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id.clone()), - redirection_data: Some(services::RedirectForm::from(( + redirection_data: Box::new(Some(services::RedirectForm::from(( link.ok_or(errors::ConnectorError::ResponseDeserializationFailed)?, services::Method::Get, - ))), - mandate_reference: None, + )))), + mandate_reference: Box::new(None), connector_metadata: Some(connector_meta), network_txn_id: None, connector_response_reference_id: Some( @@ -1624,8 +1937,8 @@ impl status, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::NoResponseId, - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: Some(connector_meta), network_txn_id: None, connector_response_reference_id: None, @@ -1662,8 +1975,8 @@ impl status: storage_enums::AttemptStatus::AuthenticationPending, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -1712,11 +2025,11 @@ impl status, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), - redirection_data: Some(paypal_threeds_link(( + redirection_data: Box::new(Some(paypal_threeds_link(( link, item.data.request.complete_authorize_url.clone(), - ))?), - mandate_reference: None, + ))?)), + mandate_reference: Box::new(None), connector_metadata: Some(connector_meta), network_txn_id: None, connector_response_reference_id: None, @@ -1780,8 +2093,8 @@ impl .order_id .clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: item @@ -2052,6 +2365,7 @@ pub struct PaypalCaptureResponse { amount: Option, invoice_id: Option, final_capture: bool, + payment_source: Option, } impl From for storage_enums::AttemptStatus { @@ -2115,8 +2429,8 @@ impl TryFrom> resource_id: types::ResponseId::ConnectorTransactionId( item.data.request.connector_transaction_id.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: Some(serde_json::json!(PaypalMeta { authorize_id: connector_payment_id.authorize_id, capture_id: Some(item.response.id.clone()), @@ -2173,8 +2487,8 @@ impl status, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id.clone()), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: item @@ -2605,6 +2919,7 @@ impl TryFrom<(PaypalRedirectsWebhooks, PaypalWebhookEventType)> for PaypalOrders intent: webhook_body.intent, status: PaypalOrderStatus::try_from(webhook_event)?, purchase_units: webhook_body.purchase_units, + payment_source: None, }) } } diff --git a/crates/router/src/connector/placetopay/transformers.rs b/crates/router/src/connector/placetopay/transformers.rs index 32d651787b69..2d1ce4771cad 100644 --- a/crates/router/src/connector/placetopay/transformers.rs +++ b/crates/router/src/connector/placetopay/transformers.rs @@ -263,8 +263,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( item.response.internal_reference.to_string(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: item .response .authorization diff --git a/crates/router/src/connector/plaid/transformers.rs b/crates/router/src/connector/plaid/transformers.rs index f0cf91b9cf6f..29d4db1297f8 100644 --- a/crates/router/src/connector/plaid/transformers.rs +++ b/crates/router/src/connector/plaid/transformers.rs @@ -308,8 +308,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( item.response.payment_id.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.payment_id), @@ -394,8 +394,8 @@ impl TryFrom status: enums::AttemptStatus::AuthenticationPending, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::NoResponseId, - redirection_data, - mandate_reference: None, + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -401,8 +401,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( item.response.transaction_id, ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata, network_txn_id: None, connector_response_reference_id: None, @@ -452,8 +452,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( item.response.transaction_id, ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -503,8 +503,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( item.response.transaction_id, ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, diff --git a/crates/router/src/connector/rapyd.rs b/crates/router/src/connector/rapyd.rs index da10513b3d3b..196eb4ce73dd 100644 --- a/crates/router/src/connector/rapyd.rs +++ b/crates/router/src/connector/rapyd.rs @@ -1,11 +1,11 @@ pub mod transformers; -use std::fmt::Debug; use base64::Engine; use common_utils::{ date_time, ext_traits::{Encode, StringExt}, request::RequestContent, + types::{AmountConvertor, MinorUnit, MinorUnitForConnector}, }; use diesel_models::enums; use error_stack::{Report, ResultExt}; @@ -17,6 +17,7 @@ use transformers as rapyd; use super::utils as connector_utils; use crate::{ configs::settings, + connector::utils::convert_amount, consts, core::errors::{self, CustomResult}, events::connector_api_logs::ConnectorEvent, @@ -34,9 +35,17 @@ use crate::{ utils::{self, crypto, ByteSliceExt, BytesExt}, }; -#[derive(Debug, Clone)] -pub struct Rapyd; - +#[derive(Clone)] +pub struct Rapyd { + amount_converter: &'static (dyn AmountConvertor + Sync), +} +impl Rapyd { + pub fn new() -> &'static Self { + &Self { + amount_converter: &MinorUnitForConnector, + } + } +} impl Rapyd { pub fn generate_signature( &self, @@ -198,12 +207,12 @@ impl req: &types::PaymentsAuthorizeRouterData, _connectors: &settings::Connectors, ) -> CustomResult { - let connector_router_data = rapyd::RapydRouterData::try_from(( - &self.get_currency_unit(), + let amount = convert_amount( + self.amount_converter, + req.request.minor_amount, req.request.currency, - req.request.amount, - req, - ))?; + )?; + let connector_router_data = rapyd::RapydRouterData::from((amount, req)); let connector_req = rapyd::RapydPaymentsRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -528,12 +537,12 @@ impl req: &types::PaymentsCaptureRouterData, _connectors: &settings::Connectors, ) -> CustomResult { - let connector_router_data = rapyd::RapydRouterData::try_from(( - &self.get_currency_unit(), + let amount = convert_amount( + self.amount_converter, + req.request.minor_amount_to_capture, req.request.currency, - req.request.amount_to_capture, - req, - ))?; + )?; + let connector_router_data = rapyd::RapydRouterData::from((amount, req)); let connector_req = rapyd::CaptureRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -668,12 +677,12 @@ impl services::ConnectorIntegration, _connectors: &settings::Connectors, ) -> CustomResult { - let connector_router_data = rapyd::RapydRouterData::try_from(( - &self.get_currency_unit(), + let amount = convert_amount( + self.amount_converter, + req.request.minor_refund_amount, req.request.currency, - req.request.refund_amount, - req, - ))?; + )?; + let connector_router_data = rapyd::RapydRouterData::from((amount, req)); let connector_req = rapyd::RapydRefundRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) diff --git a/crates/router/src/connector/rapyd/transformers.rs b/crates/router/src/connector/rapyd/transformers.rs index 044a64b413cf..b83ffcec4124 100644 --- a/crates/router/src/connector/rapyd/transformers.rs +++ b/crates/router/src/connector/rapyd/transformers.rs @@ -1,3 +1,4 @@ +use common_utils::types::MinorUnit; use error_stack::ResultExt; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; @@ -15,28 +16,26 @@ use crate::{ #[derive(Debug, Serialize)] pub struct RapydRouterData { - pub amount: i64, + pub amount: MinorUnit, pub router_data: T, } -impl TryFrom<(&api::CurrencyUnit, enums::Currency, i64, T)> for RapydRouterData { - type Error = error_stack::Report; - fn try_from( - (_currency_unit, _currency, amount, item): (&api::CurrencyUnit, enums::Currency, i64, T), - ) -> Result { - Ok(Self { +impl From<(MinorUnit, T)> for RapydRouterData { + fn from((amount, router_data): (MinorUnit, T)) -> Self { + Self { amount, - router_data: item, - }) + router_data, + } } } #[derive(Default, Debug, Serialize)] pub struct RapydPaymentsRequest { - pub amount: i64, + pub amount: MinorUnit, pub currency: enums::Currency, pub payment_method: PaymentMethod, pub payment_method_options: Option, + pub merchant_reference_id: Option, pub capture: Option, pub description: Option, pub complete_payment_url: Option, @@ -162,6 +161,7 @@ impl TryFrom<&RapydRouterData<&types::PaymentsAuthorizeRouterData>> for RapydPay payment_method, capture, payment_method_options, + merchant_reference_id: Some(item.router_data.connector_request_reference_id.clone()), description: None, error_payment_url: Some(return_url.clone()), complete_payment_url: Some(return_url), @@ -274,6 +274,7 @@ pub struct ResponseData { pub country_code: Option, pub captured: Option, pub transaction_id: String, + pub merchant_reference_id: Option, pub paid: Option, pub failure_code: Option, pub failure_message: Option, @@ -299,7 +300,7 @@ pub struct DisputeResponseData { #[derive(Default, Debug, Serialize)] pub struct RapydRefundRequest { pub payment: String, - pub amount: Option, + pub amount: Option, pub currency: Option, } @@ -406,7 +407,7 @@ impl TryFrom> #[derive(Debug, Serialize, Clone)] pub struct CaptureRequest { - amount: Option, + amount: Option, receipt_email: Option>, statement_descriptor: Option, } @@ -474,11 +475,13 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( data.id.to_owned(), ), //transaction_id is also the field but this id is used to initiate a refund - redirection_data, - mandate_reference: None, + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, - connector_response_reference_id: None, + connector_response_reference_id: data + .merchant_reference_id + .to_owned(), incremental_authorization_allowed: None, charge_id: None, }), diff --git a/crates/router/src/connector/riskified/transformers/api.rs b/crates/router/src/connector/riskified/transformers/api.rs index 2e0ac3b00473..d2d38855dafc 100644 --- a/crates/router/src/connector/riskified/transformers/api.rs +++ b/crates/router/src/connector/riskified/transformers/api.rs @@ -163,7 +163,7 @@ impl TryFrom<&frm_types::FrmCheckoutRouterData> for RiskifiedPaymentsCheckoutReq .get_order_details()? .iter() .map(|order_detail| LineItem { - price: order_detail.amount, + price: order_detail.amount.get_amount_as_i64(), // This should be changed to MinorUnit when we implement amount conversion for this connector. Additionally, the function get_amount_as_i64() should be avoided in the future. quantity: i32::from(order_detail.quantity), title: order_detail.product_name.clone(), product_type: order_detail.product_type.clone(), diff --git a/crates/router/src/connector/signifyd/transformers/api.rs b/crates/router/src/connector/signifyd/transformers/api.rs index 6aeda8f8d470..eed0e9937b25 100644 --- a/crates/router/src/connector/signifyd/transformers/api.rs +++ b/crates/router/src/connector/signifyd/transformers/api.rs @@ -145,7 +145,7 @@ impl TryFrom<&frm_types::FrmSaleRouterData> for SignifydPaymentsSaleRequest { .iter() .map(|order_detail| Products { item_name: order_detail.product_name.clone(), - item_price: order_detail.amount, + item_price: order_detail.amount.get_amount_as_i64(), // This should be changed to MinorUnit when we implement amount conversion for this connector. Additionally, the function get_amount_as_i64() should be avoided in the future. item_quantity: i32::from(order_detail.quantity), item_id: order_detail.product_id.clone(), item_category: order_detail.category.clone(), @@ -382,7 +382,7 @@ impl TryFrom<&frm_types::FrmCheckoutRouterData> for SignifydPaymentsCheckoutRequ .iter() .map(|order_detail| Products { item_name: order_detail.product_name.clone(), - item_price: order_detail.amount, + item_price: order_detail.amount.get_amount_as_i64(), // This should be changed to MinorUnit when we implement amount conversion for this connector. Additionally, the function get_amount_as_i64() should be avoided in the future. item_quantity: i32::from(order_detail.quantity), item_id: order_detail.product_id.clone(), item_category: order_detail.category.clone(), diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 63720696ef4b..af82bda3e6af 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -1709,7 +1709,7 @@ impl TryFrom<(&types::PaymentsAuthorizeRouterData, MinorUnit)> for PaymentIntent connector_mandate_ids, )) => ( None, - connector_mandate_ids.connector_mandate_id, + connector_mandate_ids.get_connector_mandate_id(), StripeBillingAddress::default(), get_payment_method_type_for_saved_payment_method_payment(item)?, ), @@ -2450,6 +2450,7 @@ impl connector_mandate_id, payment_method_id, mandate_metadata: None, + connector_mandate_request_reference_id: None, } }); @@ -2490,8 +2491,8 @@ impl }); Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id.clone()), - redirection_data, - mandate_reference, + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(mandate_reference), connector_metadata, network_txn_id, connector_response_reference_id: Some(item.response.id), @@ -2655,6 +2656,7 @@ impl connector_mandate_id, payment_method_id: Some(payment_method_id), mandate_metadata: None, + connector_mandate_request_reference_id: None, } }); @@ -2697,8 +2699,8 @@ impl }); Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id.clone()), - redirection_data, - mandate_reference, + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(mandate_reference), connector_metadata, network_txn_id: network_transaction_id, connector_response_reference_id: Some(item.response.id.clone()), @@ -2746,6 +2748,7 @@ impl connector_mandate_id, payment_method_id, mandate_metadata: None, + connector_mandate_request_reference_id: None, } }); let status = enums::AttemptStatus::from(item.response.status); @@ -2776,8 +2779,8 @@ impl Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id.clone()), - redirection_data, - mandate_reference, + redirection_data: Box::new(redirection_data), + mandate_reference: Box::new(mandate_reference), connector_metadata: None, network_txn_id: network_transaction_id, connector_response_reference_id: Some(item.response.id), @@ -3270,7 +3273,7 @@ pub struct MitExemption { #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[serde(untagged)] pub enum LatestAttempt { - PaymentIntentAttempt(LatestPaymentAttempt), + PaymentIntentAttempt(Box), SetupAttempt(String), } #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] @@ -3480,8 +3483,8 @@ impl TryFrom { - connector_mandate_ids.connector_mandate_id.clone() + connector_mandate_ids.get_connector_mandate_id() } Some(payments::MandateReferenceId::NetworkMandateId(_)) | None @@ -725,6 +725,7 @@ impl PaymentsPreProcessingData for types::PaymentsPreProcessingData { pub trait PaymentsCaptureRequestData { fn is_multiple_capture(&self) -> bool; fn get_browser_info(&self) -> Result; + fn get_capture_method(&self) -> Option; } impl PaymentsCaptureRequestData for types::PaymentsCaptureData { @@ -736,6 +737,9 @@ impl PaymentsCaptureRequestData for types::PaymentsCaptureData { .clone() .ok_or_else(missing_field_err("browser_info")) } + fn get_capture_method(&self) -> Option { + self.capture_method.to_owned() + } } pub trait RevokeMandateRequestData { @@ -795,6 +799,7 @@ pub trait PaymentsAuthorizeRequestData { fn get_total_surcharge_amount(&self) -> Option; fn get_metadata_as_object(&self) -> Option; fn get_authentication_data(&self) -> Result; + fn get_connector_mandate_request_reference_id(&self) -> Result; } pub trait PaymentMethodTokenizationRequestData { @@ -857,7 +862,7 @@ impl PaymentsAuthorizeRequestData for types::PaymentsAuthorizeData { .as_ref() .and_then(|mandate_ids| match &mandate_ids.mandate_reference_id { Some(payments::MandateReferenceId::ConnectorMandateId(connector_mandate_ids)) => { - connector_mandate_ids.connector_mandate_id.clone() + connector_mandate_ids.get_connector_mandate_id() } Some(payments::MandateReferenceId::NetworkMandateId(_)) | None @@ -975,6 +980,21 @@ impl PaymentsAuthorizeRequestData for types::PaymentsAuthorizeData { .clone() .ok_or_else(missing_field_err("authentication_data")) } + + /// Attempts to retrieve the connector mandate reference ID as a `Result`. + fn get_connector_mandate_request_reference_id(&self) -> Result { + self.mandate_id + .as_ref() + .and_then(|mandate_ids| match &mandate_ids.mandate_reference_id { + Some(payments::MandateReferenceId::ConnectorMandateId(connector_mandate_ids)) => { + connector_mandate_ids.get_connector_mandate_request_reference_id() + } + Some(payments::MandateReferenceId::NetworkMandateId(_)) + | None + | Some(payments::MandateReferenceId::NetworkTokenWithNTI(_)) => None, + }) + .ok_or_else(missing_field_err("connector_mandate_request_reference_id")) + } } pub trait ConnectorCustomerData { @@ -1054,6 +1074,7 @@ pub trait PaymentsCompleteAuthorizeRequestData { fn get_redirect_response_payload(&self) -> Result; fn get_complete_authorize_url(&self) -> Result; fn is_mandate_payment(&self) -> bool; + fn get_connector_mandate_request_reference_id(&self) -> Result; } impl PaymentsCompleteAuthorizeRequestData for types::CompleteAuthorizeData { @@ -1094,6 +1115,20 @@ impl PaymentsCompleteAuthorizeRequestData for types::CompleteAuthorizeData { .and_then(|mandate_ids| mandate_ids.mandate_reference_id.as_ref()) .is_some() } + /// Attempts to retrieve the connector mandate reference ID as a `Result`. + fn get_connector_mandate_request_reference_id(&self) -> Result { + self.mandate_id + .as_ref() + .and_then(|mandate_ids| match &mandate_ids.mandate_reference_id { + Some(payments::MandateReferenceId::ConnectorMandateId(connector_mandate_ids)) => { + connector_mandate_ids.get_connector_mandate_request_reference_id() + } + Some(payments::MandateReferenceId::NetworkMandateId(_)) + | None + | Some(payments::MandateReferenceId::NetworkTokenWithNTI(_)) => None, + }) + .ok_or_else(missing_field_err("connector_mandate_request_reference_id")) + } } pub trait PaymentsSyncRequestData { @@ -1920,8 +1955,7 @@ pub trait MandateReferenceData { impl MandateReferenceData for payments::ConnectorMandateReferenceId { fn get_connector_mandate_id(&self) -> Result { - self.connector_mandate_id - .clone() + self.get_connector_mandate_id() .ok_or_else(missing_field_err("mandate_id")) } } @@ -2431,31 +2465,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/connector/wellsfargo.rs b/crates/router/src/connector/wellsfargo.rs index f5cdb6431b35..a63007f0a273 100644 --- a/crates/router/src/connector/wellsfargo.rs +++ b/crates/router/src/connector/wellsfargo.rs @@ -1,9 +1,10 @@ pub mod transformers; -use std::fmt::Debug; - use base64::Engine; -use common_utils::request::RequestContent; +use common_utils::{ + request::RequestContent, + types::{AmountConvertor, MinorUnit, StringMajorUnit, StringMajorUnitForConnector}, +}; use diesel_models::enums; use error_stack::{report, Report, ResultExt}; use masking::{ExposeInterface, PeekInterface}; @@ -12,6 +13,7 @@ use time::OffsetDateTime; use transformers as wellsfargo; use url::Url; +use super::utils::convert_amount; use crate::{ configs::settings, connector::{ @@ -35,10 +37,18 @@ use crate::{ utils::BytesExt, }; -#[derive(Debug, Clone)] -pub struct Wellsfargo; +#[derive(Clone)] +pub struct Wellsfargo { + amount_converter: &'static (dyn AmountConvertor + Sync), +} impl Wellsfargo { + pub fn new() -> &'static Self { + &Self { + amount_converter: &StringMajorUnitForConnector, + } + } + pub fn generate_digest(&self, payload: &[u8]) -> String { let payload_digest = digest::digest(&digest::SHA256, payload); consts::BASE64_ENGINE.encode(payload_digest) @@ -600,12 +610,14 @@ impl ConnectorIntegration CustomResult { - let connector_router_data = wellsfargo::WellsfargoRouterData::try_from(( - &self.get_currency_unit(), + let amount = convert_amount( + self.amount_converter, + MinorUnit::new(req.request.amount_to_capture), req.request.currency, - req.request.amount_to_capture, - req, - ))?; + )?; + + let connector_router_data = wellsfargo::WellsfargoRouterData::from((amount, req)); + let connector_req = wellsfargo::WellsfargoPaymentsCaptureRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) @@ -792,12 +804,13 @@ impl ConnectorIntegration CustomResult { - let connector_router_data = wellsfargo::WellsfargoRouterData::try_from(( - &self.get_currency_unit(), + let amount = convert_amount( + self.amount_converter, + MinorUnit::new(req.request.amount), req.request.currency, - req.request.amount, - req, - ))?; + )?; + + let connector_router_data = wellsfargo::WellsfargoRouterData::from((amount, req)); let connector_req = wellsfargo::WellsfargoPaymentsRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) @@ -915,20 +928,21 @@ impl ConnectorIntegration CustomResult { - let connector_router_data = wellsfargo::WellsfargoRouterData::try_from(( - &self.get_currency_unit(), + let amount = convert_amount( + self.amount_converter, + MinorUnit::new(req.request.amount.ok_or( + errors::ConnectorError::MissingRequiredField { + field_name: "Amount", + }, + )?), req.request .currency .ok_or(errors::ConnectorError::MissingRequiredField { field_name: "Currency", })?, - req.request - .amount - .ok_or(errors::ConnectorError::MissingRequiredField { - field_name: "Amount", - })?, - req, - ))?; + )?; + + let connector_router_data = wellsfargo::WellsfargoRouterData::from((amount, req)); let connector_req = wellsfargo::WellsfargoVoidRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) @@ -1040,12 +1054,13 @@ impl ConnectorIntegration CustomResult { - let connector_router_data = wellsfargo::WellsfargoRouterData::try_from(( - &self.get_currency_unit(), + let amount = convert_amount( + self.amount_converter, + MinorUnit::new(req.request.refund_amount), req.request.currency, - req.request.refund_amount, - req, - ))?; + )?; + + let connector_router_data = wellsfargo::WellsfargoRouterData::from((amount, req)); let connector_req = wellsfargo::WellsfargoRefundRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -1204,12 +1219,13 @@ impl req: &types::PaymentsIncrementalAuthorizationRouterData, _connectors: &settings::Connectors, ) -> CustomResult { - let connector_router_data = wellsfargo::WellsfargoRouterData::try_from(( - &self.get_currency_unit(), + let amount = convert_amount( + self.amount_converter, + MinorUnit::new(req.request.additional_amount), req.request.currency, - req.request.additional_amount, - req, - ))?; + )?; + + let connector_router_data = wellsfargo::WellsfargoRouterData::from((amount, req)); let connector_request = wellsfargo::WellsfargoPaymentsIncrementalAuthorizationRequest::try_from( &connector_router_data, diff --git a/crates/router/src/connector/wellsfargo/transformers.rs b/crates/router/src/connector/wellsfargo/transformers.rs index c57306efe318..1ca6c7bd9683 100644 --- a/crates/router/src/connector/wellsfargo/transformers.rs +++ b/crates/router/src/connector/wellsfargo/transformers.rs @@ -1,7 +1,10 @@ use api_models::payments; use base64::Engine; use common_enums::FutureUsage; -use common_utils::{pii, types::SemanticVersion}; +use common_utils::{ + pii, + types::{SemanticVersion, StringMajorUnit}, +}; use masking::{ExposeInterface, PeekInterface, Secret}; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -26,21 +29,16 @@ use crate::{ #[derive(Debug, Serialize)] pub struct WellsfargoRouterData { - pub amount: String, + pub amount: StringMajorUnit, pub router_data: T, } -impl TryFrom<(&api::CurrencyUnit, enums::Currency, i64, T)> for WellsfargoRouterData { - type Error = error_stack::Report; - fn try_from( - (currency_unit, currency, amount, item): (&api::CurrencyUnit, enums::Currency, i64, T), - ) -> Result { - // This conversion function is used at different places in the file, if updating this, keep a check for those - let amount = utils::get_amount_as_string(currency_unit, amount, currency)?; - Ok(Self { +impl From<(StringMajorUnit, T)> for WellsfargoRouterData { + fn from((amount, router_data): (StringMajorUnit, T)) -> Self { + Self { amount, - router_data: item, - }) + router_data, + } } } @@ -61,7 +59,7 @@ impl TryFrom<&types::SetupMandateRouterData> for WellsfargoZeroMandateRequest { let order_information = OrderInformationWithBill { amount_details: Amount { - total_amount: "0".to_string(), + total_amount: StringMajorUnit::zero(), currency: item.request.currency, }, bill_to: Some(bill_to), @@ -472,14 +470,14 @@ pub struct OrderInformation { #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct Amount { - total_amount: String, + total_amount: StringMajorUnit, currency: api_models::enums::Currency, } #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct AdditionalAmount { - additional_amount: String, + additional_amount: StringMajorUnit, currency: String, } @@ -1789,12 +1787,13 @@ fn get_payment_response( .map(|payment_instrument| payment_instrument.id.expose()), payment_method_id: None, mandate_metadata: None, + connector_mandate_request_reference_id: None, }); Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(info_response.id.clone()), - redirection_data: None, - mandate_reference, + redirection_data: Box::new(None), + mandate_reference: Box::new(mandate_reference), connector_metadata: None, network_txn_id: info_response.processor_information.as_ref().and_then( |processor_information| processor_information.network_transaction_id.clone(), @@ -1975,6 +1974,7 @@ impl .map(|payment_instrument| payment_instrument.id.expose()), payment_method_id: None, mandate_metadata: None, + connector_mandate_request_reference_id: None, }); let mut mandate_status = enums::AttemptStatus::foreign_from(( item.response @@ -2005,8 +2005,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( item.response.id.clone(), ), - redirection_data: None, - mandate_reference, + redirection_data: Box::new(None), + mandate_reference: Box::new(mandate_reference), connector_metadata: None, network_txn_id: item.response.processor_information.as_ref().and_then( |processor_information| { @@ -2143,8 +2143,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( item.response.id.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: item @@ -2165,8 +2165,8 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( item.response.id.clone(), ), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(item.response.id), diff --git a/crates/router/src/connector/wellsfargopayout/transformers.rs b/crates/router/src/connector/wellsfargopayout/transformers.rs index e335c3cf59ae..135cb5f53cbf 100644 --- a/crates/router/src/connector/wellsfargopayout/transformers.rs +++ b/crates/router/src/connector/wellsfargopayout/transformers.rs @@ -134,8 +134,8 @@ impl status: enums::AttemptStatus::from(item.response.status), response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, diff --git a/crates/router/src/connector/worldpay/response.rs b/crates/router/src/connector/worldpay/response.rs deleted file mode 100644 index dbd596e2e202..000000000000 --- a/crates/router/src/connector/worldpay/response.rs +++ /dev/null @@ -1,323 +0,0 @@ -use masking::Secret; -use serde::{Deserialize, Serialize}; - -use super::requests::*; -use crate::{core::errors, types, types::transformers::ForeignTryFrom}; -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct WorldpayPaymentsResponse { - pub outcome: Option, - /// Any risk factors which have been identified for the authorization. This section will not appear if no risks are identified. - #[serde(skip_serializing_if = "Option::is_none")] - pub risk_factors: Option>, - #[serde(skip_serializing_if = "Option::is_none")] - pub issuer: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub scheme: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub payment_instrument: Option, - #[serde(rename = "_links", skip_serializing_if = "Option::is_none")] - pub links: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub description: Option, -} - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub enum PaymentOutcome { - #[serde(alias = "authorized", alias = "Authorized")] - Authorized, - Refused, - #[serde(alias = "Sent for Settlement")] - SentForSettlement, - #[serde(alias = "Sent for Refund")] - SentForRefund, -} - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub enum RefundOutcome { - #[serde(alias = "Sent for Refund")] - SentForRefund, -} - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct WorldpayEventResponse { - pub last_event: EventType, - #[serde(rename = "_links", skip_serializing_if = "Option::is_none")] - pub links: Option, -} - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub enum EventType { - SentForAuthorization, - #[serde(alias = "Authorized")] - Authorized, - #[serde(alias = "Sent for Settlement")] - SentForSettlement, - Settled, - SettlementFailed, - Cancelled, - Error, - Expired, - Refused, - #[serde(alias = "Sent for Refund")] - SentForRefund, - Refunded, - RefundFailed, - #[serde(other)] - Unknown, -} - -#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] -pub struct PaymentLinks { - #[serde( - rename = "cardPayments:events", - skip_serializing_if = "Option::is_none" - )] - pub events: Option, - #[serde( - rename = "cardPayments:settle", - skip_serializing_if = "Option::is_none" - )] - pub settle_event: Option, - #[serde( - rename = "cardPayments:partialSettle", - skip_serializing_if = "Option::is_none" - )] - pub partial_settle_event: Option, - #[serde( - rename = "cardPayments:refund", - skip_serializing_if = "Option::is_none" - )] - pub refund_event: Option, - #[serde( - rename = "cardPayments:partialRefund", - skip_serializing_if = "Option::is_none" - )] - pub partial_refund_event: Option, - #[serde( - rename = "cardPayments:reverse", - skip_serializing_if = "Option::is_none" - )] - pub reverse_event: Option, -} - -#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] -pub struct EventLinks { - #[serde(rename = "payments:events", skip_serializing_if = "Option::is_none")] - pub events: Option, -} - -#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] -pub struct PaymentLink { - pub href: String, -} - -fn get_resource_id( - links: Option, - transform_fn: F, -) -> Result> -where - F: Fn(String) -> T, -{ - let reference_id = links - .and_then(|l| l.events) - .and_then(|e| e.href.rsplit_once('/').map(|h| h.1.to_string())) - .map(transform_fn); - reference_id.ok_or_else(|| { - errors::ConnectorError::MissingRequiredField { - field_name: "links.events", - } - .into() - }) -} - -pub struct ResponseIdStr { - pub id: String, -} - -impl TryFrom> for ResponseIdStr { - type Error = error_stack::Report; - fn try_from(links: Option) -> Result { - get_resource_id(links, |id| Self { id }) - } -} - -impl ForeignTryFrom> for types::ResponseId { - type Error = error_stack::Report; - fn foreign_try_from(links: Option) -> Result { - get_resource_id(links, Self::ConnectorTransactionId) - } -} - -#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Issuer { - pub authorization_code: Secret, -} - -impl Issuer { - pub fn new(code: String) -> Self { - Self { - authorization_code: Secret::new(code), - } - } -} - -#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct PaymentsResPaymentInstrument { - #[serde(rename = "type", skip_serializing_if = "Option::is_none")] - pub payment_instrument_type: Option, - pub card_bin: Option, - pub last_four: Option, - pub category: Option, - pub expiry_date: Option, - pub card_brand: Option, - pub funding_type: Option, - pub issuer_name: Option, - pub payment_account_reference: Option, -} - -impl PaymentsResPaymentInstrument { - pub fn new() -> Self { - Self { - payment_instrument_type: None, - card_bin: None, - last_four: None, - category: None, - expiry_date: None, - card_brand: None, - funding_type: None, - issuer_name: None, - payment_account_reference: None, - } - } -} - -#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RiskFactorsInner { - #[serde(rename = "type")] - pub risk_type: RiskType, - #[serde(skip_serializing_if = "Option::is_none")] - pub detail: Option, - pub risk: Risk, -} - -impl RiskFactorsInner { - pub fn new(risk_type: RiskType, risk: Risk) -> Self { - Self { - risk_type, - detail: None, - risk, - } - } -} - -#[derive( - Clone, Copy, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, -)] -#[serde(rename_all = "camelCase")] -pub enum RiskType { - #[default] - Avs, - Cvc, - RiskProfile, -} - -#[derive( - Clone, Copy, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, -)] -#[serde(rename_all = "camelCase")] -pub enum Detail { - #[default] - Address, - Postcode, -} - -#[derive( - Clone, Copy, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, -)] -#[serde(rename_all = "camelCase")] -pub enum Risk { - #[default] - NotChecked, - NotMatched, - NotSupplied, - VerificationFailed, -} - -#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] -pub struct PaymentsResponseScheme { - pub reference: String, -} - -impl PaymentsResponseScheme { - pub fn new(reference: String) -> Self { - Self { reference } - } -} - -#[derive(Debug, Serialize, Deserialize, PartialEq)] -#[serde(rename_all = "camelCase")] -pub struct WorldpayErrorResponse { - pub error_name: String, - pub message: String, - pub validation_errors: Option, -} - -impl WorldpayErrorResponse { - pub fn default(status_code: u16) -> Self { - match status_code { - code @ 404 => Self { - error_name: format!("{} Not found", code), - message: "Resource not found".to_string(), - validation_errors: None, - }, - code => Self { - error_name: code.to_string(), - message: "Unknown error".to_string(), - validation_errors: None, - }, - } - } -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct WorldpayWebhookTransactionId { - pub event_details: EventDetails, -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct EventDetails { - pub transaction_reference: String, - #[serde(rename = "type")] - pub event_type: EventType, -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct WorldpayWebhookEventType { - pub event_id: String, - pub event_timestamp: String, - pub event_details: EventDetails, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[serde(rename_all = "camelCase")] -pub enum WorldpayWebhookStatus { - SentForSettlement, - Authorized, - SentForAuthorization, - Cancelled, - Error, - Expired, - Refused, - SentForRefund, - RefundFailed, -} diff --git a/crates/router/src/connector/worldpay/transformers.rs b/crates/router/src/connector/worldpay/transformers.rs deleted file mode 100644 index c5398b83a86f..000000000000 --- a/crates/router/src/connector/worldpay/transformers.rs +++ /dev/null @@ -1,364 +0,0 @@ -use api_models::payments::Address; -use base64::Engine; -use common_utils::{errors::CustomResult, ext_traits::OptionExt, types::MinorUnit}; -use diesel_models::enums; -use error_stack::ResultExt; -use hyperswitch_connectors::utils::RouterData; -use masking::{PeekInterface, Secret}; -use serde::Serialize; - -use super::{requests::*, response::*}; -use crate::{ - connector::utils, - consts, - core::errors, - types::{ - self, domain, transformers::ForeignTryFrom, PaymentsAuthorizeData, PaymentsResponseData, - }, -}; - -#[derive(Debug, Serialize)] -pub struct WorldpayRouterData { - amount: i64, - router_data: T, -} -impl - TryFrom<( - &types::api::CurrencyUnit, - types::storage::enums::Currency, - MinorUnit, - T, - )> for WorldpayRouterData -{ - type Error = error_stack::Report; - fn try_from( - (_currency_unit, _currency, minor_amount, item): ( - &types::api::CurrencyUnit, - types::storage::enums::Currency, - MinorUnit, - T, - ), - ) -> Result { - Ok(Self { - amount: minor_amount.get_amount_as_i64(), - router_data: item, - }) - } -} -fn fetch_payment_instrument( - payment_method: domain::PaymentMethodData, - billing_address: Option<&Address>, -) -> CustomResult { - match payment_method { - domain::PaymentMethodData::Card(card) => Ok(PaymentInstrument::Card(CardPayment { - payment_type: PaymentType::Card, - expiry_date: ExpiryDate { - month: utils::CardData::get_expiry_month_as_i8(&card)?, - year: utils::CardData::get_expiry_year_as_i32(&card)?, - }, - card_number: card.card_number, - cvc: card.card_cvc, - card_holder_name: card.nick_name, - billing_address: if let Some(address) = - billing_address.and_then(|addr| addr.address.clone()) - { - Some(BillingAddress { - address1: address.line1, - address2: address.line2, - address3: address.line3, - city: address.city, - state: address.state, - postal_code: address.zip.get_required_value("zip").change_context( - errors::ConnectorError::MissingRequiredField { field_name: "zip" }, - )?, - country_code: address - .country - .get_required_value("country_code") - .change_context(errors::ConnectorError::MissingRequiredField { - field_name: "country_code", - })?, - }) - } else { - None - }, - })), - domain::PaymentMethodData::Wallet(wallet) => match wallet { - domain::WalletData::GooglePay(data) => { - Ok(PaymentInstrument::Googlepay(WalletPayment { - payment_type: PaymentType::Googlepay, - wallet_token: Secret::new(data.tokenization_data.token), - ..WalletPayment::default() - })) - } - domain::WalletData::ApplePay(data) => Ok(PaymentInstrument::Applepay(WalletPayment { - payment_type: PaymentType::Applepay, - wallet_token: Secret::new(data.payment_data), - ..WalletPayment::default() - })), - 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::GooglePayRedirect(_) - | domain::WalletData::GooglePayThirdPartySdk(_) - | domain::WalletData::MbWayRedirect(_) - | domain::WalletData::MobilePayRedirect(_) - | domain::WalletData::PaypalRedirect(_) - | domain::WalletData::PaypalSdk(_) - | domain::WalletData::Paze(_) - | domain::WalletData::SamsungPay(_) - | domain::WalletData::TwintRedirect {} - | domain::WalletData::VippsRedirect {} - | domain::WalletData::TouchNGoRedirect(_) - | domain::WalletData::WeChatPayRedirect(_) - | domain::WalletData::CashappQr(_) - | domain::WalletData::SwishQr(_) - | domain::WalletData::WeChatPayQr(_) - | domain::WalletData::Mifinity(_) => Err(errors::ConnectorError::NotImplemented( - utils::get_unimplemented_payment_method_error_message("worldpay"), - ) - .into()), - }, - 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::CardRedirect(_) - | 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("worldpay"), - ) - .into()) - } - } -} - -impl - TryFrom<( - &WorldpayRouterData< - &types::RouterData< - types::api::payments::Authorize, - PaymentsAuthorizeData, - PaymentsResponseData, - >, - >, - &Secret, - )> for WorldpayPaymentsRequest -{ - type Error = error_stack::Report; - - fn try_from( - req: ( - &WorldpayRouterData< - &types::RouterData< - types::api::payments::Authorize, - PaymentsAuthorizeData, - PaymentsResponseData, - >, - >, - &Secret, - ), - ) -> Result { - let (item, entity_id) = req; - Ok(Self { - instruction: Instruction { - request_auto_settlement: RequestAutoSettlement { - enabled: item.router_data.request.capture_method - == Some(enums::CaptureMethod::Automatic), - }, - value: PaymentValue { - amount: item.amount, - currency: item.router_data.request.currency, - }, - narrative: InstructionNarrative { - line1: item - .router_data - .merchant_id - .get_string_repr() - .replace('_', "-"), - ..Default::default() - }, - payment_instrument: fetch_payment_instrument( - item.router_data.request.payment_method_data.clone(), - item.router_data.get_optional_billing(), - )?, - debt_repayment: None, - }, - merchant: Merchant { - entity: entity_id.clone(), - ..Default::default() - }, - transaction_reference: item.router_data.connector_request_reference_id.clone(), - channel: Channel::Ecom, - customer: None, - }) - } -} - -pub struct WorldpayAuthType { - pub(super) api_key: Secret, - pub(super) entity_id: Secret, -} - -impl TryFrom<&types::ConnectorAuthType> for WorldpayAuthType { - type Error = error_stack::Report; - fn try_from(auth_type: &types::ConnectorAuthType) -> Result { - match auth_type { - // TODO: Remove this later, kept purely for backwards compatibility - types::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 { - api_key: Secret::new(auth_header), - entity_id: Secret::new("default".to_string()), - }) - } - types::ConnectorAuthType::SignatureKey { - api_key, - key1, - api_secret, - } => { - let auth_key = format!("{}:{}", key1.peek(), api_key.peek()); - let auth_header = format!("Basic {}", consts::BASE64_ENGINE.encode(auth_key)); - Ok(Self { - api_key: Secret::new(auth_header), - entity_id: api_secret.clone(), - }) - } - _ => Err(errors::ConnectorError::FailedToObtainAuthType)?, - } - } -} - -impl From for enums::AttemptStatus { - fn from(item: PaymentOutcome) -> Self { - match item { - PaymentOutcome::Authorized => Self::Authorized, - PaymentOutcome::Refused => Self::Failure, - PaymentOutcome::SentForSettlement => Self::CaptureInitiated, - PaymentOutcome::SentForRefund => Self::AutoRefunded, - } - } -} - -impl From<&EventType> for enums::AttemptStatus { - fn from(value: &EventType) -> Self { - match value { - EventType::SentForAuthorization => Self::Authorizing, - EventType::SentForSettlement => Self::CaptureInitiated, - EventType::Settled => Self::Charged, - EventType::Authorized => Self::Authorized, - EventType::Refused | EventType::SettlementFailed => Self::Failure, - EventType::Cancelled - | EventType::SentForRefund - | EventType::RefundFailed - | EventType::Refunded - | EventType::Error - | EventType::Expired - | EventType::Unknown => Self::Pending, - } - } -} - -impl From for enums::RefundStatus { - fn from(value: EventType) -> Self { - match value { - EventType::Refunded | EventType::SentForRefund => Self::Success, - EventType::RefundFailed => Self::Failure, - EventType::Authorized - | EventType::Cancelled - | EventType::Settled - | EventType::Refused - | EventType::Error - | EventType::SentForSettlement - | EventType::SentForAuthorization - | EventType::SettlementFailed - | EventType::Expired - | EventType::Unknown => Self::Pending, - } - } -} - -impl TryFrom> - for types::PaymentsAuthorizeRouterData -{ - type Error = error_stack::Report; - fn try_from( - item: types::PaymentsResponseRouterData, - ) -> Result { - Ok(Self { - status: match item.response.outcome { - Some(outcome) => enums::AttemptStatus::from(outcome), - None => Err(errors::ConnectorError::MissingRequiredField { - field_name: "outcome", - })?, - }, - description: item.response.description, - response: Ok(PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::foreign_try_from(item.response.links)?, - redirection_data: None, - mandate_reference: None, - connector_metadata: None, - network_txn_id: None, - connector_response_reference_id: None, - incremental_authorization_allowed: None, - charge_id: None, - }), - ..item.data - }) - } -} - -impl TryFrom<(&types::PaymentsCaptureRouterData, MinorUnit)> for WorldpayPartialRequest { - type Error = error_stack::Report; - fn try_from(req: (&types::PaymentsCaptureRouterData, MinorUnit)) -> Result { - let (item, amount) = req; - Ok(Self { - reference: item.payment_id.clone().replace("_", "-"), - value: PaymentValue { - amount: amount.get_amount_as_i64(), - currency: item.request.currency, - }, - }) - } -} - -impl TryFrom<(&types::RefundsRouterData, MinorUnit)> for WorldpayPartialRequest { - type Error = error_stack::Report; - fn try_from(req: (&types::RefundsRouterData, MinorUnit)) -> Result { - let (item, amount) = req; - Ok(Self { - reference: item.request.refund_id.clone().replace("_", "-"), - value: PaymentValue { - amount: amount.get_amount_as_i64(), - currency: item.request.currency, - }, - }) - } -} - -impl TryFrom for WorldpayEventResponse { - type Error = error_stack::Report; - fn try_from(event: WorldpayWebhookEventType) -> Result { - Ok(Self { - last_event: event.event_details.event_type, - links: None, - }) - } -} diff --git a/crates/router/src/consts.rs b/crates/router/src/consts.rs index 28f3f23ccb8b..090ddca961ba 100644 --- a/crates/router/src/consts.rs +++ b/crates/router/src/consts.rs @@ -136,12 +136,15 @@ pub const CONNECTOR_CREDS_TOKEN_TTL: i64 = 900; pub const MAX_ALLOWED_AMOUNT: i64 = 999999999; //payment attempt default unified error code and unified error message -pub const DEFAULT_UNIFIED_ERROR_CODE: &str = "UE_000"; +pub const DEFAULT_UNIFIED_ERROR_CODE: &str = "UE_9000"; pub const DEFAULT_UNIFIED_ERROR_MESSAGE: &str = "Something went wrong"; // Recon's feature tag pub const RECON_FEATURE_TAG: &str = "RECONCILIATION AND SETTLEMENT"; +// Length of the unique reference ID generated for connector mandate requests +pub const CONNECTOR_MANDATE_REQUEST_REFERENCE_ID_LENGTH: usize = 18; + /// Vault Add request url #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] pub const ADD_VAULT_REQUEST_URL: &str = "/vault/add"; @@ -177,3 +180,6 @@ pub const VAULT_DELETE_FLOW_TYPE: &str = "delete_from_vault"; /// Vault Fingerprint fetch flow type #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] pub const VAULT_GET_FINGERPRINT_FLOW_TYPE: &str = "get_fingerprint_vault"; + +/// Worldpay's unique reference ID for a request TODO: Move to hyperswitch_connectors/constants once Worldpay is moved to connectors crate +pub const WP_CORRELATION_ID: &str = "WP-CorrelationId"; diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs index 545f94cfeb4e..cffb8267bff9 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -15,7 +15,7 @@ use diesel_models::configs; use diesel_models::organization::OrganizationBridge; use error_stack::{report, FutureExt, ResultExt}; use hyperswitch_domain_models::merchant_connector_account::{ - McaFromRequest, McaFromRequestfromUpdate, + FromRequestEncryptableMerchantConnectorAccount, UpdateEncryptableMerchantConnectorAccount, }; use masking::{ExposeInterface, PeekInterface, Secret}; use pm_auth::{connector::plaid::transformers::PlaidAuthType, types as pm_auth_types}; @@ -2095,18 +2095,20 @@ impl MerchantConnectorAccountUpdateBridge for api_models::admin::MerchantConnect let encrypted_data = domain_types::crypto_operation( key_manager_state, type_name!(domain::MerchantConnectorAccount), - domain_types::CryptoOperation::BatchEncrypt(McaFromRequestfromUpdate::to_encryptable( - McaFromRequestfromUpdate { - connector_account_details: self.connector_account_details, - connector_wallets_details: - helpers::get_connector_wallets_details_with_apple_pay_certificates( - &self.metadata, - &self.connector_wallets_details, - ) - .await?, - additional_merchant_data: merchant_recipient_data.map(Secret::new), - }, - )), + domain_types::CryptoOperation::BatchEncrypt( + UpdateEncryptableMerchantConnectorAccount::to_encryptable( + UpdateEncryptableMerchantConnectorAccount { + connector_account_details: self.connector_account_details, + connector_wallets_details: + helpers::get_connector_wallets_details_with_apple_pay_certificates( + &self.metadata, + &self.connector_wallets_details, + ) + .await?, + additional_merchant_data: merchant_recipient_data.map(Secret::new), + }, + ), + ), km_types::Identifier::Merchant(key_store.merchant_id.clone()), key_store.key.peek(), ) @@ -2115,14 +2117,15 @@ impl MerchantConnectorAccountUpdateBridge for api_models::admin::MerchantConnect .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed while decrypting connector account details".to_string())?; - let encrypted_data = McaFromRequestfromUpdate::from_encryptable(encrypted_data) - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Failed while decrypting connector account details")?; + let encrypted_data = + UpdateEncryptableMerchantConnectorAccount::from_encryptable(encrypted_data) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed while decrypting connector account details")?; Ok(storage::MerchantConnectorAccountUpdate::Update { connector_type: Some(self.connector_type), connector_label: self.connector_label.clone(), - connector_account_details: encrypted_data.connector_account_details, + connector_account_details: Box::new(encrypted_data.connector_account_details), disabled, payment_methods_enabled, metadata: self.metadata, @@ -2136,10 +2139,10 @@ impl MerchantConnectorAccountUpdateBridge for api_models::admin::MerchantConnect None => None, }, applepay_verified_domains: None, - pm_auth_config: self.pm_auth_config, + pm_auth_config: Box::new(self.pm_auth_config), status: Some(connector_status), - additional_merchant_data: encrypted_data.additional_merchant_data, - connector_wallets_details: encrypted_data.connector_wallets_details, + additional_merchant_data: Box::new(encrypted_data.additional_merchant_data), + connector_wallets_details: Box::new(encrypted_data.connector_wallets_details), }) } } @@ -2262,18 +2265,20 @@ impl MerchantConnectorAccountUpdateBridge for api_models::admin::MerchantConnect let encrypted_data = domain_types::crypto_operation( key_manager_state, type_name!(domain::MerchantConnectorAccount), - domain_types::CryptoOperation::BatchEncrypt(McaFromRequestfromUpdate::to_encryptable( - McaFromRequestfromUpdate { - connector_account_details: self.connector_account_details, - connector_wallets_details: - helpers::get_connector_wallets_details_with_apple_pay_certificates( - &self.metadata, - &self.connector_wallets_details, - ) - .await?, - additional_merchant_data: merchant_recipient_data.map(Secret::new), - }, - )), + domain_types::CryptoOperation::BatchEncrypt( + UpdateEncryptableMerchantConnectorAccount::to_encryptable( + UpdateEncryptableMerchantConnectorAccount { + connector_account_details: self.connector_account_details, + connector_wallets_details: + helpers::get_connector_wallets_details_with_apple_pay_certificates( + &self.metadata, + &self.connector_wallets_details, + ) + .await?, + additional_merchant_data: merchant_recipient_data.map(Secret::new), + }, + ), + ), km_types::Identifier::Merchant(key_store.merchant_id.clone()), key_store.key.peek(), ) @@ -2282,34 +2287,37 @@ impl MerchantConnectorAccountUpdateBridge for api_models::admin::MerchantConnect .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed while decrypting connector account details".to_string())?; - let encrypted_data = McaFromRequestfromUpdate::from_encryptable(encrypted_data) - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Failed while decrypting connector account details")?; + let encrypted_data = + UpdateEncryptableMerchantConnectorAccount::from_encryptable(encrypted_data) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed while decrypting connector account details")?; Ok(storage::MerchantConnectorAccountUpdate::Update { connector_type: Some(self.connector_type), connector_name: None, merchant_connector_id: None, connector_label: self.connector_label.clone(), - connector_account_details: encrypted_data.connector_account_details, + connector_account_details: Box::new(encrypted_data.connector_account_details), test_mode: self.test_mode, disabled, payment_methods_enabled, metadata: self.metadata, frm_configs, connector_webhook_details: match &self.connector_webhook_details { - Some(connector_webhook_details) => connector_webhook_details - .encode_to_value() - .change_context(errors::ApiErrorResponse::InternalServerError) - .map(Some)? - .map(Secret::new), - None => None, + Some(connector_webhook_details) => Box::new( + connector_webhook_details + .encode_to_value() + .change_context(errors::ApiErrorResponse::InternalServerError) + .map(Some)? + .map(Secret::new), + ), + None => Box::new(None), }, applepay_verified_domains: None, - pm_auth_config: self.pm_auth_config, + pm_auth_config: Box::new(self.pm_auth_config), status: Some(connector_status), - additional_merchant_data: encrypted_data.additional_merchant_data, - connector_wallets_details: encrypted_data.connector_wallets_details, + additional_merchant_data: Box::new(encrypted_data.additional_merchant_data), + connector_wallets_details: Box::new(encrypted_data.connector_wallets_details), }) } } @@ -2402,22 +2410,24 @@ impl MerchantConnectorAccountCreateBridge for api::MerchantConnectorCreate { let encrypted_data = domain_types::crypto_operation( key_manager_state, type_name!(domain::MerchantConnectorAccount), - domain_types::CryptoOperation::BatchEncrypt(McaFromRequest::to_encryptable( - McaFromRequest { - connector_account_details: self.connector_account_details.ok_or( - errors::ApiErrorResponse::MissingRequiredField { - field_name: "connector_account_details", - }, - )?, - connector_wallets_details: - helpers::get_connector_wallets_details_with_apple_pay_certificates( - &self.metadata, - &self.connector_wallets_details, - ) - .await?, - additional_merchant_data: merchant_recipient_data.map(Secret::new), - }, - )), + domain_types::CryptoOperation::BatchEncrypt( + FromRequestEncryptableMerchantConnectorAccount::to_encryptable( + FromRequestEncryptableMerchantConnectorAccount { + connector_account_details: self.connector_account_details.ok_or( + errors::ApiErrorResponse::MissingRequiredField { + field_name: "connector_account_details", + }, + )?, + connector_wallets_details: + helpers::get_connector_wallets_details_with_apple_pay_certificates( + &self.metadata, + &self.connector_wallets_details, + ) + .await?, + additional_merchant_data: merchant_recipient_data.map(Secret::new), + }, + ), + ), identifier.clone(), key_store.key.peek(), ) @@ -2426,9 +2436,10 @@ impl MerchantConnectorAccountCreateBridge for api::MerchantConnectorCreate { .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed while decrypting connector account details".to_string())?; - let encrypted_data = McaFromRequest::from_encryptable(encrypted_data) - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Failed while decrypting connector account details")?; + let encrypted_data = + FromRequestEncryptableMerchantConnectorAccount::from_encryptable(encrypted_data) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed while decrypting connector account details")?; Ok(domain::MerchantConnectorAccount { merchant_id: business_profile.merchant_id.clone(), @@ -2571,22 +2582,24 @@ impl MerchantConnectorAccountCreateBridge for api::MerchantConnectorCreate { let encrypted_data = domain_types::crypto_operation( key_manager_state, type_name!(domain::MerchantConnectorAccount), - domain_types::CryptoOperation::BatchEncrypt(McaFromRequest::to_encryptable( - McaFromRequest { - connector_account_details: self.connector_account_details.ok_or( - errors::ApiErrorResponse::MissingRequiredField { - field_name: "connector_account_details", - }, - )?, - connector_wallets_details: - helpers::get_connector_wallets_details_with_apple_pay_certificates( - &self.metadata, - &self.connector_wallets_details, - ) - .await?, - additional_merchant_data: merchant_recipient_data.map(Secret::new), - }, - )), + domain_types::CryptoOperation::BatchEncrypt( + FromRequestEncryptableMerchantConnectorAccount::to_encryptable( + FromRequestEncryptableMerchantConnectorAccount { + connector_account_details: self.connector_account_details.ok_or( + errors::ApiErrorResponse::MissingRequiredField { + field_name: "connector_account_details", + }, + )?, + connector_wallets_details: + helpers::get_connector_wallets_details_with_apple_pay_certificates( + &self.metadata, + &self.connector_wallets_details, + ) + .await?, + additional_merchant_data: merchant_recipient_data.map(Secret::new), + }, + ), + ), identifier.clone(), key_store.key.peek(), ) @@ -2595,9 +2608,10 @@ impl MerchantConnectorAccountCreateBridge for api::MerchantConnectorCreate { .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed while decrypting connector account details".to_string())?; - let encrypted_data = McaFromRequest::from_encryptable(encrypted_data) - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Failed while decrypting connector account details")?; + let encrypted_data = + FromRequestEncryptableMerchantConnectorAccount::from_encryptable(encrypted_data) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed while decrypting connector account details")?; Ok(domain::MerchantConnectorAccount { merchant_id: business_profile.merchant_id.clone(), diff --git a/crates/router/src/core/api_keys.rs b/crates/router/src/core/api_keys.rs index 6e907dbd91bf..de4a8931c785 100644 --- a/crates/router/src/core/api_keys.rs +++ b/crates/router/src/core/api_keys.rs @@ -13,7 +13,6 @@ use crate::{ routes::{metrics, SessionState}, services::{authentication, ApplicationResponse}, types::{api, storage, transformers::ForeignInto}, - utils, }; #[cfg(feature = "email")] @@ -63,9 +62,9 @@ impl PlaintextApiKey { Self(format!("{env}_{key}").into()) } - pub fn new_key_id() -> String { + pub fn new_key_id() -> common_utils::id_type::ApiKeyId { let env = router_env::env::prefix_for_env(); - utils::generate_id(consts::ID_LENGTH, env) + common_utils::id_type::ApiKeyId::generate_key_id(env) } pub fn prefix(&self) -> String { @@ -223,7 +222,7 @@ pub async fn add_api_key_expiry_task( expiry_reminder_days: expiry_reminder_days.clone(), }; - let process_tracker_id = generate_task_id_for_api_key_expiry_workflow(api_key.key_id.as_str()); + let process_tracker_id = generate_task_id_for_api_key_expiry_workflow(&api_key.key_id); let process_tracker_entry = storage::ProcessTrackerNew::new( process_tracker_id, API_KEY_EXPIRY_NAME, @@ -241,7 +240,7 @@ pub async fn add_api_key_expiry_task( .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable_lazy(|| { format!( - "Failed while inserting API key expiry reminder to process_tracker: api_key_id: {}", + "Failed while inserting API key expiry reminder to process_tracker: {:?}", api_key.key_id ) })?; @@ -258,11 +257,11 @@ pub async fn add_api_key_expiry_task( pub async fn retrieve_api_key( state: SessionState, merchant_id: common_utils::id_type::MerchantId, - key_id: &str, + key_id: common_utils::id_type::ApiKeyId, ) -> RouterResponse { let store = state.store.as_ref(); let api_key = store - .find_api_key_by_merchant_id_key_id_optional(&merchant_id, key_id) + .find_api_key_by_merchant_id_key_id_optional(&merchant_id, &key_id) .await .change_context(errors::ApiErrorResponse::InternalServerError) // If retrieve failed .attach_printable("Failed to retrieve API key")? @@ -388,7 +387,7 @@ pub async fn update_api_key_expiry_task( } } - let task_id = generate_task_id_for_api_key_expiry_workflow(api_key.key_id.as_str()); + let task_id = generate_task_id_for_api_key_expiry_workflow(&api_key.key_id); let task_ids = vec![task_id.clone()]; @@ -430,7 +429,7 @@ pub async fn update_api_key_expiry_task( pub async fn revoke_api_key( state: SessionState, merchant_id: &common_utils::id_type::MerchantId, - key_id: &str, + key_id: &common_utils::id_type::ApiKeyId, ) -> RouterResponse { let store = state.store.as_ref(); @@ -496,7 +495,7 @@ pub async fn revoke_api_key( #[instrument(skip_all)] pub async fn revoke_api_key_expiry_task( store: &dyn crate::db::StorageInterface, - key_id: &str, + key_id: &common_utils::id_type::ApiKeyId, ) -> Result<(), errors::ProcessTrackerError> { let task_id = generate_task_id_for_api_key_expiry_workflow(key_id); let task_ids = vec![task_id]; @@ -535,8 +534,13 @@ pub async fn list_api_keys( } #[cfg(feature = "email")] -fn generate_task_id_for_api_key_expiry_workflow(key_id: &str) -> String { - format!("{API_KEY_EXPIRY_RUNNER}_{API_KEY_EXPIRY_NAME}_{key_id}") +fn generate_task_id_for_api_key_expiry_workflow( + key_id: &common_utils::id_type::ApiKeyId, +) -> String { + format!( + "{API_KEY_EXPIRY_RUNNER}_{API_KEY_EXPIRY_NAME}_{}", + key_id.get_string_repr() + ) } impl From<&str> for PlaintextApiKey { diff --git a/crates/router/src/core/authentication/transformers.rs b/crates/router/src/core/authentication/transformers.rs index 6013cdbe97f7..6b8a378a0701 100644 --- a/crates/router/src/core/authentication/transformers.rs +++ b/crates/router/src/core/authentication/transformers.rs @@ -184,6 +184,7 @@ pub fn construct_router_data( integrity_check: Ok(()), additional_merchant_data: None, header_payload: None, + connector_mandate_request_reference_id: None, }) } diff --git a/crates/router/src/core/connector_onboarding.rs b/crates/router/src/core/connector_onboarding.rs index c3de228d9a7b..5813a5bcd0cc 100644 --- a/crates/router/src/core/connector_onboarding.rs +++ b/crates/router/src/core/connector_onboarding.rs @@ -95,7 +95,7 @@ pub async fn sync_onboarding_status( .await?; return Ok(ApplicationResponse::Json(api::OnboardingStatus::PayPal( - api::PayPalOnboardingStatus::ConnectorIntegrated(update_mca_data), + api::PayPalOnboardingStatus::ConnectorIntegrated(Box::new(update_mca_data)), ))); } Ok(ApplicationResponse::Json(status)) diff --git a/crates/router/src/core/currency.rs b/crates/router/src/core/currency.rs index 96d75098271b..912484b014a7 100644 --- a/crates/router/src/core/currency.rs +++ b/crates/router/src/core/currency.rs @@ -1,4 +1,6 @@ +use analytics::errors::AnalyticsError; use common_utils::errors::CustomResult; +use currency_conversion::types::ExchangeRates; use error_stack::ResultExt; use crate::{ @@ -46,3 +48,19 @@ pub async fn convert_forex( .change_context(ApiErrorResponse::InternalServerError)?, )) } + +pub async fn get_forex_exchange_rates( + state: SessionState, +) -> CustomResult { + let forex_api = state.conf.forex_api.get_inner(); + let rates = get_forex_rates( + &state, + forex_api.call_delay, + forex_api.local_fetch_retry_delay, + forex_api.local_fetch_retry_count, + ) + .await + .change_context(AnalyticsError::ForexFetchFailed)?; + + Ok((*rates.data).clone()) +} diff --git a/crates/router/src/core/customers.rs b/crates/router/src/core/customers.rs index 19fbbf1952bc..6d47ac174f3d 100644 --- a/crates/router/src/core/customers.rs +++ b/crates/router/src/core/customers.rs @@ -1,16 +1,15 @@ -use api_models::customers::CustomerRequestWithEmail; use common_utils::{ crypto::Encryptable, errors::ReportSwitchExt, ext_traits::{AsyncExt, OptionExt}, - id_type, type_name, + id_type, pii, type_name, types::{ keymanager::{Identifier, KeyManagerState, ToEncryptable}, Description, }, }; use error_stack::{report, ResultExt}; -use masking::{Secret, SwitchStrategy}; +use masking::{ExposeInterface, Secret, SwitchStrategy}; use router_env::{instrument, tracing}; #[cfg(all(feature = "v2", feature = "customer_v2"))] @@ -145,13 +144,15 @@ impl CustomerCreateBridge for customers::CustomerRequest { let encrypted_data = types::crypto_operation( key_manager_state, type_name!(domain::Customer), - types::CryptoOperation::BatchEncrypt(CustomerRequestWithEmail::to_encryptable( - CustomerRequestWithEmail { - name: self.name.clone(), - email: self.email.clone(), - phone: self.phone.clone(), - }, - )), + types::CryptoOperation::BatchEncrypt( + domain::FromRequestEncryptableCustomer::to_encryptable( + domain::FromRequestEncryptableCustomer { + name: self.name.clone(), + email: self.email.clone().map(|a| a.expose().switch_strategy()), + phone: self.phone.clone(), + }, + ), + ), Identifier::Merchant(key_store.merchant_id.clone()), key, ) @@ -160,8 +161,9 @@ impl CustomerCreateBridge for customers::CustomerRequest { .switch() .attach_printable("Failed while encrypting Customer")?; - let encryptable_customer = CustomerRequestWithEmail::from_encryptable(encrypted_data) - .change_context(errors::CustomersErrorResponse::InternalServerError)?; + let encryptable_customer = + domain::FromRequestEncryptableCustomer::from_encryptable(encrypted_data) + .change_context(errors::CustomersErrorResponse::InternalServerError)?; Ok(domain::Customer { customer_id: merchant_reference_id @@ -169,7 +171,13 @@ impl CustomerCreateBridge for customers::CustomerRequest { .ok_or(errors::CustomersErrorResponse::InternalServerError)?, merchant_id: merchant_id.to_owned(), name: encryptable_customer.name, - email: encryptable_customer.email, + email: encryptable_customer.email.map(|email| { + let encryptable: Encryptable> = Encryptable::new( + email.clone().into_inner().switch_strategy(), + email.into_encrypted(), + ); + encryptable + }), phone: encryptable_customer.phone, description: self.description.clone(), phone_country_code: self.phone_country_code.clone(), @@ -234,13 +242,15 @@ impl CustomerCreateBridge for customers::CustomerRequest { let encrypted_data = types::crypto_operation( key_state, type_name!(domain::Customer), - types::CryptoOperation::BatchEncrypt(CustomerRequestWithEmail::to_encryptable( - CustomerRequestWithEmail { - name: Some(self.name.clone()), - email: Some(self.email.clone()), - phone: self.phone.clone(), - }, - )), + types::CryptoOperation::BatchEncrypt( + domain::FromRequestEncryptableCustomer::to_encryptable( + domain::FromRequestEncryptableCustomer { + name: Some(self.name.clone()), + email: Some(self.email.clone().expose().switch_strategy()), + phone: self.phone.clone(), + }, + ), + ), Identifier::Merchant(key_store.merchant_id.clone()), key, ) @@ -249,15 +259,22 @@ impl CustomerCreateBridge for customers::CustomerRequest { .switch() .attach_printable("Failed while encrypting Customer")?; - let encryptable_customer = CustomerRequestWithEmail::from_encryptable(encrypted_data) - .change_context(errors::CustomersErrorResponse::InternalServerError)?; + let encryptable_customer = + domain::FromRequestEncryptableCustomer::from_encryptable(encrypted_data) + .change_context(errors::CustomersErrorResponse::InternalServerError)?; Ok(domain::Customer { id: common_utils::generate_time_ordered_id("cus"), merchant_reference_id: merchant_reference_id.to_owned(), merchant_id, name: encryptable_customer.name, - email: encryptable_customer.email, + email: encryptable_customer.email.map(|email| { + let encryptable: Encryptable> = Encryptable::new( + email.clone().into_inner().switch_strategy(), + email.into_encrypted(), + ); + encryptable + }), phone: encryptable_customer.phone, description: self.description.clone(), phone_country_code: self.phone_country_code.clone(), @@ -662,7 +679,7 @@ impl CustomerDeleteBridge for customers::GlobalId { description: Some(Description::from_str_unchecked(REDACTED)), phone_country_code: Some(REDACTED.to_string()), metadata: None, - connector_customer: None, + connector_customer: Box::new(None), default_billing_address: None, default_shipping_address: None, default_payment_method_id: None, @@ -904,7 +921,7 @@ impl CustomerDeleteBridge for customers::CustomerId { description: Some(Description::from_str_unchecked(REDACTED)), phone_country_code: Some(REDACTED.to_string()), metadata: None, - connector_customer: None, + connector_customer: Box::new(None), address_id: None, }; @@ -1174,13 +1191,18 @@ impl CustomerUpdateBridge for customers::CustomerUpdateRequest { let encrypted_data = types::crypto_operation( key_manager_state, type_name!(domain::Customer), - types::CryptoOperation::BatchEncrypt(CustomerRequestWithEmail::to_encryptable( - CustomerRequestWithEmail { - name: self.name.clone(), - email: self.email.clone(), - phone: self.phone.clone(), - }, - )), + types::CryptoOperation::BatchEncrypt( + domain::FromRequestEncryptableCustomer::to_encryptable( + domain::FromRequestEncryptableCustomer { + name: self.name.clone(), + email: self + .email + .as_ref() + .map(|a| a.clone().expose().switch_strategy()), + phone: self.phone.clone(), + }, + ), + ), Identifier::Merchant(key_store.merchant_id.clone()), key, ) @@ -1188,8 +1210,9 @@ impl CustomerUpdateBridge for customers::CustomerUpdateRequest { .and_then(|val| val.try_into_batchoperation()) .switch()?; - let encryptable_customer = CustomerRequestWithEmail::from_encryptable(encrypted_data) - .change_context(errors::CustomersErrorResponse::InternalServerError)?; + let encryptable_customer = + domain::FromRequestEncryptableCustomer::from_encryptable(encrypted_data) + .change_context(errors::CustomersErrorResponse::InternalServerError)?; let response = db .update_customer_by_customer_id_merchant_id( @@ -1199,12 +1222,19 @@ impl CustomerUpdateBridge for customers::CustomerUpdateRequest { domain_customer.to_owned(), storage::CustomerUpdate::Update { name: encryptable_customer.name, - email: encryptable_customer.email, + email: encryptable_customer.email.map(|email| { + let encryptable: Encryptable> = + Encryptable::new( + email.clone().into_inner().switch_strategy(), + email.into_encrypted(), + ); + encryptable + }), phone: Box::new(encryptable_customer.phone), phone_country_code: self.phone_country_code.clone(), metadata: self.metadata.clone(), description: self.description.clone(), - connector_customer: None, + connector_customer: Box::new(None), address_id: address.clone().map(|addr| addr.address_id), }, key_store, @@ -1266,13 +1296,18 @@ impl CustomerUpdateBridge for customers::CustomerUpdateRequest { let encrypted_data = types::crypto_operation( key_manager_state, type_name!(domain::Customer), - types::CryptoOperation::BatchEncrypt(CustomerRequestWithEmail::to_encryptable( - CustomerRequestWithEmail { - name: self.name.clone(), - email: self.email.clone(), - phone: self.phone.clone(), - }, - )), + types::CryptoOperation::BatchEncrypt( + domain::FromRequestEncryptableCustomer::to_encryptable( + domain::FromRequestEncryptableCustomer { + name: self.name.clone(), + email: self + .email + .as_ref() + .map(|a| a.clone().expose().switch_strategy()), + phone: self.phone.clone(), + }, + ), + ), Identifier::Merchant(key_store.merchant_id.clone()), key, ) @@ -1280,8 +1315,9 @@ impl CustomerUpdateBridge for customers::CustomerUpdateRequest { .and_then(|val| val.try_into_batchoperation()) .switch()?; - let encryptable_customer = CustomerRequestWithEmail::from_encryptable(encrypted_data) - .change_context(errors::CustomersErrorResponse::InternalServerError)?; + let encryptable_customer = + domain::FromRequestEncryptableCustomer::from_encryptable(encrypted_data) + .change_context(errors::CustomersErrorResponse::InternalServerError)?; let response = db .update_customer_by_global_id( @@ -1291,12 +1327,19 @@ impl CustomerUpdateBridge for customers::CustomerUpdateRequest { merchant_account.get_id(), storage::CustomerUpdate::Update { name: encryptable_customer.name, - email: Box::new(encryptable_customer.email), + email: Box::new(encryptable_customer.email.map(|email| { + let encryptable: Encryptable> = + Encryptable::new( + email.clone().into_inner().switch_strategy(), + email.into_encrypted(), + ); + encryptable + })), phone: Box::new(encryptable_customer.phone), phone_country_code: self.phone_country_code.clone(), metadata: self.metadata.clone(), description: self.description.clone(), - connector_customer: None, + connector_customer: Box::new(None), default_billing_address: encrypted_customer_billing_address.map(Into::into), default_shipping_address: encrypted_customer_shipping_address.map(Into::into), default_payment_method_id: Some(self.default_payment_method_id.clone()), diff --git a/crates/router/src/core/errors.rs b/crates/router/src/core/errors.rs index aa4ff406a2ce..d095b471e2dd 100644 --- a/crates/router/src/core/errors.rs +++ b/crates/router/src/core/errors.rs @@ -328,6 +328,20 @@ pub enum RoutingError { VolumeSplitFailed, #[error("Unable to parse metadata")] MetadataParsingError, + #[error("Unable to retrieve success based routing config")] + SuccessBasedRoutingConfigError, + #[error("Unable to calculate success based routing config from dynamic routing service")] + SuccessRateCalculationError, + #[error("Success rate client from dynamic routing gRPC service not initialized")] + SuccessRateClientInitializationError, + #[error("Unable to convert from '{from}' to '{to}'")] + GenericConversionError { from: String, to: String }, + #[error("Invalid success based connector label received from dynamic routing service: '{0}'")] + InvalidSuccessBasedConnectorLabel(String), + #[error("unable to find '{field}'")] + GenericNotFoundError { field: String }, + #[error("Unable to deserialize from '{from}' to '{to}'")] + DeserializationError { from: String, to: String }, } #[derive(Debug, Clone, thiserror::Error)] 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 64c8694a5bf6..4249559aab6b 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 @@ -159,6 +160,7 @@ impl ConstructFlowSpecificData( integrity_check: Ok(()), additional_merchant_data: None, header_payload: None, + connector_mandate_request_reference_id: None, }; Ok(router_data) } 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 1c55bffeb870..3ef2b9232082 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; @@ -128,6 +128,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; @@ -136,6 +136,7 @@ impl ConstructFlowSpecificData, _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, > { @@ -145,6 +145,7 @@ impl integrity_check: Ok(()), additional_merchant_data: None, header_payload, + connector_mandate_request_reference_id: None, }; Ok(router_data) 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 8a9a91fb1e7a..deb4a3621ff3 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/mandate.rs b/crates/router/src/core/mandate.rs index b5707979247b..5ed3e9105632 100644 --- a/crates/router/src/core/mandate.rs +++ b/crates/router/src/core/mandate.rs @@ -357,10 +357,10 @@ where network_txn_id, .. } => (mandate_reference.clone(), network_txn_id.clone()), - _ => (None, None), + _ => (Box::new(None), None), }; - let mandate_ids = mandate_reference + let mandate_ids = (*mandate_reference) .as_ref() .map(|md| { md.encode_to_value() @@ -379,7 +379,7 @@ where mandate_ids, network_txn_id, get_insensitive_payment_method_data_if_exists(resp), - mandate_reference, + *mandate_reference, merchant_connector_id, )? else { @@ -439,7 +439,7 @@ impl ForeignFrom> match resp { Ok(types::PaymentsResponseData::TransactionResponse { mandate_reference, .. - }) => mandate_reference, + }) => *mandate_reference, _ => None, } } diff --git a/crates/router/src/core/mandate/utils.rs b/crates/router/src/core/mandate/utils.rs index 544f9ea756ec..294be0493785 100644 --- a/crates/router/src/core/mandate/utils.rs +++ b/crates/router/src/core/mandate/utils.rs @@ -80,6 +80,7 @@ pub async fn construct_mandate_revoke_router_data( integrity_check: Ok(()), additional_merchant_data: None, header_payload: None, + connector_mandate_request_reference_id: None, }; Ok(router_data) diff --git a/crates/router/src/core/payment_link.rs b/crates/router/src/core/payment_link.rs index ebc522b30ad9..09a2457197cb 100644 --- a/crates/router/src/core/payment_link.rs +++ b/crates/router/src/core/payment_link.rs @@ -11,7 +11,7 @@ use common_utils::{ DEFAULT_PRODUCT_IMG, DEFAULT_SDK_LAYOUT, DEFAULT_SESSION_EXPIRY, }, ext_traits::{AsyncExt, OptionExt, ValueExt}, - types::{AmountConvertor, MinorUnit, StringMajorUnitForCore}, + types::{AmountConvertor, StringMajorUnitForCore}, }; use error_stack::{report, ResultExt}; use futures::future; @@ -547,7 +547,7 @@ fn validate_order_details( .clone_from(&order.product_img_link) }; order_details_amount_string.amount = required_conversion_type - .convert(MinorUnit::new(order.amount), currency) + .convert(order.amount, currency) .change_context(errors::ApiErrorResponse::AmountConversionFailed { amount_type: "StringMajorUnit", })?; diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs index 005b5aeba6c3..87078dfa5aff 100644 --- a/crates/router/src/core/payment_methods.rs +++ b/crates/router/src/core/payment_methods.rs @@ -753,6 +753,7 @@ pub(crate) async fn get_payment_method_create_request( payment_method_type: Option, customer_id: &Option, billing_name: Option>, + payment_method_billing_address: Option<&api_models::payments::Address>, ) -> RouterResult { match payment_method_data { Some(pm_data) => match payment_method { @@ -787,7 +788,7 @@ pub(crate) async fn get_payment_method_create_request( .map(|card_network| card_network.to_string()), client_secret: None, payment_method_data: None, - billing: None, + billing: payment_method_billing_address.cloned(), connector_mandate_details: None, network_transaction_id: None, }; diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 8419a600f39e..990a0f0e9ad5 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -2058,7 +2058,7 @@ pub async fn get_payment_method_from_hs_locker<'a>( merchant_id, payment_method_reference, locker_choice, - state.tenant.name.clone(), + state.tenant.tenant_id.clone(), state.request_id, ) .await @@ -2112,7 +2112,7 @@ pub async fn add_card_to_hs_locker( locker, payload, locker_choice, - state.tenant.name.clone(), + state.tenant.tenant_id.clone(), state.request_id, ) .await?; @@ -2309,7 +2309,7 @@ pub async fn get_card_from_hs_locker<'a>( merchant_id, card_reference, Some(locker_choice), - state.tenant.name.clone(), + state.tenant.tenant_id.clone(), state.request_id, ) .await @@ -2355,7 +2355,7 @@ pub async fn delete_card_from_hs_locker<'a>( customer_id, merchant_id, card_reference, - state.tenant.name.clone(), + state.tenant.tenant_id.clone(), state.request_id, ) .await @@ -2980,6 +2980,7 @@ pub async fn list_payment_methods( api_enums::PaymentMethodType::ApplePay, api_enums::PaymentMethodType::Klarna, api_enums::PaymentMethodType::Paypal, + api_enums::PaymentMethodType::SamsungPay, ]); let mut chosen = Vec::::new(); @@ -3031,6 +3032,15 @@ pub async fn list_payment_methods( .connector .connector_name .to_string() + && first_routable_connector + .connector + .merchant_connector_id + .as_ref() + .map(|merchant_connector_id| { + *merchant_connector_id.get_string_repr() + == intermediate.merchant_connector_id + }) + .unwrap_or_default() } else { false } @@ -3774,6 +3784,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 +3845,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, @@ -4068,6 +4080,7 @@ pub async fn filter_payment_methods( let response_pm_type = ResponsePaymentMethodIntermediate::new( payment_method_object, connector.clone(), + mca_id.get_string_repr().to_string(), payment_method, ); resp.push(response_pm_type); diff --git a/crates/router/src/core/payment_methods/migration.rs b/crates/router/src/core/payment_methods/migration.rs index d548d03ab47c..af9e01d253c8 100644 --- a/crates/router/src/core/payment_methods/migration.rs +++ b/crates/router/src/core/payment_methods/migration.rs @@ -1,6 +1,7 @@ -use actix_multipart::form::{bytes::Bytes, MultipartForm}; +use actix_multipart::form::{bytes::Bytes, text::Text, MultipartForm}; use api_models::payment_methods::{PaymentMethodMigrationResponse, PaymentMethodRecord}; use csv::Reader; +use error_stack::ResultExt; use rdkafka::message::ToBytes; use crate::{ @@ -15,12 +16,32 @@ pub async fn migrate_payment_methods( merchant_id: &common_utils::id_type::MerchantId, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, + mca_id: Option, ) -> errors::RouterResponse> { let mut result = Vec::new(); for record in payment_methods { + let req = api::PaymentMethodMigrate::try_from(( + record.clone(), + merchant_id.clone(), + mca_id.clone(), + )) + .map_err(|err| errors::ApiErrorResponse::InvalidRequestData { + message: format!("error: {:?}", err), + }) + .attach_printable("record deserialization failed"); + match req { + Ok(_) => (), + Err(e) => { + result.push(PaymentMethodMigrationResponse::from(( + Err(e.to_string()), + record, + ))); + continue; + } + }; let res = migrate_payment_method( state.clone(), - api::PaymentMethodMigrate::from(record.clone()), + req?, merchant_id, merchant_account, key_store, @@ -42,6 +63,10 @@ pub async fn migrate_payment_methods( pub struct PaymentMethodsMigrateForm { #[multipart(limit = "1MB")] pub file: Bytes, + + pub merchant_id: Text, + + pub merchant_connector_id: Text>, } fn parse_csv(data: &[u8]) -> csv::Result> { @@ -58,26 +83,19 @@ fn parse_csv(data: &[u8]) -> csv::Result> { } pub fn get_payment_method_records( form: PaymentMethodsMigrateForm, -) -> Result<(common_utils::id_type::MerchantId, Vec), errors::ApiErrorResponse> -{ +) -> Result< + ( + common_utils::id_type::MerchantId, + Vec, + Option, + ), + errors::ApiErrorResponse, +> { match parse_csv(form.file.data.to_bytes()) { Ok(records) => { - if let Some(first_record) = records.first() { - if records - .iter() - .all(|merchant_id| merchant_id.merchant_id == first_record.merchant_id) - { - Ok((first_record.merchant_id.clone(), records)) - } else { - Err(errors::ApiErrorResponse::PreconditionFailed { - message: "Only one merchant id can be updated at a time".to_string(), - }) - } - } else { - Err(errors::ApiErrorResponse::PreconditionFailed { - message: "No records found".to_string(), - }) - } + let merchant_id = form.merchant_id.clone(); + let mca_id = form.merchant_connector_id.clone(); + Ok((merchant_id.clone(), records, mca_id)) } Err(e) => Err(errors::ApiErrorResponse::PreconditionFailed { message: e.to_string(), 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 7de4f15adbad..ca1cdf06768d 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 fd45c475b6d5..5d75001b118a 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,12 +1017,11 @@ 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 F: Send + Clone + Sync, - Req: Authenticate + Clone, + Req: Clone, Op: Operation + Send + Sync, D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, { @@ -918,7 +1049,6 @@ where &merchant_account, &profile, &key_store, - auth_flow, &header_payload, ) .await?; @@ -1319,13 +1449,12 @@ pub async fn payments_intent_core( key_store: domain::MerchantKeyStore, operation: Op, req: Req, - auth_flow: services::AuthFlow, header_payload: HeaderPayload, ) -> RouterResponse where F: Send + Clone + Sync, Op: Operation + Send + Sync + Clone, - Req: Debug + Authenticate + Clone, + Req: Debug + Clone, D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, Res: transformers::ToResponse, { @@ -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, @@ -2910,9 +3071,9 @@ where let should_continue = matches!( router_data.response, Ok(router_types::PaymentsResponseData::TransactionResponse { - redirection_data: None, + ref redirection_data, .. - }) + }) if redirection_data.is_none() ) && router_data.status != common_enums::AttemptStatus::AuthenticationFailed; (router_data, should_continue) @@ -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")] @@ -3888,6 +4051,7 @@ pub async fn apply_filters_on_payments( constraints.payment_method_type, constraints.authentication_type, constraints.merchant_connector_id, + constraints.card_network, merchant.storage_scheme, ) .await @@ -4060,6 +4224,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 +4259,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 +4311,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( @@ -4994,21 +5216,15 @@ where })) }, )?; - let mandate_reference_id = - Some(payments_api::MandateReferenceId::ConnectorMandateId( - payments_api::ConnectorMandateReferenceId { - connector_mandate_id: Some( - mandate_reference_record.connector_mandate_id.clone(), - ), - payment_method_id: Some( - payment_method_info.get_id().clone(), - ), - update_history: None, - mandate_metadata: mandate_reference_record - .mandate_metadata - .clone(), - }, - )); + let mandate_reference_id = Some(payments_api::MandateReferenceId::ConnectorMandateId( + api_models::payments::ConnectorMandateReferenceId::new( + Some(mandate_reference_record.connector_mandate_id.clone()), // connector_mandate_id + Some(payment_method_info.get_id().clone()), // payment_method_id + None, // update_history + mandate_reference_record.mandate_metadata.clone(), // mandate_metadata + mandate_reference_record.connector_mandate_request_reference_id.clone(), // connector_mandate_request_reference_id + ) + )); payment_data.set_recurring_mandate_payment_data( hyperswitch_domain_models::router_data::RecurringMandatePaymentData { payment_method_type: mandate_reference_record @@ -5018,9 +5234,8 @@ where original_payment_authorized_currency: mandate_reference_record .original_payment_authorized_currency, mandate_metadata: mandate_reference_record - .mandate_metadata.clone(), + .mandate_metadata.clone() }); - connector_choice = Some((connector_data, mandate_reference_id.clone())); break; } @@ -5298,7 +5513,10 @@ where let routing_choice = choice .first() .ok_or(errors::ApiErrorResponse::InternalServerError)?; - if connector_data.connector.connector_name == routing_choice.connector.connector_name { + if connector_data.connector.connector_name == routing_choice.connector.connector_name + && connector_data.connector.merchant_connector_id + == routing_choice.connector.merchant_connector_id + { final_list.push(connector_data); } } @@ -5358,6 +5576,19 @@ where .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("failed eligibility analysis and fallback")?; + // dynamic success based connector selection + #[cfg(all(feature = "v1", feature = "dynamic_routing"))] + let connectors = { + if business_profile.dynamic_routing_algorithm.is_some() { + routing::perform_success_based_routing(state, connectors.clone(), business_profile) + .await + .map_err(|e| logger::error!(success_rate_routing_error=?e)) + .unwrap_or(connectors) + } else { + connectors + } + }; + let connector_data = connectors .into_iter() .map(|conn| { @@ -6096,6 +6327,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 +6599,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 +6642,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/connector_integration_v2_impls.rs b/crates/router/src/core/payments/connector_integration_v2_impls.rs index 4e900321f95a..10ed62c70c53 100644 --- a/crates/router/src/core/payments/connector_integration_v2_impls.rs +++ b/crates/router/src/core/payments/connector_integration_v2_impls.rs @@ -693,7 +693,6 @@ default_imp_for_new_connector_integration_payment!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -704,7 +703,6 @@ default_imp_for_new_connector_integration_payment!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -712,36 +710,27 @@ default_imp_for_new_connector_integration_payment!( connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Trustpay, connector::Threedsecureio, connector::Wellsfargo, connector::Wellsfargopayout, connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, connector::Plaid ); @@ -765,7 +754,6 @@ default_imp_for_new_connector_integration_refund!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -776,7 +764,6 @@ default_imp_for_new_connector_integration_refund!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -784,35 +771,26 @@ default_imp_for_new_connector_integration_refund!( connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Trustpay, connector::Threedsecureio, connector::Wellsfargo, connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, connector::Plaid ); @@ -831,7 +809,6 @@ default_imp_for_new_connector_integration_connector_access_token!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -842,7 +819,6 @@ default_imp_for_new_connector_integration_connector_access_token!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -850,35 +826,26 @@ default_imp_for_new_connector_integration_connector_access_token!( connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Trustpay, connector::Threedsecureio, connector::Wellsfargo, connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, connector::Plaid ); @@ -919,7 +886,6 @@ default_imp_for_new_connector_integration_accept_dispute!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -930,7 +896,6 @@ default_imp_for_new_connector_integration_accept_dispute!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -938,35 +903,26 @@ default_imp_for_new_connector_integration_accept_dispute!( connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Trustpay, connector::Threedsecureio, connector::Wellsfargo, connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, connector::Plaid ); @@ -989,7 +945,6 @@ default_imp_for_new_connector_integration_defend_dispute!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -1000,7 +955,6 @@ default_imp_for_new_connector_integration_defend_dispute!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1008,42 +962,32 @@ default_imp_for_new_connector_integration_defend_dispute!( connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Trustpay, connector::Threedsecureio, connector::Wellsfargo, connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, connector::Plaid ); default_imp_for_new_connector_integration_submit_evidence!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -1054,7 +998,6 @@ default_imp_for_new_connector_integration_submit_evidence!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1062,35 +1005,26 @@ default_imp_for_new_connector_integration_submit_evidence!( connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Trustpay, connector::Threedsecureio, connector::Wellsfargo, connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, connector::Plaid ); @@ -1124,7 +1058,6 @@ default_imp_for_new_connector_integration_file_upload!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -1135,7 +1068,6 @@ default_imp_for_new_connector_integration_file_upload!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1143,35 +1075,26 @@ default_imp_for_new_connector_integration_file_upload!( connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Trustpay, connector::Threedsecureio, connector::Wellsfargo, connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, connector::Plaid ); @@ -1207,6 +1130,7 @@ default_imp_for_new_connector_integration_payouts!( connector::Digitalvirgo, connector::Dlocal, connector::Ebanx, + connector::Elavon, connector::Fiserv, connector::Fiservemea, connector::Fiuu, @@ -1218,6 +1142,7 @@ default_imp_for_new_connector_integration_payouts!( connector::Helcim, connector::Iatapay, connector::Itaubank, + connector::Jpmorgan, connector::Klarna, connector::Mifinity, connector::Mollie, @@ -1259,7 +1184,6 @@ default_imp_for_new_connector_integration_payouts!( connector::Worldline, connector::Worldpay, connector::Zen, - connector::Zsl, connector::Plaid ); @@ -1285,7 +1209,6 @@ default_imp_for_new_connector_integration_payouts_create!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -1296,7 +1219,6 @@ default_imp_for_new_connector_integration_payouts_create!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1304,35 +1226,26 @@ default_imp_for_new_connector_integration_payouts_create!( connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Trustpay, connector::Threedsecureio, connector::Wellsfargo, connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, connector::Plaid ); @@ -1358,7 +1271,6 @@ default_imp_for_new_connector_integration_payouts_eligibility!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -1369,7 +1281,6 @@ default_imp_for_new_connector_integration_payouts_eligibility!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1377,35 +1288,26 @@ default_imp_for_new_connector_integration_payouts_eligibility!( connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Trustpay, connector::Threedsecureio, connector::Wellsfargo, connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, connector::Plaid ); @@ -1431,7 +1333,6 @@ default_imp_for_new_connector_integration_payouts_fulfill!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -1442,7 +1343,6 @@ default_imp_for_new_connector_integration_payouts_fulfill!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1450,35 +1350,26 @@ default_imp_for_new_connector_integration_payouts_fulfill!( connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Trustpay, connector::Threedsecureio, connector::Wellsfargo, connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, connector::Plaid ); @@ -1504,7 +1395,6 @@ default_imp_for_new_connector_integration_payouts_cancel!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -1515,7 +1405,6 @@ default_imp_for_new_connector_integration_payouts_cancel!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1523,35 +1412,26 @@ default_imp_for_new_connector_integration_payouts_cancel!( connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Trustpay, connector::Threedsecureio, connector::Wellsfargo, connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, connector::Plaid ); @@ -1577,7 +1457,6 @@ default_imp_for_new_connector_integration_payouts_quote!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -1588,7 +1467,6 @@ default_imp_for_new_connector_integration_payouts_quote!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1596,35 +1474,26 @@ default_imp_for_new_connector_integration_payouts_quote!( connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Trustpay, connector::Threedsecureio, connector::Wellsfargo, connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, connector::Plaid ); @@ -1650,7 +1519,6 @@ default_imp_for_new_connector_integration_payouts_recipient!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -1661,7 +1529,6 @@ default_imp_for_new_connector_integration_payouts_recipient!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1669,35 +1536,26 @@ default_imp_for_new_connector_integration_payouts_recipient!( connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Trustpay, connector::Threedsecureio, connector::Wellsfargo, connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, connector::Plaid ); @@ -1723,7 +1581,6 @@ default_imp_for_new_connector_integration_payouts_sync!( connector::Adyenplatform, connector::Aci, connector::Adyen, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -1734,7 +1591,6 @@ default_imp_for_new_connector_integration_payouts_sync!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1742,35 +1598,26 @@ default_imp_for_new_connector_integration_payouts_sync!( connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, connector::Plaid ); @@ -1796,7 +1643,6 @@ default_imp_for_new_connector_integration_payouts_recipient_account!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -1807,7 +1653,6 @@ default_imp_for_new_connector_integration_payouts_recipient_account!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1815,35 +1660,26 @@ default_imp_for_new_connector_integration_payouts_recipient_account!( connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Trustpay, connector::Threedsecureio, connector::Wellsfargo, connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, connector::Plaid ); @@ -1867,7 +1703,6 @@ default_imp_for_new_connector_integration_webhook_source_verification!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -1878,7 +1713,6 @@ default_imp_for_new_connector_integration_webhook_source_verification!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1886,35 +1720,26 @@ default_imp_for_new_connector_integration_webhook_source_verification!( connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Trustpay, connector::Threedsecureio, connector::Wellsfargo, connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, connector::Plaid ); @@ -1950,6 +1775,7 @@ default_imp_for_new_connector_integration_frm!( connector::Digitalvirgo, connector::Dlocal, connector::Ebanx, + connector::Elavon, connector::Fiserv, connector::Fiservemea, connector::Forte, @@ -1961,6 +1787,7 @@ default_imp_for_new_connector_integration_frm!( connector::Helcim, connector::Iatapay, connector::Itaubank, + connector::Jpmorgan, connector::Klarna, connector::Mifinity, connector::Mollie, @@ -2002,7 +1829,6 @@ default_imp_for_new_connector_integration_frm!( connector::Worldline, connector::Worldpay, connector::Zen, - connector::Zsl, connector::Plaid ); @@ -2028,7 +1854,6 @@ default_imp_for_new_connector_integration_frm_sale!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -2039,7 +1864,6 @@ default_imp_for_new_connector_integration_frm_sale!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2047,35 +1871,26 @@ default_imp_for_new_connector_integration_frm_sale!( connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Trustpay, connector::Threedsecureio, connector::Wellsfargo, connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, connector::Plaid ); @@ -2101,7 +1916,6 @@ default_imp_for_new_connector_integration_frm_checkout!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -2112,7 +1926,6 @@ default_imp_for_new_connector_integration_frm_checkout!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2120,35 +1933,26 @@ default_imp_for_new_connector_integration_frm_checkout!( connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Trustpay, connector::Threedsecureio, connector::Wellsfargo, connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, connector::Plaid ); @@ -2174,7 +1978,6 @@ default_imp_for_new_connector_integration_frm_transaction!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -2185,7 +1988,6 @@ default_imp_for_new_connector_integration_frm_transaction!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2193,35 +1995,26 @@ default_imp_for_new_connector_integration_frm_transaction!( connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Trustpay, connector::Threedsecureio, connector::Wellsfargo, connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, connector::Plaid ); @@ -2247,7 +2040,6 @@ default_imp_for_new_connector_integration_frm_fulfillment!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -2258,7 +2050,6 @@ default_imp_for_new_connector_integration_frm_fulfillment!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2266,35 +2057,26 @@ default_imp_for_new_connector_integration_frm_fulfillment!( connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Trustpay, connector::Threedsecureio, connector::Wellsfargo, connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, connector::Plaid ); @@ -2320,7 +2102,6 @@ default_imp_for_new_connector_integration_frm_record_return!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -2331,7 +2112,6 @@ default_imp_for_new_connector_integration_frm_record_return!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2339,35 +2119,26 @@ default_imp_for_new_connector_integration_frm_record_return!( connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Trustpay, connector::Threedsecureio, connector::Wellsfargo, connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, connector::Plaid ); @@ -2390,7 +2161,6 @@ default_imp_for_new_connector_integration_revoking_mandates!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -2401,7 +2171,6 @@ default_imp_for_new_connector_integration_revoking_mandates!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2409,35 +2178,26 @@ default_imp_for_new_connector_integration_revoking_mandates!( connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Trustpay, connector::Threedsecureio, connector::Wellsfargo, connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, connector::Plaid ); @@ -2508,6 +2268,7 @@ default_imp_for_new_connector_integration_connector_authentication!( connector::Digitalvirgo, connector::Dlocal, connector::Ebanx, + connector::Elavon, connector::Fiserv, connector::Fiservemea, connector::Forte, @@ -2519,6 +2280,7 @@ default_imp_for_new_connector_integration_connector_authentication!( connector::Helcim, connector::Iatapay, connector::Itaubank, + connector::Jpmorgan, connector::Klarna, connector::Mifinity, connector::Mollie, diff --git a/crates/router/src/core/payments/flows.rs b/crates/router/src/core/payments/flows.rs index babf393bb3a9..b28f39a51de1 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, @@ -212,26 +212,20 @@ default_imp_for_complete_authorize!( connector::Checkout, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Gocardless, connector::Gpayments, connector::Iatapay, connector::Itaubank, connector::Klarna, 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, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, @@ -239,10 +233,7 @@ default_imp_for_complete_authorize!( connector::Trustpay, connector::Wise, connector::Wellsfargo, - connector::Wellsfargopayout, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wellsfargopayout ); macro_rules! default_imp_for_webhook_source_verification { ($($path:ident::$connector:ident),*) => { @@ -274,7 +265,6 @@ default_imp_for_webhook_source_verification!( connector::Adyenplatform, connector::Aci, connector::Adyen, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -285,7 +275,6 @@ default_imp_for_webhook_source_verification!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -293,36 +282,27 @@ default_imp_for_webhook_source_verification!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, - connector::Shift4, connector::Signifyd, connector::Stripe, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wise ); macro_rules! default_imp_for_create_customer { @@ -356,7 +336,6 @@ default_imp_for_create_customer!( connector::Adyenplatform, connector::Aci, connector::Adyen, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -367,43 +346,33 @@ default_imp_for_create_customer!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gpayments, connector::Iatapay, connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, - connector::Shift4, connector::Signifyd, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wise ); macro_rules! default_imp_for_connector_redirect_response { @@ -445,35 +414,26 @@ default_imp_for_connector_redirect_response!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Gocardless, connector::Gpayments, connector::Iatapay, connector::Itaubank, connector::Klarna, connector::Mifinity, - connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Opayo, connector::Opennode, - connector::Payeezy, connector::Payone, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, connector::Rapyd, - connector::Razorpay, connector::Riskified, - connector::Shift4, connector::Signifyd, connector::Threedsecureio, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zsl + connector::Wise ); macro_rules! default_imp_for_connector_request_id { @@ -489,7 +449,6 @@ impl api::ConnectorTransactionId for connector::DummyConnector { default_imp_for_connector_request_id!( connector::Adyenplatform, - connector::Zsl, connector::Aci, connector::Adyen, connector::Airwallex, @@ -512,6 +471,7 @@ default_imp_for_connector_request_id!( connector::Digitalvirgo, connector::Dlocal, connector::Ebanx, + connector::Elavon, connector::Fiserv, connector::Fiservemea, connector::Fiuu, @@ -522,6 +482,7 @@ default_imp_for_connector_request_id!( connector::Gpayments, connector::Iatapay, connector::Itaubank, + connector::Jpmorgan, connector::Klarna, connector::Mifinity, connector::Mollie, @@ -562,7 +523,8 @@ default_imp_for_connector_request_id!( connector::Wise, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); macro_rules! default_imp_for_accept_dispute { @@ -598,7 +560,6 @@ impl default_imp_for_accept_dispute!( connector::Adyenplatform, connector::Aci, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -608,7 +569,6 @@ default_imp_for_accept_dispute!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -616,37 +576,28 @@ default_imp_for_accept_dispute!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, - connector::Shift4, connector::Signifyd, connector::Stripe, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wise ); macro_rules! default_imp_for_file_upload { @@ -701,7 +652,6 @@ impl default_imp_for_file_upload!( connector::Adyenplatform, connector::Aci, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -711,7 +661,6 @@ default_imp_for_file_upload!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -719,36 +668,27 @@ default_imp_for_file_upload!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, - connector::Shift4, connector::Signifyd, connector::Threedsecureio, connector::Trustpay, connector::Opennode, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wise ); macro_rules! default_imp_for_submit_evidence { @@ -781,7 +721,6 @@ impl default_imp_for_submit_evidence!( connector::Adyenplatform, connector::Aci, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -791,7 +730,6 @@ default_imp_for_submit_evidence!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -799,36 +737,27 @@ default_imp_for_submit_evidence!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, - connector::Shift4, connector::Signifyd, connector::Threedsecureio, connector::Trustpay, connector::Opennode, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wise ); macro_rules! default_imp_for_defend_dispute { @@ -861,7 +790,6 @@ impl default_imp_for_defend_dispute!( connector::Adyenplatform, connector::Aci, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -872,33 +800,26 @@ default_imp_for_defend_dispute!( connector::Datatrans, connector::Ebanx, connector::Globalpay, - connector::Forte, connector::Gocardless, connector::Gpayments, connector::Iatapay, connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, - connector::Shift4, connector::Signifyd, connector::Stripe, connector::Threedsecureio, @@ -906,10 +827,7 @@ default_imp_for_defend_dispute!( connector::Opennode, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wise ); macro_rules! default_imp_for_pre_processing_steps{ @@ -968,35 +886,26 @@ 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Threedsecureio, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wise ); #[cfg(feature = "dummy_connector")] @@ -1014,7 +923,6 @@ impl default_imp_for_post_processing_steps!( connector::Adyenplatform, connector::Adyen, - connector::Airwallex, connector::Bankofamerica, connector::Cybersource, connector::Gocardless, @@ -1022,7 +930,6 @@ default_imp_for_post_processing_steps!( connector::Nuvei, connector::Payme, connector::Paypal, - connector::Shift4, connector::Stripe, connector::Trustpay, connector::Aci, @@ -1036,21 +943,16 @@ 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,11 +961,7 @@ default_imp_for_post_processing_steps!( connector::Threedsecureio, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl, - connector::Razorpay + connector::Wise ); macro_rules! default_imp_for_payouts { @@ -1097,6 +995,7 @@ default_imp_for_payouts!( connector::Deutschebank, connector::Digitalvirgo, connector::Dlocal, + connector::Elavon, connector::Fiserv, connector::Fiservemea, connector::Fiuu, @@ -1108,6 +1007,7 @@ default_imp_for_payouts!( connector::Helcim, connector::Iatapay, connector::Itaubank, + connector::Jpmorgan, connector::Klarna, connector::Mifinity, connector::Mollie, @@ -1132,10 +1032,10 @@ default_imp_for_payouts!( connector::Rapyd, connector::Razorpay, connector::Riskified, + connector::Shift4, connector::Signifyd, connector::Square, connector::Stax, - connector::Shift4, connector::Taxjar, connector::Threedsecureio, connector::Trustpay, @@ -1180,7 +1080,6 @@ impl default_imp_for_payouts_create!( connector::Adyenplatform, connector::Aci, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -1190,7 +1089,6 @@ default_imp_for_payouts_create!( connector::Checkout, connector::Cybersource, connector::Datatrans, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1198,34 +1096,25 @@ default_imp_for_payouts_create!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, connector::Signifyd, - connector::Shift4, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, - connector::Wellsfargopayout, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wellsfargopayout ); #[cfg(feature = "payouts")] @@ -1260,7 +1149,6 @@ default_imp_for_payouts_retrieve!( connector::Adyenplatform, connector::Aci, connector::Adyen, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -1271,7 +1159,6 @@ default_imp_for_payouts_retrieve!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1279,36 +1166,27 @@ default_imp_for_payouts_retrieve!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wise ); #[cfg(feature = "payouts")] @@ -1345,7 +1223,6 @@ impl default_imp_for_payouts_eligibility!( connector::Adyenplatform, connector::Aci, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -1355,7 +1232,6 @@ default_imp_for_payouts_eligibility!( connector::Checkout, connector::Cybersource, connector::Datatrans, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1363,36 +1239,27 @@ default_imp_for_payouts_eligibility!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, - connector::Wellsfargopayout, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wellsfargopayout ); #[cfg(feature = "payouts")] @@ -1425,7 +1292,6 @@ impl #[cfg(feature = "payouts")] default_imp_for_payouts_fulfill!( connector::Aci, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -1434,7 +1300,6 @@ default_imp_for_payouts_fulfill!( connector::Braintree, connector::Checkout, connector::Datatrans, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1442,33 +1307,24 @@ default_imp_for_payouts_fulfill!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, connector::Signifyd, - connector::Shift4, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, - connector::Wellsfargopayout, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wellsfargopayout ); #[cfg(feature = "payouts")] @@ -1502,7 +1358,6 @@ impl default_imp_for_payouts_cancel!( connector::Adyenplatform, connector::Aci, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -1512,7 +1367,6 @@ default_imp_for_payouts_cancel!( connector::Checkout, connector::Cybersource, connector::Datatrans, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1520,35 +1374,26 @@ default_imp_for_payouts_cancel!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, connector::Signifyd, - connector::Shift4, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, - connector::Wellsfargopayout, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wellsfargopayout ); #[cfg(feature = "payouts")] @@ -1583,7 +1428,6 @@ default_imp_for_payouts_quote!( connector::Adyenplatform, connector::Aci, connector::Adyen, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -1593,7 +1437,6 @@ default_imp_for_payouts_quote!( connector::Checkout, connector::Cybersource, connector::Datatrans, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1601,36 +1444,27 @@ default_imp_for_payouts_quote!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, - connector::Wellsfargopayout, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wellsfargopayout ); #[cfg(feature = "payouts")] @@ -1665,7 +1499,6 @@ default_imp_for_payouts_recipient!( connector::Adyenplatform, connector::Aci, connector::Adyen, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -1675,7 +1508,6 @@ default_imp_for_payouts_recipient!( connector::Checkout, connector::Cybersource, connector::Datatrans, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1683,35 +1515,26 @@ default_imp_for_payouts_recipient!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, connector::Signifyd, - connector::Shift4, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, - connector::Wellsfargopayout, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wellsfargopayout ); #[cfg(feature = "payouts")] @@ -1749,7 +1572,6 @@ default_imp_for_payouts_recipient_account!( connector::Adyenplatform, connector::Aci, connector::Adyen, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -1760,7 +1582,6 @@ default_imp_for_payouts_recipient_account!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1768,36 +1589,27 @@ default_imp_for_payouts_recipient_account!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, connector::Signifyd, - connector::Shift4, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wise ); macro_rules! default_imp_for_approve { @@ -1831,7 +1643,6 @@ default_imp_for_approve!( connector::Adyenplatform, connector::Aci, connector::Adyen, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -1842,7 +1653,6 @@ default_imp_for_approve!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1850,37 +1660,28 @@ default_imp_for_approve!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wise ); macro_rules! default_imp_for_reject { @@ -1914,7 +1715,6 @@ default_imp_for_reject!( connector::Adyenplatform, connector::Aci, connector::Adyen, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -1925,7 +1725,6 @@ default_imp_for_reject!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1933,37 +1732,28 @@ default_imp_for_reject!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wise ); macro_rules! default_imp_for_fraud_check { @@ -2001,6 +1791,7 @@ default_imp_for_fraud_check!( connector::Digitalvirgo, connector::Dlocal, connector::Ebanx, + connector::Elavon, connector::Fiserv, connector::Fiservemea, connector::Fiuu, @@ -2012,6 +1803,7 @@ default_imp_for_fraud_check!( connector::Helcim, connector::Iatapay, connector::Itaubank, + connector::Jpmorgan, connector::Klarna, connector::Mifinity, connector::Mollie, @@ -2037,10 +1829,10 @@ default_imp_for_fraud_check!( connector::Prophetpay, connector::Rapyd, connector::Razorpay, + connector::Shift4, connector::Square, connector::Stax, connector::Stripe, - connector::Shift4, connector::Taxjar, connector::Threedsecureio, connector::Trustpay, @@ -2088,7 +1880,6 @@ default_imp_for_frm_sale!( connector::Adyenplatform, connector::Aci, connector::Adyen, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -2099,7 +1890,6 @@ default_imp_for_frm_sale!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2107,35 +1897,26 @@ default_imp_for_frm_sale!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Stripe, - connector::Shift4, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wise ); #[cfg(feature = "frm")] @@ -2171,7 +1952,6 @@ default_imp_for_frm_checkout!( connector::Adyenplatform, connector::Aci, connector::Adyen, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -2182,7 +1962,6 @@ default_imp_for_frm_checkout!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2190,35 +1969,26 @@ default_imp_for_frm_checkout!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Stripe, - connector::Shift4, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wise ); #[cfg(feature = "frm")] @@ -2254,7 +2024,6 @@ default_imp_for_frm_transaction!( connector::Adyenplatform, connector::Aci, connector::Adyen, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -2265,7 +2034,6 @@ default_imp_for_frm_transaction!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2273,35 +2041,26 @@ default_imp_for_frm_transaction!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Stripe, - connector::Shift4, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wise ); #[cfg(feature = "frm")] @@ -2337,7 +2096,6 @@ default_imp_for_frm_fulfillment!( connector::Adyenplatform, connector::Aci, connector::Adyen, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -2348,7 +2106,6 @@ default_imp_for_frm_fulfillment!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2356,35 +2113,26 @@ default_imp_for_frm_fulfillment!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Stripe, - connector::Shift4, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wise ); #[cfg(feature = "frm")] @@ -2420,7 +2168,6 @@ default_imp_for_frm_record_return!( connector::Adyenplatform, connector::Aci, connector::Adyen, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -2431,7 +2178,6 @@ default_imp_for_frm_record_return!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2439,35 +2185,26 @@ default_imp_for_frm_record_return!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Stripe, - connector::Shift4, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wise ); macro_rules! default_imp_for_incremental_authorization { @@ -2501,7 +2238,6 @@ default_imp_for_incremental_authorization!( connector::Adyenplatform, connector::Aci, connector::Adyen, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -2511,7 +2247,6 @@ default_imp_for_incremental_authorization!( connector::Checkout, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2519,36 +2254,27 @@ default_imp_for_incremental_authorization!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wise ); macro_rules! default_imp_for_revoking_mandates { @@ -2580,7 +2306,6 @@ default_imp_for_revoking_mandates!( connector::Adyenplatform, connector::Aci, connector::Adyen, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -2590,7 +2315,6 @@ default_imp_for_revoking_mandates!( connector::Checkout, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2598,34 +2322,25 @@ default_imp_for_revoking_mandates!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Threedsecureio, connector::Trustpay, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wise ); macro_rules! default_imp_for_connector_authentication { @@ -2738,6 +2453,7 @@ default_imp_for_connector_authentication!( connector::Digitalvirgo, connector::Dlocal, connector::Ebanx, + connector::Elavon, connector::Fiserv, connector::Fiservemea, connector::Fiuu, @@ -2748,6 +2464,7 @@ default_imp_for_connector_authentication!( connector::Helcim, connector::Iatapay, connector::Itaubank, + connector::Jpmorgan, connector::Klarna, connector::Mifinity, connector::Mollie, @@ -2773,11 +2490,11 @@ default_imp_for_connector_authentication!( connector::Rapyd, connector::Razorpay, connector::Riskified, + connector::Shift4, connector::Signifyd, connector::Square, connector::Stax, connector::Stripe, - connector::Shift4, connector::Taxjar, connector::Trustpay, connector::Tsys, @@ -2819,7 +2536,6 @@ default_imp_for_authorize_session_token!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -2830,7 +2546,6 @@ default_imp_for_authorize_session_token!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2838,36 +2553,27 @@ default_imp_for_authorize_session_token!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wise ); macro_rules! default_imp_for_calculate_tax { @@ -2899,7 +2605,6 @@ default_imp_for_calculate_tax!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -2910,7 +2615,6 @@ default_imp_for_calculate_tax!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2918,37 +2622,28 @@ default_imp_for_calculate_tax!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wise ); macro_rules! default_imp_for_session_update { @@ -2980,7 +2675,6 @@ default_imp_for_session_update!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -2991,7 +2685,6 @@ default_imp_for_session_update!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2999,36 +2692,27 @@ default_imp_for_session_update!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wise ); macro_rules! default_imp_for_post_session_tokens { @@ -3060,7 +2744,6 @@ default_imp_for_post_session_tokens!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, connector::Authorizedotnet, connector::Bamboraapac, connector::Bankofamerica, @@ -3071,7 +2754,6 @@ default_imp_for_post_session_tokens!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -3079,34 +2761,25 @@ default_imp_for_post_session_tokens!( connector::Itaubank, connector::Klarna, 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, connector::Rapyd, - connector::Razorpay, connector::Riskified, connector::Signifyd, connector::Stripe, - connector::Shift4, connector::Threedsecureio, connector::Trustpay, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldpay, - connector::Zen, - connector::Zsl + connector::Wise ); diff --git a/crates/router/src/core/payments/flows/approve_flow.rs b/crates/router/src/core/payments/flows/approve_flow.rs index c91de9eb3a7f..98d204d52643 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 03b2a3153ea5..09a6fb519248 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 1f212cc631be..9c5bc84a6218 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 8f326aa1bcf2..aaa245a341f0 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 0e27e4f37ad7..24f6d8d07545 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 7a3f9f0ac44c..a187146903e7 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 fe83090d795e..13738480c907 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 2bb8fc190830..34ebfdf4bad0 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 3dc4783d37e7..43163c1374b8 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 31027bc8c526..ba8054696a11 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 @@ -511,7 +511,13 @@ fn create_paze_session_token( field_name: "connector_wallets_details".to_string(), expected_format: "paze_metadata_format".to_string(), })?; - + let required_amount_type = StringMajorUnitForConnector; + let transaction_currency_code = router_data.request.currency; + let transaction_amount = required_amount_type + .convert(router_data.request.minor_amount, transaction_currency_code) + .change_context(errors::ApiErrorResponse::PreconditionFailed { + message: "Failed to convert amount to string major unit for paze".to_string(), + })?; Ok(types::PaymentsSessionRouterData { response: Ok(types::PaymentsResponseData::SessionResponse { session_token: payment_types::SessionToken::Paze(Box::new( @@ -519,6 +525,9 @@ fn create_paze_session_token( client_id: paze_wallet_details.data.client_id, client_name: paze_wallet_details.data.client_name, client_profile_id: paze_wallet_details.data.client_profile_id, + transaction_currency_code, + transaction_amount, + email_address: router_data.request.email.clone(), }, )), }), @@ -528,7 +537,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 +691,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 +940,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 +989,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 6cad2500814c..e48f90d1bb6a 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 69720b870a26..2cee81115d64 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 27d73d0df46d..5a8bc5cd12bd 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -1,12 +1,9 @@ use std::{borrow::Cow, str::FromStr}; -#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] -use api_models::customers::CustomerRequestWithEmail; use api_models::{ mandates::RecurringDetails, payments::{ - additional_info as payment_additional_types, AddressDetailsWithPhone, PaymentChargeRequest, - RequestSurchargeDetails, + additional_info as payment_additional_types, PaymentChargeRequest, RequestSurchargeDetails, }, }; use base64::Engine; @@ -39,7 +36,7 @@ use hyperswitch_domain_models::{ }; use hyperswitch_interfaces::integrity::{CheckIntegrity, FlowIntegrity, GetIntegrityObject}; use josekit::jwe; -use masking::{ExposeInterface, PeekInterface}; +use masking::{ExposeInterface, PeekInterface, SwitchStrategy}; use openssl::{ derive::Deriver, pkey::PKey, @@ -126,16 +123,33 @@ pub async fn create_or_update_address_for_payment_by_request( let encrypted_data = types::crypto_operation( &session_state.into(), type_name!(domain::Address), - types::CryptoOperation::BatchEncrypt(AddressDetailsWithPhone::to_encryptable( - AddressDetailsWithPhone { - address: address.address.clone(), - phone_number: address - .phone - .as_ref() - .and_then(|phone| phone.number.clone()), - email: address.email.clone(), - }, - )), + types::CryptoOperation::BatchEncrypt( + domain::FromRequestEncryptableAddress::to_encryptable( + domain::FromRequestEncryptableAddress { + line1: address.address.as_ref().and_then(|a| a.line1.clone()), + line2: address.address.as_ref().and_then(|a| a.line2.clone()), + line3: address.address.as_ref().and_then(|a| a.line3.clone()), + state: address.address.as_ref().and_then(|a| a.state.clone()), + first_name: address + .address + .as_ref() + .and_then(|a| a.first_name.clone()), + last_name: address + .address + .as_ref() + .and_then(|a| a.last_name.clone()), + zip: address.address.as_ref().and_then(|a| a.zip.clone()), + phone_number: address + .phone + .as_ref() + .and_then(|phone| phone.number.clone()), + email: address + .email + .as_ref() + .map(|a| a.clone().expose().switch_strategy()), + }, + ), + ), Identifier::Merchant(merchant_key_store.merchant_id.clone()), key, ) @@ -143,9 +157,10 @@ pub async fn create_or_update_address_for_payment_by_request( .and_then(|val| val.try_into_batchoperation()) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed while encrypting address")?; - let encryptable_address = AddressDetailsWithPhone::from_encryptable(encrypted_data) - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Failed while encrypting address")?; + let encryptable_address = + domain::FromRequestEncryptableAddress::from_encryptable(encrypted_data) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed while encrypting address")?; let address_update = storage::AddressUpdate::Update { city: address .address @@ -165,7 +180,14 @@ pub async fn create_or_update_address_for_payment_by_request( .as_ref() .and_then(|value| value.country_code.clone()), updated_by: storage_scheme.to_string(), - email: encryptable_address.email, + email: encryptable_address.email.map(|email| { + let encryptable: Encryptable> = + Encryptable::new( + email.clone().into_inner().switch_strategy(), + email.into_encrypted(), + ); + encryptable + }), }; let address = db .find_address_by_merchant_id_payment_id_address_id( @@ -317,23 +339,35 @@ pub async fn get_domain_address( let encrypted_data = types::crypto_operation( &session_state.into(), type_name!(domain::Address), - types::CryptoOperation::BatchEncrypt(AddressDetailsWithPhone::to_encryptable( - AddressDetailsWithPhone { - address: address_details.cloned(), - phone_number: address - .phone - .as_ref() - .and_then(|phone| phone.number.clone()), - email: address.email.clone(), - }, - )), + types::CryptoOperation::BatchEncrypt( + domain::FromRequestEncryptableAddress::to_encryptable( + domain::FromRequestEncryptableAddress { + line1: address.address.as_ref().and_then(|a| a.line1.clone()), + line2: address.address.as_ref().and_then(|a| a.line2.clone()), + line3: address.address.as_ref().and_then(|a| a.line3.clone()), + state: address.address.as_ref().and_then(|a| a.state.clone()), + first_name: address.address.as_ref().and_then(|a| a.first_name.clone()), + last_name: address.address.as_ref().and_then(|a| a.last_name.clone()), + zip: address.address.as_ref().and_then(|a| a.zip.clone()), + phone_number: address + .phone + .as_ref() + .and_then(|phone| phone.number.clone()), + email: address + .email + .as_ref() + .map(|a| a.clone().expose().switch_strategy()), + }, + ), + ), Identifier::Merchant(merchant_id.to_owned()), key, ) .await .and_then(|val| val.try_into_batchoperation())?; - let encryptable_address = AddressDetailsWithPhone::from_encryptable(encrypted_data) - .change_context(common_utils::errors::CryptoError::EncodingFailed)?; + let encryptable_address = + domain::FromRequestEncryptableAddress::from_encryptable(encrypted_data) + .change_context(common_utils::errors::CryptoError::EncodingFailed)?; Ok(domain::Address { phone_number: encryptable_address.phone_number, country_code: address.phone.as_ref().and_then(|a| a.country_code.clone()), @@ -351,7 +385,14 @@ pub async fn get_domain_address( modified_at: common_utils::date_time::now(), zip: encryptable_address.zip, updated_by: storage_scheme.to_string(), - email: encryptable_address.email, + email: encryptable_address.email.map(|email| { + let encryptable: Encryptable> = + Encryptable::new( + email.clone().into_inner().switch_strategy(), + email.into_encrypted(), + ); + encryptable + }), }) } .await @@ -385,19 +426,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 +1196,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 +1222,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 +1236,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 +1248,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 +1377,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 +1449,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 +1467,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)] @@ -1598,13 +1630,18 @@ pub async fn create_customer_if_not_exist<'a, F: Clone, R, D>( let encrypted_data = types::crypto_operation( key_manager_state, type_name!(domain::Customer), - types::CryptoOperation::BatchEncrypt(CustomerRequestWithEmail::to_encryptable( - CustomerRequestWithEmail { - name: request_customer_details.name.clone(), - email: request_customer_details.email.clone(), - phone: request_customer_details.phone.clone(), - }, - )), + types::CryptoOperation::BatchEncrypt( + domain::FromRequestEncryptableCustomer::to_encryptable( + domain::FromRequestEncryptableCustomer { + name: request_customer_details.name.clone(), + email: request_customer_details + .email + .as_ref() + .map(|e| e.clone().expose().switch_strategy()), + phone: request_customer_details.phone.clone(), + }, + ), + ), Identifier::Merchant(key_store.merchant_id.clone()), key, ) @@ -1612,9 +1649,10 @@ pub async fn create_customer_if_not_exist<'a, F: Clone, R, D>( .and_then(|val| val.try_into_batchoperation()) .change_context(errors::StorageError::SerializationFailed) .attach_printable("Failed while encrypting Customer while Update")?; - let encryptable_customer = CustomerRequestWithEmail::from_encryptable(encrypted_data) - .change_context(errors::StorageError::SerializationFailed) - .attach_printable("Failed while encrypting Customer while Update")?; + let encryptable_customer = + domain::FromRequestEncryptableCustomer::from_encryptable(encrypted_data) + .change_context(errors::StorageError::SerializationFailed) + .attach_printable("Failed while encrypting Customer while Update")?; Some(match customer_data { Some(c) => { // Update the customer data if new data is passed in the request @@ -1625,11 +1663,19 @@ pub async fn create_customer_if_not_exist<'a, F: Clone, R, D>( { let customer_update = Update { name: encryptable_customer.name, - email: encryptable_customer.email, + email: encryptable_customer.email.map(|email| { + let encryptable: Encryptable< + masking::Secret, + > = Encryptable::new( + email.clone().into_inner().switch_strategy(), + email.into_encrypted(), + ); + encryptable + }), phone: Box::new(encryptable_customer.phone), phone_country_code: request_customer_details.phone_country_code, description: None, - connector_customer: None, + connector_customer: Box::new(None), metadata: None, address_id: None, }; @@ -1653,7 +1699,15 @@ pub async fn create_customer_if_not_exist<'a, F: Clone, R, D>( customer_id, merchant_id: merchant_id.to_owned(), name: encryptable_customer.name, - email: encryptable_customer.email, + email: encryptable_customer.email.map(|email| { + let encryptable: Encryptable< + masking::Secret, + > = Encryptable::new( + email.clone().into_inner().switch_strategy(), + email.into_encrypted(), + ); + encryptable + }), phone: encryptable_customer.phone, phone_country_code: request_customer_details.phone_country_code.clone(), description: None, @@ -1707,6 +1761,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 +2585,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 @@ -3588,7 +3644,7 @@ pub async fn insert_merchant_connector_creds_to_config( #[derive(Clone)] pub enum MerchantConnectorAccountType { - DbVal(domain::MerchantConnectorAccount), + DbVal(Box), CacheVal(api_models::admin::MerchantConnectorDetails), } @@ -3765,14 +3821,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")] @@ -3798,7 +3858,7 @@ pub async fn get_merchant_connector_account( todo!() } }; - mca.map(MerchantConnectorAccountType::DbVal) + mca.map(Box::new).map(MerchantConnectorAccountType::DbVal) } } } @@ -3861,14 +3921,16 @@ pub fn router_data_type_conversion( connector_wallets_details: router_data.connector_wallets_details, additional_merchant_data: router_data.additional_merchant_data, header_payload: router_data.header_payload, + connector_mandate_request_reference_id: router_data.connector_mandate_request_reference_id, } } +#[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 +4137,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 +4224,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 +4769,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, @@ -5445,13 +5509,13 @@ pub async fn get_unified_translation( } pub fn validate_order_details_amount( order_details: Vec, - amount: i64, + amount: MinorUnit, should_validate: bool, ) -> Result<(), errors::ApiErrorResponse> { if should_validate { - let total_order_details_amount: i64 = order_details + let total_order_details_amount: MinorUnit = order_details .iter() - .map(|order| order.amount * i64::from(order.quantity)) + .map(|order| order.amount * order.quantity) .sum(); if total_order_details_amount != amount { diff --git a/crates/router/src/core/payments/operations.rs b/crates/router/src/core/payments/operations.rs index 56b198c5381b..b03f41ac0fd1 100644 --- a/crates/router/src/core/payments/operations.rs +++ b/crates/router/src/core/payments/operations.rs @@ -28,8 +28,12 @@ pub mod payments_incremental_authorization; #[cfg(feature = "v1")] pub mod tax_calculation; +#[cfg(feature = "v2")] +pub mod payment_confirm_intent; #[cfg(feature = "v2")] pub mod payment_create_intent; +#[cfg(feature = "v2")] +pub mod payment_get_intent; use api_models::enums::FrmSuggestion; #[cfg(all(feature = "v1", feature = "dynamic_routing"))] @@ -39,7 +43,11 @@ 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; +#[cfg(feature = "v2")] +pub use self::payment_get_intent::PaymentGetIntent; pub use self::payment_response::PaymentResponse; #[cfg(feature = "v1")] pub use self::{ @@ -149,9 +157,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 +171,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 +186,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 +318,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 +330,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 +757,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 e8814c7e56e5..fe5e7a7e72f3 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 c84dcc50e6d4..8d7361cd257e 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 93a79e2d2e30..2451cbcd8e9d 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 e705c64d6e0f..850fa738cd84 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 ca32be35e550..1bd3ddce7351 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -1,16 +1,17 @@ use std::marker::PhantomData; +// use api_models::{admin::ExtendedCardInfoConfig, enums::FrmSuggestion, payments::ExtendedCardInfo}; +#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] +use api_models::payment_methods::PaymentMethodsData; use api_models::{ admin::ExtendedCardInfoConfig, enums::FrmSuggestion, // payment_methods::PaymentMethodsData, - payments::{ExtendedCardInfo, GetAddressFromPaymentMethodData}, + payments::{ConnectorMandateReferenceId, ExtendedCardInfo, GetAddressFromPaymentMethodData}, }; -// use api_models::{admin::ExtendedCardInfoConfig, enums::FrmSuggestion, payments::ExtendedCardInfo}; -#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] -use api_models::{payment_methods::PaymentMethodsData, payments::AdditionalPaymentData}; use async_trait::async_trait; use common_utils::ext_traits::{AsyncExt, Encode, StringExt, ValueExt}; +use diesel_models::payment_attempt::ConnectorMandateReferenceId as DieselConnectorMandateReferenceId; use error_stack::{report, ResultExt}; use futures::FutureExt; #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] @@ -23,6 +24,7 @@ use tracing_futures::Instrument; use super::{BoxedOperation, Domain, GetTracker, Operation, UpdateTracker, ValidateRequest}; #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] use crate::{ + consts, core::payment_methods::cards::create_encrypted_data, events::audit_events::{AuditEvent, AuditEventType}, }; @@ -45,6 +47,7 @@ use crate::{ api::{self, ConnectorCallType, PaymentIdTypeExt}, domain::{self}, storage::{self, enums as storage_enums}, + transformers::ForeignFrom, }, utils::{self, OptionExt}, }; @@ -66,7 +69,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(); @@ -98,7 +101,7 @@ impl GetTracker, api::PaymentsRequest> for Pa if let Some(order_details) = &request.order_details { helpers::validate_order_details_amount( order_details.to_owned(), - payment_intent.amount.get_amount_as_i64(), + payment_intent.amount, false, )?; } @@ -573,6 +576,39 @@ impl GetTracker, api::PaymentsRequest> for Pa payment_method_info, } = mandate_details; + let additional_pm_data_from_locker = if let Some(ref pm) = payment_method_info { + let card_detail_from_locker: Option = pm + .payment_method_data + .clone() + .map(|x| x.into_inner().expose()) + .and_then(|v| { + v.parse_value("PaymentMethodsData") + .map_err(|err| { + router_env::logger::info!( + "PaymentMethodsData deserialization failed: {:?}", + err + ) + }) + .ok() + }) + .and_then(|pmd| match pmd { + PaymentMethodsData::Card(crd) => Some(api::CardDetailFromLocker::from(crd)), + _ => None, + }); + card_detail_from_locker.map(|card_details| { + let additional_data = card_details.into(); + api_models::payments::AdditionalPaymentData::Card(Box::new(additional_data)) + }) + } else { + None + }; + payment_attempt.payment_method_data = additional_pm_data_from_locker + .as_ref() + .map(Encode::encode_to_value) + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed to encode additional pm data")?; + payment_attempt.payment_method = payment_method.or(payment_attempt.payment_method); payment_attempt.payment_method_type = payment_method_type @@ -679,14 +715,13 @@ impl GetTracker, api::PaymentsRequest> for Pa mandate_id: None, mandate_reference_id: Some( api_models::payments::MandateReferenceId::ConnectorMandateId( - api_models::payments::ConnectorMandateReferenceId { - connector_mandate_id: Some( - token.processor_payment_token.clone(), - ), - payment_method_id: None, - update_history: None, - mandate_metadata: None, - }, + ConnectorMandateReferenceId::new( + Some(token.processor_payment_token.clone()), // connector_mandate_id + None, // payment_method_id + None, // update_history + None, // mandate_metadata + None, // connector_mandate_request_reference_id + ), ), ), }) @@ -714,6 +749,17 @@ impl GetTracker, api::PaymentsRequest> for Pa .net_amount .set_order_tax_amount(order_tax_amount); + payment_attempt.connector_mandate_detail = Some( + DieselConnectorMandateReferenceId::foreign_from(ConnectorMandateReferenceId::new( + None, + None, + None, // update_history + None, // mandate_metadata + Some(common_utils::generate_id_with_len( + consts::CONNECTOR_MANDATE_REQUEST_REFERENCE_ID_LENGTH.to_owned(), + )), // connector_mandate_request_reference_id + )), + ); let payment_data = PaymentData { flow: PhantomData, payment_intent, @@ -1065,7 +1111,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 +1137,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, @@ -1198,31 +1244,6 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed to encode additional pm data")?; - let encode_additional_pm_to_value = if let Some(ref pm) = payment_data.payment_method_info { - let card_detail_from_locker: Option = pm - .payment_method_data - .clone() - .map(|x| x.into_inner().expose()) - .and_then(|v| serde_json::from_value::(v).ok()) - .and_then(|pmd| match pmd { - PaymentMethodsData::Card(crd) => Some(api::CardDetailFromLocker::from(crd)), - _ => None, - }); - - card_detail_from_locker.and_then(|card_details| { - let additional_data = card_details.into(); - let additional_data_payment = - AdditionalPaymentData::Card(Box::new(additional_data)); - additional_data_payment - .encode_to_value() - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Failed to encode additional pm data") - .ok() - }) - } else { - None - }; - let customer_details = payment_data.payment_intent.customer_details.clone(); let business_sub_label = payment_data.payment_attempt.business_sub_label.clone(); let authentication_type = payment_data.payment_attempt.authentication_type; @@ -1278,7 +1299,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen let m_payment_token = payment_token.clone(); let m_additional_pm_data = encoded_additional_pm_data .clone() - .or(encode_additional_pm_to_value); + .or(payment_data.payment_attempt.payment_method_data); let m_business_sub_label = business_sub_label.clone(); let m_straight_through_algorithm = straight_through_algorithm.clone(); let m_error_code = error_code.clone(); @@ -1350,6 +1371,9 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen surcharge_amount, tax_amount, ), + connector_mandate_detail: payment_data + .payment_attempt + .connector_mandate_detail, }, storage_scheme, ) @@ -1496,7 +1520,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen .event(AuditEvent::new(AuditEventType::PaymentConfirm { client_src, client_ver, - frm_message, + frm_message: Box::new(frm_message), })) .with(payment_data.to_event()) .emit(); 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 000000000000..083bb5adca28 --- /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 fc1f71c2085d..d4057c523bc6 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -13,13 +13,16 @@ use common_utils::{ MinorUnit, }, }; -use diesel_models::ephemeral_key; +use diesel_models::{ + ephemeral_key, + payment_attempt::ConnectorMandateReferenceId as DieselConnectorMandateReferenceId, +}; use error_stack::{self, ResultExt}; use hyperswitch_domain_models::{ mandates::{MandateData, MandateDetails}, payments::{ - payment_attempt::PaymentAttempt, - payment_intent::{CustomerData, PaymentAddressFromRequest}, + payment_attempt::PaymentAttempt, payment_intent::CustomerData, + FromRequestEncryptablePaymentIntent, }, }; use masking::{ExposeInterface, PeekInterface, Secret}; @@ -49,7 +52,7 @@ use crate::{ self, enums::{self, IntentStatus}, }, - transformers::ForeignTryFrom, + transformers::{ForeignFrom, ForeignTryFrom}, }, utils::{self, OptionExt}, }; @@ -73,7 +76,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; @@ -338,13 +341,13 @@ impl GetTracker, api::PaymentsRequest> for Pa if let Some(order_details) = &request.order_details { helpers::validate_order_details_amount( order_details.to_owned(), - payment_intent.amount.get_amount_as_i64(), + payment_intent.amount, false, )?; } #[cfg(feature = "v1")] - let payment_attempt = db + let mut payment_attempt = db .insert_payment_attempt(payment_attempt_new, storage_scheme) .await .to_duplicate_response(errors::ApiErrorResponse::DuplicatePayment { @@ -399,12 +402,13 @@ impl GetTracker, api::PaymentsRequest> for Pa api_models::payments::MandateIds { mandate_id: Some(mandate_obj.mandate_id), mandate_reference_id: Some(api_models::payments::MandateReferenceId::ConnectorMandateId( - api_models::payments::ConnectorMandateReferenceId{ - connector_mandate_id: connector_id.connector_mandate_id, - payment_method_id: connector_id.payment_method_id, - update_history: None, - mandate_metadata: None, - } + api_models::payments::ConnectorMandateReferenceId::new( + connector_id.get_connector_mandate_id(), + connector_id.get_payment_method_id(), + None, + None, + connector_id.get_connector_mandate_request_reference_id(), + ) )) } }), @@ -436,14 +440,13 @@ impl GetTracker, api::PaymentsRequest> for Pa mandate_id: None, mandate_reference_id: Some( api_models::payments::MandateReferenceId::ConnectorMandateId( - api_models::payments::ConnectorMandateReferenceId { - connector_mandate_id: Some( - token.processor_payment_token.clone(), - ), - payment_method_id: None, - update_history: None, - mandate_metadata: None, - }, + api_models::payments::ConnectorMandateReferenceId::new( + Some(token.processor_payment_token.clone()), + None, + None, + None, + None, + ), ), ), }) @@ -500,8 +503,55 @@ impl GetTracker, api::PaymentsRequest> for Pa .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Card cobadge check failed due to an invalid card network regex")?; + let additional_pm_data_from_locker = if let Some(ref pm) = payment_method_info { + let card_detail_from_locker: Option = pm + .payment_method_data + .clone() + .map(|x| x.into_inner().expose()) + .and_then(|v| { + v.parse_value("PaymentMethodsData") + .map_err(|err| { + router_env::logger::info!( + "PaymentMethodsData deserialization failed: {:?}", + err + ) + }) + .ok() + }) + .and_then(|pmd| match pmd { + PaymentMethodsData::Card(crd) => Some(api::CardDetailFromLocker::from(crd)), + _ => None, + }); + + card_detail_from_locker.map(|card_details| { + let additional_data = card_details.into(); + api_models::payments::AdditionalPaymentData::Card(Box::new(additional_data)) + }) + } else { + None + }; + + payment_attempt.payment_method_data = additional_pm_data_from_locker + .as_ref() + .map(Encode::encode_to_value) + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed to encode additional pm data")?; let amount = payment_attempt.get_total_amount().into(); + payment_attempt.connector_mandate_detail = + Some(DieselConnectorMandateReferenceId::foreign_from( + api_models::payments::ConnectorMandateReferenceId::new( + None, + None, + None, // update_history + None, // mandate_metadata + Some(common_utils::generate_id_with_len( + consts::CONNECTOR_MANDATE_REQUEST_REFERENCE_ID_LENGTH.to_owned(), + )), // connector_mandate_request_reference_id + ), + )); + let address = PaymentAddress::new( shipping_address.as_ref().map(From::from), billing_address.as_ref().map(From::from), @@ -775,7 +825,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, @@ -955,7 +1005,11 @@ impl ValidateRequest> f helpers::validate_customer_id_mandatory_cases( request.setup_future_usage.is_some(), - request.customer_id.as_ref(), + request.customer_id.as_ref().or(request + .customer + .as_ref() + .map(|customer| customer.id.clone()) + .as_ref()), )?; } @@ -1336,11 +1390,13 @@ impl PaymentCreate { &key_manager_state, type_name!(storage::PaymentIntent), domain::types::CryptoOperation::BatchEncrypt( - PaymentAddressFromRequest::to_encryptable(PaymentAddressFromRequest { - shipping: shipping_details_encoded, - billing: billing_details_encoded, - customer_details: customer_details_encoded, - }), + FromRequestEncryptablePaymentIntent::to_encryptable( + FromRequestEncryptablePaymentIntent { + shipping_details: shipping_details_encoded, + billing_details: billing_details_encoded, + customer_details: customer_details_encoded, + }, + ), ), identifier.clone(), key, @@ -1350,7 +1406,7 @@ impl PaymentCreate { .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Unable to encrypt data")?; - let encrypted_data = PaymentAddressFromRequest::from_encryptable(encrypted_data) + let encrypted_data = FromRequestEncryptablePaymentIntent::from_encryptable(encrypted_data) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Unable to encrypt the payment intent data")?; @@ -1403,10 +1459,10 @@ impl PaymentCreate { .request_external_three_ds_authentication, charges, frm_metadata: request.frm_metadata.clone(), - billing_details: encrypted_data.billing, + billing_details: encrypted_data.billing_details, customer_details: encrypted_data.customer_details, merchant_order_reference_id: request.merchant_order_reference_id.clone(), - shipping_details: encrypted_data.shipping, + shipping_details: encrypted_data.shipping_details, is_payment_processor_token_flow, organization_id: merchant_account.organization_id.clone(), shipping_cost: request.shipping_cost, 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 c0b66b444689..bd82a67e6270 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_get_intent.rs b/crates/router/src/core/payments/operations/payment_get_intent.rs new file mode 100644 index 000000000000..55ddc3b482a6 --- /dev/null +++ b/crates/router/src/core/payments/operations/payment_get_intent.rs @@ -0,0 +1,231 @@ +use std::marker::PhantomData; + +use api_models::{enums::FrmSuggestion, payments::PaymentsGetIntentRequest}; +use async_trait::async_trait; +use common_utils::errors::CustomResult; +use router_env::{instrument, tracing}; + +use super::{BoxedOperation, Domain, GetTracker, Operation, UpdateTracker, ValidateRequest}; +use crate::{ + core::{ + errors::{self, RouterResult}, + payments::{self, helpers, operations}, + }, + db::errors::StorageErrorExt, + routes::{app::ReqState, SessionState}, + types::{ + api, domain, + storage::{self, enums}, + }, +}; + +#[derive(Debug, Clone, Copy)] +pub struct PaymentGetIntent; + +impl Operation for &PaymentGetIntent { + type Data = payments::PaymentIntentData; + 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 Operation for PaymentGetIntent { + type Data = payments::PaymentIntentData; + 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) + } +} + +type PaymentsGetIntentOperation<'b, F> = + BoxedOperation<'b, F, PaymentsGetIntentRequest, payments::PaymentIntentData>; + +#[async_trait] +impl GetTracker, PaymentsGetIntentRequest> + for PaymentGetIntent +{ + #[instrument(skip_all)] + async fn get_trackers<'a>( + &'a self, + state: &'a SessionState, + _payment_id: &common_utils::id_type::GlobalPaymentId, + request: &PaymentsGetIntentRequest, + merchant_account: &domain::MerchantAccount, + _profile: &domain::Profile, + key_store: &domain::MerchantKeyStore, + _header_payload: &hyperswitch_domain_models::payments::HeaderPayload, + ) -> RouterResult< + operations::GetTrackerResponse< + 'a, + F, + PaymentsGetIntentRequest, + payments::PaymentIntentData, + >, + > { + 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, &request.id, key_store, storage_scheme) + .await + .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?; + + let payment_data = payments::PaymentIntentData { + flow: PhantomData, + payment_intent, + }; + + let get_trackers_response = operations::GetTrackerResponse { + operation: Box::new(self), + payment_data, + }; + + Ok(get_trackers_response) + } +} + +#[async_trait] +impl UpdateTracker, PaymentsGetIntentRequest> + for PaymentGetIntent +{ + #[instrument(skip_all)] + async fn update_trackers<'b>( + &'b self, + _state: &'b SessionState, + _req_state: ReqState, + payment_data: payments::PaymentIntentData, + _customer: Option, + _storage_scheme: enums::MerchantStorageScheme, + _updated_customer: Option, + _key_store: &domain::MerchantKeyStore, + _frm_suggestion: Option, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, + ) -> RouterResult<( + PaymentsGetIntentOperation<'b, F>, + payments::PaymentIntentData, + )> + where + F: 'b + Send, + { + Ok((Box::new(self), payment_data)) + } +} + +impl ValidateRequest> + for PaymentGetIntent +{ + #[instrument(skip_all)] + fn validate_request<'a, 'b>( + &'b self, + _request: &PaymentsGetIntentRequest, + merchant_account: &'a domain::MerchantAccount, + ) -> RouterResult<( + PaymentsGetIntentOperation<'b, F>, + operations::ValidateResult, + )> { + Ok(( + Box::new(self), + operations::ValidateResult { + merchant_id: merchant_account.get_id().to_owned(), + storage_scheme: merchant_account.storage_scheme, + requeue: false, + }, + )) + } +} + +#[async_trait] +impl Domain> + for PaymentGetIntent +{ + #[instrument(skip_all)] + async fn get_customer_details<'a>( + &'a self, + state: &SessionState, + payment_data: &mut payments::PaymentIntentData, + merchant_key_store: &domain::MerchantKeyStore, + storage_scheme: enums::MerchantStorageScheme, + ) -> CustomResult< + ( + BoxedOperation<'a, F, PaymentsGetIntentRequest, payments::PaymentIntentData>, + Option, + ), + errors::StorageError, + > { + Ok((Box::new(self), None)) + } + + #[instrument(skip_all)] + async fn make_pm_data<'a>( + &'a self, + _state: &'a SessionState, + _payment_data: &mut payments::PaymentIntentData, + _storage_scheme: enums::MerchantStorageScheme, + _merchant_key_store: &domain::MerchantKeyStore, + _customer: &Option, + _business_profile: &domain::Profile, + ) -> RouterResult<( + PaymentsGetIntentOperation<'a, F>, + Option, + Option, + )> { + Ok((Box::new(self), None, None)) + } + + async fn get_connector<'a>( + &'a self, + _merchant_account: &domain::MerchantAccount, + state: &SessionState, + _request: &PaymentsGetIntentRequest, + _payment_intent: &storage::PaymentIntent, + _merchant_key_store: &domain::MerchantKeyStore, + ) -> CustomResult { + helpers::get_connector_default(state, None).await + } + + #[instrument(skip_all)] + async fn guard_payment_against_blocklist<'a>( + &'a self, + _state: &SessionState, + _merchant_account: &domain::MerchantAccount, + _key_store: &domain::MerchantKeyStore, + _payment_data: &mut payments::PaymentIntentData, + ) -> CustomResult { + Ok(false) + } +} 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 81702979ac40..846f739e0823 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 2257ff0402c1..55b935012758 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 3bb6647b527c..0234b97032c7 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, @@ -181,7 +181,11 @@ impl PostUpdateTracker, types::PaymentsAuthor .ok(); } }; - + let connector_mandate_reference_id = payment_data + .payment_attempt + .connector_mandate_detail + .as_ref() + .map(|detail| ConnectorMandateReferenceId::foreign_from(detail.clone())); let save_payment_call_future = Box::pin(tokenization::save_payment_method( state, connector_name.clone(), @@ -193,6 +197,7 @@ impl PostUpdateTracker, types::PaymentsAuthor billing_name.clone(), payment_method_billing_address, business_profile, + connector_mandate_reference_id.clone(), )); let is_connector_mandate = resp.request.customer_acceptance.is_some() @@ -307,6 +312,7 @@ impl PostUpdateTracker, types::PaymentsAuthor billing_name, payment_method_billing_address.as_ref(), &business_profile, + connector_mandate_reference_id, )) .await; @@ -365,7 +371,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 +537,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 +552,6 @@ impl PostUpdateTracker, types::PaymentsSyncData> for { Box::pin(payment_response_update_tracker( db, - payment_id, payment_data, router_data, key_store, @@ -574,7 +577,7 @@ impl PostUpdateTracker, types::PaymentsSyncData> for where F: 'b + Clone + Send + Sync, { - let (connector_mandate_id, mandate_metadata) = resp + let (connector_mandate_id, mandate_metadata, connector_mandate_request_reference_id) = resp .response .clone() .ok() @@ -587,17 +590,19 @@ impl PostUpdateTracker, types::PaymentsSyncData> for ( mandate_ref.connector_mandate_id.clone(), mandate_ref.mandate_metadata.clone(), + mandate_ref.connector_mandate_request_reference_id.clone(), ) }) } else { None } }) - .unwrap_or((None, None)); + .unwrap_or((None, None, None)); update_connector_mandate_details_for_the_flow( connector_mandate_id, mandate_metadata, + connector_mandate_request_reference_id, payment_data, )?; @@ -623,7 +628,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 +643,6 @@ impl PostUpdateTracker, types::PaymentsSessionData> { payment_data = Box::pin(payment_response_update_tracker( db, - payment_id, payment_data, router_data, key_store, @@ -664,7 +667,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 +791,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 +852,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 +867,6 @@ impl PostUpdateTracker, types::PaymentsCaptureData> { payment_data = Box::pin(payment_response_update_tracker( db, - payment_id, payment_data, router_data, key_store, @@ -890,7 +889,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 +904,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 +928,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 +943,6 @@ impl PostUpdateTracker, types::PaymentsApproveData> { payment_data = Box::pin(payment_response_update_tracker( db, - payment_id, payment_data, router_data, key_store, @@ -970,7 +965,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 +980,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 +1004,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 +1028,6 @@ impl PostUpdateTracker, types::SetupMandateRequestDa payment_data = Box::pin(payment_response_update_tracker( db, - payment_id, payment_data, router_data, key_store, @@ -1064,6 +1055,7 @@ impl PostUpdateTracker, types::SetupMandateRequestDa where F: 'b + Clone + Send + Sync, { + let payment_method_billing_address = payment_data.address.get_payment_method_billing(); let billing_name = resp .address .get_payment_method_billing() @@ -1082,6 +1074,12 @@ impl PostUpdateTracker, types::SetupMandateRequestDa field_name: "connector_name", } })?; + let connector_mandate_reference_id = payment_data + .payment_attempt + .connector_mandate_detail + .as_ref() + .map(|detail| ConnectorMandateReferenceId::foreign_from(detail.clone())); + let merchant_connector_id = payment_data.payment_attempt.merchant_connector_id.clone(); let tokenization::SavePaymentMethodDataResponse { payment_method_id, @@ -1096,11 +1094,40 @@ impl PostUpdateTracker, types::SetupMandateRequestDa resp.request.payment_method_type, key_store, billing_name, - None, + payment_method_billing_address, business_profile, + connector_mandate_reference_id, )) .await?; + payment_data.payment_method_info = if let Some(payment_method_id) = &payment_method_id { + match state + .store + .find_payment_method( + &(state.into()), + key_store, + payment_method_id, + merchant_account.storage_scheme, + ) + .await + { + Ok(payment_method) => Some(payment_method), + Err(error) => { + if error.current_context().is_db_not_found() { + logger::info!("Payment Method not found in db {:?}", error); + None + } else { + Err(error) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Error retrieving payment method from db") + .map_err(|err| logger::error!(payment_method_retrieve=?err)) + .ok() + } + } + } + } else { + None + }; let mandate_id = mandate::mandate_procedure( state, resp, @@ -1134,7 +1161,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 +1176,6 @@ impl PostUpdateTracker, types::CompleteAuthorizeData { Box::pin(payment_response_update_tracker( db, - payment_id, payment_data, response, key_store, @@ -1176,7 +1201,7 @@ impl PostUpdateTracker, types::CompleteAuthorizeData where F: 'b + Clone + Send + Sync, { - let (connector_mandate_id, mandate_metadata) = resp + let (connector_mandate_id, mandate_metadata, connector_mandate_request_reference_id) = resp .response .clone() .ok() @@ -1189,16 +1214,18 @@ impl PostUpdateTracker, types::CompleteAuthorizeData ( mandate_ref.connector_mandate_id.clone(), mandate_ref.mandate_metadata.clone(), + mandate_ref.connector_mandate_request_reference_id.clone(), ) }) } else { None } }) - .unwrap_or((None, None)); + .unwrap_or((None, None, None)); update_connector_mandate_details_for_the_flow( connector_mandate_id, mandate_metadata, + connector_mandate_request_reference_id, payment_data, )?; @@ -1216,26 +1243,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, @@ -1534,7 +1546,7 @@ async fn payment_response_update_tracker( let encoded_data = payment_data.payment_attempt.encoded_data.clone(); - let authentication_data = redirection_data + let authentication_data = (*redirection_data) .as_ref() .map(Encode::encode_to_value) .transpose() @@ -1556,8 +1568,11 @@ async fn payment_response_update_tracker( } else { None }; - - if router_data.status == enums::AttemptStatus::Charged { + // update connector_mandate_details in case of Authorized/Charged Payment Status + if matches!( + router_data.status, + enums::AttemptStatus::Charged | enums::AttemptStatus::Authorized + ) { payment_data .payment_intent .fingerprint_id @@ -1597,10 +1612,10 @@ async fn payment_response_update_tracker( }) .unwrap_or(false) { - let (connector_mandate_id, mandate_metadata) = payment_data.payment_attempt.connector_mandate_detail.clone() - .map(|cmr| (cmr.connector_mandate_id, cmr.mandate_metadata)) - .unwrap_or((None, None)); + let (connector_mandate_id, mandate_metadata,connector_mandate_request_reference_id) = payment_data.payment_attempt.connector_mandate_detail.clone() + .map(|cmr| (cmr.connector_mandate_id, cmr.mandate_metadata,cmr.connector_mandate_request_reference_id)) + .unwrap_or((None, None,None)); // Update the connector mandate details with the payment attempt connector mandate id let connector_mandate_details = tokenization::update_connector_mandate_details( @@ -1617,6 +1632,7 @@ async fn payment_response_update_tracker( payment_data.payment_attempt.merchant_connector_id.clone(), connector_mandate_id, mandate_metadata, + connector_mandate_request_reference_id )?; // Update the payment method table with the active mandate record payment_methods::cards::update_payment_method_connector_mandate_details( @@ -1948,8 +1964,7 @@ async fn payment_response_update_tracker( #[cfg(all(feature = "v1", feature = "dynamic_routing"))] { - if let Some(dynamic_routing_algorithm) = business_profile.dynamic_routing_algorithm.clone() - { + if business_profile.dynamic_routing_algorithm.is_some() { let state = state.clone(); let business_profile = business_profile.clone(); let payment_attempt = payment_attempt.clone(); @@ -1960,7 +1975,6 @@ async fn payment_response_update_tracker( &payment_attempt, routable_connectors, &business_profile, - dynamic_routing_algorithm, ) .await .map_err(|e| logger::error!(dynamic_routing_metrics_error=?e)) @@ -2130,18 +2144,225 @@ 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, + connector_mandate_request_reference_id: Option, payment_data: &mut PaymentData, ) -> RouterResult<()> { + let mut original_connector_mandate_reference_id = payment_data + .payment_attempt + .connector_mandate_detail + .as_ref() + .map(|detail| ConnectorMandateReferenceId::foreign_from(detail.clone())); let connector_mandate_reference_id = if connector_mandate_id.is_some() { - Some(ConnectorMandateReferenceId { - connector_mandate_id: connector_mandate_id.clone(), - payment_method_id: None, - update_history: None, - mandate_metadata: mandate_metadata.clone(), - }) + if let Some(ref mut record) = original_connector_mandate_reference_id { + record.update( + connector_mandate_id, + None, + None, + mandate_metadata, + connector_mandate_request_reference_id, + ); + Some(record.clone()) + } else { + Some(ConnectorMandateReferenceId::new( + connector_mandate_id, + None, + None, + mandate_metadata, + connector_mandate_request_reference_id, + )) + } } else { None }; diff --git a/crates/router/src/core/payments/operations/payment_session.rs b/crates/router/src/core/payments/operations/payment_session.rs index d2154f16b6a6..1bc11854ad03 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 3042b15bfa1a..cad5dcfbd676 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 47f16786ab9c..a3a826ccd0e9 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 c1eae806ce0c..9005e94c9629 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); @@ -82,7 +82,7 @@ impl GetTracker, api::PaymentsRequest> for Pa if let Some(order_details) = &request.order_details { helpers::validate_order_details_amount( order_details.to_owned(), - payment_intent.amount.get_amount_as_i64(), + payment_intent.amount, false, )?; } @@ -329,7 +329,13 @@ impl GetTracker, api::PaymentsRequest> for Pa api_models::payments::MandateIds { mandate_id: Some(mandate_obj.mandate_id), mandate_reference_id: Some(api_models::payments::MandateReferenceId::ConnectorMandateId( - api_models::payments::ConnectorMandateReferenceId {connector_mandate_id:connector_id.connector_mandate_id,payment_method_id:connector_id.payment_method_id, update_history: None, mandate_metadata:connector_id.mandate_metadata, }, + api_models::payments::ConnectorMandateReferenceId::new( + connector_id.get_connector_mandate_id(), // connector_mandate_id + connector_id.get_payment_method_id(), // payment_method_id + None, // update_history + connector_id.get_mandate_metadata(), // mandate_metadata + connector_id.get_connector_mandate_request_reference_id() // connector_mandate_request_reference_id + ) )) } }), @@ -695,7 +701,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 +721,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 9d80206b9f21..1ddaf0b6abf9 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 c72dcb6f5611..2d4054a60bed 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 e4b6d0e287c5..7fdccf9c60fa 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, @@ -415,7 +424,7 @@ where }) => { let encoded_data = payment_data.get_payment_attempt().encoded_data.clone(); - let authentication_data = redirection_data + let authentication_data = (*redirection_data) .as_ref() .map(Encode::encode_to_value) .transpose() diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index af540c6dcf68..40721e9b4c31 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -7,6 +7,8 @@ use std::{ sync::Arc, }; +#[cfg(all(feature = "v1", feature = "dynamic_routing"))] +use api_models::routing as api_routing; use api_models::{ admin as admin_api, enums::{self as api_enums, CountryAlpha2}, @@ -21,6 +23,10 @@ use euclid::{ enums as euclid_enums, frontend::{ast, dir as euclid_dir}, }; +#[cfg(all(feature = "v1", feature = "dynamic_routing"))] +use external_services::grpc_client::dynamic_routing::{ + success_rate::CalSuccessRateResponse, SuccessBasedDynamicRouting, +}; use kgraph_utils::{ mca as mca_graph, transformers::{IntoContext, IntoDirValue}, @@ -826,6 +832,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 +974,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, @@ -1216,3 +1233,114 @@ pub fn make_dsl_input_for_surcharge( }; Ok(backend_input) } + +/// success based dynamic routing +#[cfg(all(feature = "v1", feature = "dynamic_routing"))] +pub async fn perform_success_based_routing( + state: &SessionState, + routable_connectors: Vec, + business_profile: &domain::Profile, +) -> RoutingResult> { + let success_based_dynamic_routing_algo_ref: api_routing::DynamicRoutingAlgorithmRef = + business_profile + .dynamic_routing_algorithm + .clone() + .map(|val| val.parse_value("DynamicRoutingAlgorithmRef")) + .transpose() + .change_context(errors::RoutingError::DeserializationError { + from: "JSON".to_string(), + to: "DynamicRoutingAlgorithmRef".to_string(), + }) + .attach_printable("unable to deserialize DynamicRoutingAlgorithmRef from JSON")? + .unwrap_or_default(); + + let success_based_algo_ref = success_based_dynamic_routing_algo_ref + .success_based_algorithm + .ok_or(errors::RoutingError::GenericNotFoundError { field: "success_based_algorithm".to_string() }) + .attach_printable( + "success_based_algorithm not found in dynamic_routing_algorithm from business_profile table", + )?; + + if success_based_algo_ref.enabled_feature + == api_routing::SuccessBasedRoutingFeatures::DynamicConnectorSelection + { + logger::debug!( + "performing success_based_routing for profile {}", + business_profile.get_id().get_string_repr() + ); + let client = state + .grpc_client + .dynamic_routing + .success_rate_client + .as_ref() + .ok_or(errors::RoutingError::SuccessRateClientInitializationError) + .attach_printable("success_rate gRPC client not found")?; + + let success_based_routing_configs = routing::helpers::fetch_success_based_routing_configs( + state, + business_profile, + success_based_algo_ref + .algorithm_id_with_timestamp + .algorithm_id + .ok_or(errors::RoutingError::GenericNotFoundError { + field: "success_based_routing_algorithm_id".to_string(), + }) + .attach_printable( + "success_based_routing_algorithm_id not found in business_profile", + )?, + ) + .await + .change_context(errors::RoutingError::SuccessBasedRoutingConfigError) + .attach_printable("unable to fetch success_rate based dynamic routing configs")?; + + let tenant_business_profile_id = routing::helpers::generate_tenant_business_profile_id( + &state.tenant.redis_key_prefix, + business_profile.get_id().get_string_repr(), + ); + + let success_based_connectors: CalSuccessRateResponse = client + .calculate_success_rate( + tenant_business_profile_id, + success_based_routing_configs, + routable_connectors, + ) + .await + .change_context(errors::RoutingError::SuccessRateCalculationError) + .attach_printable( + "unable to calculate/fetch success rate from dynamic routing service", + )?; + + let mut connectors = Vec::with_capacity(success_based_connectors.labels_with_score.len()); + for label_with_score in success_based_connectors.labels_with_score { + let (connector, merchant_connector_id) = label_with_score.label + .split_once(':') + .ok_or(errors::RoutingError::InvalidSuccessBasedConnectorLabel(label_with_score.label.to_string())) + .attach_printable( + "unable to split connector_name and mca_id from the label obtained by the dynamic routing service", + )?; + connectors.push(api_routing::RoutableConnectorChoice { + choice_kind: api_routing::RoutableChoiceKind::FullStruct, + connector: common_enums::RoutableConnectors::from_str(connector) + .change_context(errors::RoutingError::GenericConversionError { + from: "String".to_string(), + to: "RoutableConnectors".to_string(), + }) + .attach_printable("unable to convert String to RoutableConnectors")?, + merchant_connector_id: Some( + common_utils::id_type::MerchantConnectorAccountId::wrap( + merchant_connector_id.to_string(), + ) + .change_context(errors::RoutingError::GenericConversionError { + from: "String".to_string(), + to: "MerchantConnectorAccountId".to_string(), + }) + .attach_printable("unable to convert MerchantConnectorAccountId from string")?, + ), + }); + } + logger::debug!(success_based_routing_connectors=?connectors); + Ok(connectors) + } else { + Ok(routable_connectors) + } +} diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index b4e5ade56980..553eb6724868 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -80,6 +80,7 @@ pub async fn save_payment_method( billing_name: Option>, payment_method_billing_address: Option<&api::Address>, business_profile: &domain::Profile, + mut original_connector_mandate_reference_id: Option, ) -> RouterResult where FData: mandate::MandateBehaviour + Clone, @@ -155,22 +156,23 @@ where .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Unable to serialize customer acceptance to value")?; - let (connector_mandate_id, mandate_metadata) = match responses { - types::PaymentsResponseData::TransactionResponse { - ref mandate_reference, - .. - } => { - if let Some(mandate_ref) = mandate_reference { - ( - mandate_ref.connector_mandate_id.clone(), - mandate_ref.mandate_metadata.clone(), - ) - } else { - (None, None) + let (connector_mandate_id, mandate_metadata, connector_mandate_request_reference_id) = + match responses { + types::PaymentsResponseData::TransactionResponse { + mandate_reference, .. + } => { + if let Some(ref mandate_ref) = *mandate_reference { + ( + mandate_ref.connector_mandate_id.clone(), + mandate_ref.mandate_metadata.clone(), + mandate_ref.connector_mandate_request_reference_id.clone(), + ) + } else { + (None, None, None) + } } - } - _ => (None, None), - }; + _ => (None, None, None), + }; let pm_id = if customer_acceptance.is_some() { let payment_method_create_request = @@ -180,6 +182,7 @@ where payment_method_type, &customer_id.clone(), billing_name, + payment_method_billing_address, ) .await?; let customer_id = customer_id.to_owned().get_required_value("customer_id")?; @@ -689,12 +692,24 @@ where }; // check if there needs to be a config if yes then remove it to a different place let connector_mandate_reference_id = if connector_mandate_id.is_some() { - Some(ConnectorMandateReferenceId { - connector_mandate_id: connector_mandate_id.clone(), - payment_method_id: None, - update_history: None, - mandate_metadata: mandate_metadata.clone(), - }) + if let Some(ref mut record) = original_connector_mandate_reference_id { + record.update( + connector_mandate_id, + None, + None, + mandate_metadata, + connector_mandate_request_reference_id, + ); + Some(record.clone()) + } else { + Some(ConnectorMandateReferenceId::new( + connector_mandate_id, + None, + None, + mandate_metadata, + connector_mandate_request_reference_id, + )) + } } else { None }; @@ -728,6 +743,7 @@ pub async fn save_payment_method( _billing_name: Option>, _payment_method_billing_address: Option<&api::Address>, _business_profile: &domain::Profile, + _connector_mandate_request_reference_id: Option, ) -> RouterResult where FData: mandate::MandateBehaviour + Clone, @@ -1134,6 +1150,7 @@ pub fn add_connector_mandate_details_in_payment_method( merchant_connector_id: Option, connector_mandate_id: Option, mandate_metadata: Option, + connector_mandate_request_reference_id: Option, ) -> Option { let mut mandate_details = HashMap::new(); @@ -1149,6 +1166,7 @@ pub fn add_connector_mandate_details_in_payment_method( original_payment_authorized_currency: authorized_currency, mandate_metadata, connector_mandate_status: Some(ConnectorMandateStatus::Active), + connector_mandate_request_reference_id, }, ); Some(storage::PaymentsMandateReference(mandate_details)) @@ -1156,7 +1174,7 @@ pub fn add_connector_mandate_details_in_payment_method( None } } - +#[allow(clippy::too_many_arguments)] pub fn update_connector_mandate_details( mandate_details: Option, payment_method_type: Option, @@ -1165,6 +1183,7 @@ pub fn update_connector_mandate_details( merchant_connector_id: Option, connector_mandate_id: Option, mandate_metadata: Option, + connector_mandate_request_reference_id: Option, ) -> RouterResult> { let mandate_reference = match mandate_details { Some(mut payment_mandate_reference) => { @@ -1178,6 +1197,8 @@ pub fn update_connector_mandate_details( original_payment_authorized_currency: authorized_currency, mandate_metadata: mandate_metadata.clone(), connector_mandate_status: Some(ConnectorMandateStatus::Active), + connector_mandate_request_reference_id: connector_mandate_request_reference_id + .clone(), }; payment_mandate_reference @@ -1190,6 +1211,7 @@ pub fn update_connector_mandate_details( original_payment_authorized_currency: authorized_currency, mandate_metadata: mandate_metadata.clone(), connector_mandate_status: Some(ConnectorMandateStatus::Active), + connector_mandate_request_reference_id, }); Some(payment_mandate_reference) } else { @@ -1203,6 +1225,7 @@ pub fn update_connector_mandate_details( merchant_connector_id, connector_mandate_id, mandate_metadata, + connector_mandate_request_reference_id, ), }; let connector_mandate_details = mandate_reference diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 03ae1c880087..38b475590fdb 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, @@ -79,6 +102,12 @@ where customer_data: customer, }; + let connector_mandate_request_reference_id = payment_data + .payment_attempt + .connector_mandate_detail + .as_ref() + .and_then(|detail| detail.get_connector_mandate_request_reference_id()); + let router_data = types::RouterData { flow: PhantomData, merchant_id: merchant_account.get_id().clone(), @@ -136,23 +165,228 @@ where integrity_check: Ok(()), additional_merchant_data: None, header_payload: None, + connector_mandate_request_reference_id, }; 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, + shipping_cost: payment_data.payment_intent.amount_details.shipping_cost, + additional_payment_method_data: None, + }; + let connector_mandate_request_reference_id = payment_data + .payment_attempt + .connector_mandate_detail + .as_ref() + .and_then(|detail| detail.get_connector_mandate_request_reference_id()); + + // 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, + connector_mandate_request_reference_id, + }; + + 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 +410,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>, @@ -217,8 +451,8 @@ where // [#44]: why should response be filled during request let response = Ok(types::PaymentsResponseData::TransactionResponse { resource_id, - redirection_data: None, - mandate_reference: None, + redirection_data: Box::new(None), + mandate_reference: Box::new(None), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -281,6 +515,11 @@ where } else { payment_data.address }; + let connector_mandate_request_reference_id = payment_data + .payment_attempt + .connector_mandate_detail + .as_ref() + .and_then(|detail| detail.get_connector_mandate_request_reference_id()); crate::logger::debug!("unified address details {:?}", unified_address); @@ -350,6 +589,7 @@ where ) }), header_payload, + connector_mandate_request_reference_id, }; Ok(router_data) @@ -361,6 +601,7 @@ where Op: Debug, D: OperationSessionGetters, { + #[cfg(feature = "v1")] #[allow(clippy::too_many_arguments)] fn generate_response( data: D, @@ -373,8 +614,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, @@ -520,7 +775,7 @@ where } #[cfg(feature = "v2")] -impl ToResponse for api::PaymentsCreateIntentResponse +impl ToResponse for api::PaymentsIntentResponse where F: Clone, Op: Debug, @@ -530,7 +785,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 +796,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 +846,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 +1002,7 @@ impl ForeignTryFrom<(MinorUnit, Option, Option, Currency)> } } +#[cfg(feature = "v1")] impl ToResponse for api::VerifyResponse where F: Clone, @@ -1234,7 +1558,7 @@ where .and_then(|mandate_ref| match mandate_ref { api_models::payments::MandateReferenceId::ConnectorMandateId( connector_mandate_reference_id, - ) => connector_mandate_reference_id.connector_mandate_id.clone(), + ) => connector_mandate_reference_id.get_connector_mandate_id(), _ => None, }) }); @@ -1670,7 +1994,7 @@ pub fn voucher_next_steps_check( } pub fn change_order_details_to_new_type( - order_amount: i64, + order_amount: MinorUnit, order_details: api_models::payments::OrderDetails, ) -> Option> { Some(vec![api_models::payments::OrderDetailsWithAmount { @@ -1808,7 +2132,18 @@ impl TryFrom> for types::PaymentsAuthoriz payment_data.creds_identifier.as_deref(), )); - // payment_method_data is not required during recurring mandate payment, in such case keep default PaymentMethodData as MandatePayment + let additional_payment_method_data = if payment_data.mandate_id.is_some() { + let parsed_additional_payment_data: Option = + payment_data.payment_attempt + .payment_method_data + .as_ref().map(|data| data.clone().parse_value("AdditionalPaymentData")) + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed to parse AdditionalPaymentData from payment_data.payment_attempt.payment_method_data")?; + parsed_additional_payment_data + } else { + None + }; let payment_method_data = payment_data.payment_method_data.or_else(|| { if payment_data.mandate_id.is_some() { Some(domain::PaymentMethodData::MandatePayment) @@ -1847,6 +2182,7 @@ impl TryFrom> for types::PaymentsAuthoriz .payment_intent .merchant_order_reference_id .clone(); + let shipping_cost = payment_data.payment_intent.shipping_cost; Ok(Self { payment_method_data: (payment_method_data.get_required_value("payment_method_data")?), @@ -1893,6 +2229,8 @@ impl TryFrom> for types::PaymentsAuthoriz charges, merchant_order_reference_id, integrity_object: None, + additional_payment_method_data, + shipping_cost, }) } } @@ -2004,13 +2342,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 +2381,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.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); + 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) } } @@ -2192,11 +2569,12 @@ impl TryFrom> for types::SdkPaymentsSessi + shipping_cost + surcharge_amount; Ok(Self { - net_amount, + amount: net_amount, order_tax_amount, currency: payment_data.currency, - amount: payment_data.payment_intent.amount, + order_amount: payment_data.payment_intent.amount, session_id: payment_data.session_id, + shipping_cost: payment_data.payment_intent.shipping_cost, }) } } @@ -2231,11 +2609,24 @@ impl TryFrom> for types::PaymentsPostSess .payment_intent .merchant_order_reference_id .clone(); + let router_base_url = &additional_data.router_base_url; + let connector_name = &additional_data.connector_name; + let attempt = &payment_data.payment_attempt; + let router_return_url = Some(helpers::create_redirect_url( + router_base_url, + attempt, + connector_name, + payment_data.creds_identifier.as_deref(), + )); Ok(Self { amount, //need to change after we move to connector module + order_amount: payment_data.payment_intent.amount, currency: payment_data.currency, merchant_order_reference_id, capture_method: payment_data.payment_attempt.capture_method, + shipping_cost: payment_data.payment_intent.shipping_cost, + setup_future_usage: payment_data.payment_intent.setup_future_usage, + router_return_url, }) } } @@ -2258,7 +2649,52 @@ 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, + email: payment_data.email, + }) } } @@ -2287,26 +2723,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; @@ -2323,6 +2753,7 @@ impl TryFrom> for types::PaymentsSessionD }, ), order_details, + email: payment_data.email, surcharge_details: payment_data.surcharge_details, }) } @@ -2390,6 +2821,7 @@ impl TryFrom> for types::SetupMandateRequ | Some(RequestIncrementalAuthorization::Default) ), metadata: payment_data.payment_intent.metadata.clone().map(Into::into), + shipping_cost: payment_data.payment_intent.shipping_cost, }) } } @@ -2638,42 +3070,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 +3150,7 @@ impl ForeignFrom ), surcharge_amount: amount_details.surcharge_amount, tax_on_surcharge: amount_details.tax_on_surcharge, - }) + } } } @@ -2857,20 +3320,23 @@ impl ForeignFrom impl ForeignFrom for ConnectorMandateReferenceId { fn foreign_from(value: DieselConnectorMandateReferenceId) -> Self { - Self { - connector_mandate_id: value.connector_mandate_id, - payment_method_id: value.payment_method_id, - update_history: None, - mandate_metadata: value.mandate_metadata, - } + Self::new( + value.connector_mandate_id, + value.payment_method_id, + None, + value.mandate_metadata, + value.connector_mandate_request_reference_id, + ) } } impl ForeignFrom for DieselConnectorMandateReferenceId { fn foreign_from(value: ConnectorMandateReferenceId) -> Self { Self { - connector_mandate_id: value.connector_mandate_id, - payment_method_id: value.payment_method_id, - mandate_metadata: value.mandate_metadata, + connector_mandate_id: value.get_connector_mandate_id(), + payment_method_id: value.get_payment_method_id(), + mandate_metadata: value.get_mandate_metadata(), + connector_mandate_request_reference_id: value + .get_connector_mandate_request_reference_id(), } } } diff --git a/crates/router/src/core/payouts.rs b/crates/router/src/core/payouts.rs index c1b8f78eeb13..02c619b68d9d 100644 --- a/crates/router/src/core/payouts.rs +++ b/crates/router/src/core/payouts.rs @@ -375,7 +375,7 @@ pub async fn payouts_confirm_core( &merchant_account, None, &key_store, - &payouts::PayoutRequest::PayoutCreateRequest(req.to_owned()), + &payouts::PayoutRequest::PayoutCreateRequest(Box::new(req.to_owned())), locale, ) .await?; @@ -448,7 +448,7 @@ pub async fn payouts_update_core( &merchant_account, None, &key_store, - &payouts::PayoutRequest::PayoutCreateRequest(req.to_owned()), + &payouts::PayoutRequest::PayoutCreateRequest(Box::new(req.to_owned())), locale, ) .await?; diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs index 46f459054487..49b18e53a0c7 100644 --- a/crates/router/src/core/payouts/helpers.rs +++ b/crates/router/src/core/payouts/helpers.rs @@ -1,11 +1,10 @@ -#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] -use api_models::customers::CustomerRequestWithEmail; use api_models::{enums, payment_methods::Card, payouts}; use common_utils::{ + crypto::Encryptable, encryption::Encryption, errors::CustomResult, ext_traits::{AsyncExt, StringExt}, - fp_utils, id_type, payout_method_utils as payout_additional, type_name, + fp_utils, id_type, payout_method_utils as payout_additional, pii, type_name, types::{ keymanager::{Identifier, KeyManagerState}, MinorUnit, UnifiedCode, UnifiedMessage, @@ -15,7 +14,7 @@ use common_utils::{ use common_utils::{generate_customer_id_of_default_length, types::keymanager::ToEncryptable}; use error_stack::{report, ResultExt}; use hyperswitch_domain_models::type_encryption::{crypto_operation, CryptoOperation}; -use masking::{PeekInterface, Secret}; +use masking::{ExposeInterface, PeekInterface, Secret, SwitchStrategy}; use router_env::logger; use super::PayoutData; @@ -696,13 +695,18 @@ pub(super) async fn get_or_create_customer_details( let encrypted_data = crypto_operation( &state.into(), type_name!(domain::Customer), - CryptoOperation::BatchEncrypt(CustomerRequestWithEmail::to_encryptable( - CustomerRequestWithEmail { - name: customer_details.name.clone(), - email: customer_details.email.clone(), - phone: customer_details.phone.clone(), - }, - )), + CryptoOperation::BatchEncrypt( + domain::FromRequestEncryptableCustomer::to_encryptable( + domain::FromRequestEncryptableCustomer { + name: customer_details.name.clone(), + email: customer_details + .email + .clone() + .map(|a| a.expose().switch_strategy()), + phone: customer_details.phone.clone(), + }, + ), + ), Identifier::Merchant(key_store.merchant_id.clone()), key, ) @@ -711,7 +715,7 @@ pub(super) async fn get_or_create_customer_details( .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed to encrypt customer")?; let encryptable_customer = - CustomerRequestWithEmail::from_encryptable(encrypted_data) + domain::FromRequestEncryptableCustomer::from_encryptable(encrypted_data) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed to form EncryptableCustomer")?; @@ -719,7 +723,14 @@ pub(super) async fn get_or_create_customer_details( customer_id: customer_id.clone(), merchant_id: merchant_id.to_owned().clone(), name: encryptable_customer.name, - email: encryptable_customer.email, + email: encryptable_customer.email.map(|email| { + let encryptable: Encryptable> = + Encryptable::new( + email.clone().into_inner().switch_strategy(), + email.into_encrypted(), + ); + encryptable + }), phone: encryptable_customer.phone, description: None, phone_country_code: customer_details.phone_country_code.to_owned(), diff --git a/crates/router/src/core/pm_auth.rs b/crates/router/src/core/pm_auth.rs index 2c3f76c88a0b..b8672ee79b42 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/routing.rs b/crates/router/src/core/routing.rs index 926b30081bf6..0bd38918ee77 100644 --- a/crates/router/src/core/routing.rs +++ b/crates/router/src/core/routing.rs @@ -441,9 +441,13 @@ pub async fn link_routing_config( utils::when( matches!( dynamic_routing_ref.success_based_algorithm, - Some(routing_types::DynamicAlgorithmWithTimestamp { - algorithm_id: Some(ref id), - timestamp: _ + Some(routing::SuccessBasedAlgorithm { + algorithm_id_with_timestamp: + routing_types::DynamicAlgorithmWithTimestamp { + algorithm_id: Some(ref id), + timestamp: _ + }, + enabled_feature: _ }) if id == &algorithm_id ), || { @@ -453,7 +457,17 @@ pub async fn link_routing_config( }, )?; - dynamic_routing_ref.update_algorithm_id(algorithm_id); + dynamic_routing_ref.update_algorithm_id( + algorithm_id, + dynamic_routing_ref + .success_based_algorithm + .clone() + .ok_or(errors::ApiErrorResponse::InternalServerError) + .attach_printable( + "missing success_based_algorithm in dynamic_algorithm_ref from business_profile table", + )? + .enabled_feature, + ); helpers::update_business_profile_active_dynamic_algorithm_ref( db, key_manager_state, @@ -1169,7 +1183,7 @@ pub async fn toggle_success_based_routing( state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, - status: bool, + feature_to_enable: routing::SuccessBasedRoutingFeatures, profile_id: common_utils::id_type::ProfileId, ) -> RouterResponse { metrics::ROUTING_CREATE_REQUEST_RECEIVED.add( @@ -1205,115 +1219,158 @@ pub async fn toggle_success_based_routing( )? .unwrap_or_default(); - if status { - let default_success_based_routing_config = routing::SuccessBasedRoutingConfig::default(); - let algorithm_id = common_utils::generate_routing_id_of_default_length(); - let timestamp = common_utils::date_time::now(); - let algo = RoutingAlgorithm { - algorithm_id: algorithm_id.clone(), - profile_id: business_profile.get_id().to_owned(), - merchant_id: merchant_account.get_id().to_owned(), - name: "Dynamic routing algorithm".to_string(), - description: None, - kind: diesel_models::enums::RoutingAlgorithmKind::Dynamic, - algorithm_data: serde_json::json!(default_success_based_routing_config), - created_at: timestamp, - modified_at: timestamp, - algorithm_for: common_enums::TransactionType::Payment, - }; - - let record = db - .insert_routing_algorithm(algo) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Unable to insert record in routing algorithm table")?; - - success_based_dynamic_routing_algo_ref.update_algorithm_id(algorithm_id); - helpers::update_business_profile_active_dynamic_algorithm_ref( - db, - key_manager_state, - &key_store, - business_profile, - success_based_dynamic_routing_algo_ref, - ) - .await?; - - let new_record = record.foreign_into(); - - metrics::ROUTING_CREATE_SUCCESS_RESPONSE.add( - &metrics::CONTEXT, - 1, - &add_attributes([("profile_id", profile_id.get_string_repr().to_owned())]), - ); - Ok(service_api::ApplicationResponse::Json(new_record)) - } else { - let timestamp = common_utils::date_time::now_unix_timestamp(); - match success_based_dynamic_routing_algo_ref.success_based_algorithm { - Some(algorithm_ref) => { - if let Some(algorithm_id) = algorithm_ref.algorithm_id { - let dynamic_routing_algorithm = routing_types::DynamicRoutingAlgorithmRef { - success_based_algorithm: Some( - routing_types::DynamicAlgorithmWithTimestamp { - algorithm_id: None, - timestamp, - }, - ), - }; - - // redact cache for success based routing configs - let cache_key = format!( - "{}_{}", - business_profile.get_id().get_string_repr(), - algorithm_id.get_string_repr() - ); - let cache_entries_to_redact = - vec![cache::CacheKind::SuccessBasedDynamicRoutingCache( - cache_key.into(), - )]; - let _ = cache::publish_into_redact_channel( - state.store.get_cache_store().as_ref(), - cache_entries_to_redact, - ) - .await - .map_err(|e| { - logger::error!( - "unable to publish into the redact channel for evicting the success based routing config cache {e:?}" + match feature_to_enable { + routing::SuccessBasedRoutingFeatures::Metrics + | routing::SuccessBasedRoutingFeatures::DynamicConnectorSelection => { + if let Some(ref mut algo_with_timestamp) = + success_based_dynamic_routing_algo_ref.success_based_algorithm + { + match algo_with_timestamp + .algorithm_id_with_timestamp + .algorithm_id + .clone() + { + Some(algorithm_id) => { + // algorithm is already present in profile + if algo_with_timestamp.enabled_feature == feature_to_enable { + // algorithm already has the required feature + Err(errors::ApiErrorResponse::PreconditionFailed { + message: "Success rate based routing is already enabled" + .to_string(), + })? + } else { + // enable the requested feature for the algorithm + algo_with_timestamp.update_enabled_features(feature_to_enable); + let record = db + .find_routing_algorithm_by_profile_id_algorithm_id( + business_profile.get_id(), + &algorithm_id, + ) + .await + .to_not_found_response( + errors::ApiErrorResponse::ResourceIdNotFound, + )?; + let response = record.foreign_into(); + helpers::update_business_profile_active_dynamic_algorithm_ref( + db, + key_manager_state, + &key_store, + business_profile, + success_based_dynamic_routing_algo_ref, + ) + .await?; + + metrics::ROUTING_CREATE_SUCCESS_RESPONSE.add( + &metrics::CONTEXT, + 1, + &add_attributes([( + "profile_id", + profile_id.get_string_repr().to_owned(), + )]), + ); + Ok(service_api::ApplicationResponse::Json(response)) + } + } + None => { + // algorithm isn't present in profile + helpers::default_success_based_routing_setup( + &state, + key_store, + business_profile, + feature_to_enable, + merchant_account.get_id().to_owned(), + success_based_dynamic_routing_algo_ref, ) - }); + .await + } + } + } else { + // algorithm isn't present in profile + helpers::default_success_based_routing_setup( + &state, + key_store, + business_profile, + feature_to_enable, + merchant_account.get_id().to_owned(), + success_based_dynamic_routing_algo_ref, + ) + .await + } + } + routing::SuccessBasedRoutingFeatures::None => { + // disable success based routing for the requested profile + let timestamp = common_utils::date_time::now_unix_timestamp(); + match success_based_dynamic_routing_algo_ref.success_based_algorithm { + Some(algorithm_ref) => { + if let Some(algorithm_id) = + algorithm_ref.algorithm_id_with_timestamp.algorithm_id + { + let dynamic_routing_algorithm = routing_types::DynamicRoutingAlgorithmRef { + success_based_algorithm: Some(routing::SuccessBasedAlgorithm { + algorithm_id_with_timestamp: + routing_types::DynamicAlgorithmWithTimestamp { + algorithm_id: None, + timestamp, + }, + enabled_feature: routing::SuccessBasedRoutingFeatures::None, + }), + }; - let record = db - .find_routing_algorithm_by_profile_id_algorithm_id( - business_profile.get_id(), - &algorithm_id, + // redact cache for success based routing configs + let cache_key = format!( + "{}_{}", + business_profile.get_id().get_string_repr(), + algorithm_id.get_string_repr() + ); + let cache_entries_to_redact = + vec![cache::CacheKind::SuccessBasedDynamicRoutingCache( + cache_key.into(), + )]; + let _ = cache::publish_into_redact_channel( + state.store.get_cache_store().as_ref(), + cache_entries_to_redact, ) .await - .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?; - let response = record.foreign_into(); - helpers::update_business_profile_active_dynamic_algorithm_ref( - db, - key_manager_state, - &key_store, - business_profile, - dynamic_routing_algorithm, - ) - .await?; - - metrics::ROUTING_UNLINK_CONFIG_SUCCESS_RESPONSE.add( - &metrics::CONTEXT, - 1, - &add_attributes([("profile_id", profile_id.get_string_repr().to_owned())]), - ); - - Ok(service_api::ApplicationResponse::Json(response)) - } else { - Err(errors::ApiErrorResponse::PreconditionFailed { - message: "Algorithm is already inactive".to_string(), - })? + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("unable to publish into the redact channel for evicting the success based routing config cache")?; + + let record = db + .find_routing_algorithm_by_profile_id_algorithm_id( + business_profile.get_id(), + &algorithm_id, + ) + .await + .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?; + let response = record.foreign_into(); + helpers::update_business_profile_active_dynamic_algorithm_ref( + db, + key_manager_state, + &key_store, + business_profile, + dynamic_routing_algorithm, + ) + .await?; + + metrics::ROUTING_UNLINK_CONFIG_SUCCESS_RESPONSE.add( + &metrics::CONTEXT, + 1, + &add_attributes([( + "profile_id", + profile_id.get_string_repr().to_owned(), + )]), + ); + + Ok(service_api::ApplicationResponse::Json(response)) + } else { + Err(errors::ApiErrorResponse::PreconditionFailed { + message: "Algorithm is already inactive".to_string(), + })? + } } + None => Err(errors::ApiErrorResponse::PreconditionFailed { + message: "Success rate based routing is already disabled".to_string(), + })?, } - None => Err(errors::ApiErrorResponse::PreconditionFailed { - message: "Algorithm is already inactive".to_string(), - })?, } } } diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index 22966208dd44..31cd4234714e 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -12,10 +12,16 @@ use api_models::routing as routing_types; use common_utils::ext_traits::ValueExt; use common_utils::{ext_traits::Encode, id_type, types::keymanager::KeyManagerState}; use diesel_models::configs; +#[cfg(feature = "v1")] +use diesel_models::routing_algorithm; use error_stack::ResultExt; -#[cfg(feature = "dynamic_routing")] +#[cfg(all(feature = "dynamic_routing", feature = "v1"))] use external_services::grpc_client::dynamic_routing::SuccessBasedDynamicRouting; +#[cfg(feature = "v1")] +use hyperswitch_domain_models::api::ApplicationResponse; #[cfg(all(feature = "dynamic_routing", feature = "v1"))] +use router_env::logger; +#[cfg(any(feature = "dynamic_routing", feature = "v1"))] use router_env::{instrument, metrics::add_attributes, tracing}; use rustc_hash::FxHashSet; use storage_impl::redis::cache; @@ -29,8 +35,10 @@ use crate::{ types::{domain, storage}, utils::StringExt, }; -#[cfg(all(feature = "dynamic_routing", feature = "v1"))] -use crate::{core::metrics as core_metrics, routes::metrics}; +#[cfg(feature = "v1")] +use crate::{core::metrics as core_metrics, routes::metrics, types::transformers::ForeignInto}; +pub const SUCCESS_BASED_DYNAMIC_ROUTING_ALGORITHM: &str = + "Success rate based dynamic routing algorithm"; /// Provides us with all the configured configs of the Merchant in the ascending time configured /// manner and chooses the first of them @@ -594,28 +602,8 @@ pub async fn refresh_success_based_routing_cache( pub async fn fetch_success_based_routing_configs( state: &SessionState, business_profile: &domain::Profile, - dynamic_routing_algorithm: serde_json::Value, + success_based_routing_id: id_type::RoutingId, ) -> RouterResult { - let dynamic_routing_algorithm_ref = dynamic_routing_algorithm - .parse_value::("DynamicRoutingAlgorithmRef") - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("unable to parse dynamic_routing_algorithm_ref")?; - - let success_based_routing_id = dynamic_routing_algorithm_ref - .success_based_algorithm - .ok_or(errors::ApiErrorResponse::GenericNotFoundError { - message: "success_based_algorithm not found in dynamic_routing_algorithm_ref" - .to_string(), - })? - .algorithm_id - // error can be possible when the feature is toggled off. - .ok_or(errors::ApiErrorResponse::GenericNotFoundError { - message: format!( - "unable to find algorithm_id in success based algorithm config as the feature is disabled for profile_id: {}", - business_profile.get_id().get_string_repr() - ), - })?; - let key = format!( "{}_{}", business_profile.get_id().get_string_repr(), @@ -657,156 +645,185 @@ pub async fn push_metrics_for_success_based_routing( payment_attempt: &storage::PaymentAttempt, routable_connectors: Vec, business_profile: &domain::Profile, - dynamic_routing_algorithm: serde_json::Value, ) -> RouterResult<()> { - let client = state - .grpc_client - .dynamic_routing - .success_rate_client - .as_ref() - .ok_or(errors::ApiErrorResponse::GenericNotFoundError { - message: "success_rate gRPC client not found".to_string(), - })?; - - let payment_connector = &payment_attempt.connector.clone().ok_or( - errors::ApiErrorResponse::GenericNotFoundError { - message: "unable to derive payment connector from payment attempt".to_string(), - }, - )?; - - let success_based_routing_configs = - fetch_success_based_routing_configs(state, business_profile, dynamic_routing_algorithm) - .await + let success_based_dynamic_routing_algo_ref: routing_types::DynamicRoutingAlgorithmRef = + business_profile + .dynamic_routing_algorithm + .clone() + .map(|val| val.parse_value("DynamicRoutingAlgorithmRef")) + .transpose() .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("unable to retrieve success_rate based dynamic routing configs")?; + .attach_printable("Failed to deserialize DynamicRoutingAlgorithmRef from JSON")? + .unwrap_or_default(); - let tenant_business_profile_id = format!( - "{}:{}", - state.tenant.redis_key_prefix, - business_profile.get_id().get_string_repr() - ); + let success_based_algo_ref = success_based_dynamic_routing_algo_ref + .success_based_algorithm + .ok_or(errors::ApiErrorResponse::InternalServerError) + .attach_printable("success_based_algorithm not found in dynamic_routing_algorithm from business_profile table")?; + + if success_based_algo_ref.enabled_feature != routing_types::SuccessBasedRoutingFeatures::None { + let client = state + .grpc_client + .dynamic_routing + .success_rate_client + .as_ref() + .ok_or(errors::ApiErrorResponse::GenericNotFoundError { + message: "success_rate gRPC client not found".to_string(), + })?; + + let payment_connector = &payment_attempt.connector.clone().ok_or( + errors::ApiErrorResponse::GenericNotFoundError { + message: "unable to derive payment connector from payment attempt".to_string(), + }, + )?; - let success_based_connectors = client - .calculate_success_rate( - tenant_business_profile_id.clone(), - success_based_routing_configs.clone(), - routable_connectors.clone(), + let success_based_routing_configs = fetch_success_based_routing_configs( + state, + business_profile, + success_based_algo_ref + .algorithm_id_with_timestamp + .algorithm_id + .ok_or(errors::ApiErrorResponse::InternalServerError) + .attach_printable( + "success_based_routing_algorithm_id not found in business_profile", + )?, ) .await .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("unable to calculate/fetch success rate from dynamic routing service")?; - - let payment_status_attribute = - get_desired_payment_status_for_success_routing_metrics(&payment_attempt.status); - - let first_success_based_connector_label = &success_based_connectors - .labels_with_score - .first() - .ok_or(errors::ApiErrorResponse::InternalServerError) - .attach_printable( - "unable to fetch the first connector from list of connectors obtained from dynamic routing service", - )? - .label - .to_string(); - - let (first_success_based_connector, merchant_connector_id) = first_success_based_connector_label - .split_once(':') - .ok_or(errors::ApiErrorResponse::InternalServerError) - .attach_printable( - "unable to split connector_name and mca_id from the first connector obtained from dynamic routing service", - )?; - - let outcome = get_success_based_metrics_outcome_for_payment( - &payment_status_attribute, - payment_connector.to_string(), - first_success_based_connector.to_string(), - ); - - core_metrics::DYNAMIC_SUCCESS_BASED_ROUTING.add( - &metrics::CONTEXT, - 1, - &add_attributes([ - ("tenant", state.tenant.name.clone()), - ( - "merchant_id", - payment_attempt.merchant_id.get_string_repr().to_string(), - ), - ( - "profile_id", - payment_attempt.profile_id.get_string_repr().to_string(), - ), - ("merchant_connector_id", merchant_connector_id.to_string()), - ( - "payment_id", - payment_attempt.payment_id.get_string_repr().to_string(), - ), - ( - "success_based_routing_connector", - first_success_based_connector.to_string(), - ), - ("payment_connector", payment_connector.to_string()), - ( - "currency", - payment_attempt - .currency - .map_or_else(|| "None".to_string(), |currency| currency.to_string()), - ), - ( - "payment_method", - payment_attempt.payment_method.map_or_else( - || "None".to_string(), - |payment_method| payment_method.to_string(), + .attach_printable("unable to retrieve success_rate based dynamic routing configs")?; + + let tenant_business_profile_id = generate_tenant_business_profile_id( + &state.tenant.redis_key_prefix, + business_profile.get_id().get_string_repr(), + ); + + let success_based_connectors = client + .calculate_success_rate( + tenant_business_profile_id.clone(), + success_based_routing_configs.clone(), + routable_connectors.clone(), + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable( + "unable to calculate/fetch success rate from dynamic routing service", + )?; + + let payment_status_attribute = + get_desired_payment_status_for_success_routing_metrics(&payment_attempt.status); + + let first_success_based_connector_label = &success_based_connectors + .labels_with_score + .first() + .ok_or(errors::ApiErrorResponse::InternalServerError) + .attach_printable( + "unable to fetch the first connector from list of connectors obtained from dynamic routing service", + )? + .label + .to_string(); + + let (first_success_based_connector, merchant_connector_id) = first_success_based_connector_label + .split_once(':') + .ok_or(errors::ApiErrorResponse::InternalServerError) + .attach_printable( + "unable to split connector_name and mca_id from the first connector obtained from dynamic routing service", + )?; + + let outcome = get_success_based_metrics_outcome_for_payment( + &payment_status_attribute, + payment_connector.to_string(), + first_success_based_connector.to_string(), + ); + + core_metrics::DYNAMIC_SUCCESS_BASED_ROUTING.add( + &metrics::CONTEXT, + 1, + &add_attributes([ + ("tenant", state.tenant.tenant_id.clone()), + ( + "merchant_id", + payment_attempt.merchant_id.get_string_repr().to_string(), ), - ), - ( - "payment_method_type", - payment_attempt.payment_method_type.map_or_else( - || "None".to_string(), - |payment_method_type| payment_method_type.to_string(), + ( + "profile_id", + payment_attempt.profile_id.get_string_repr().to_string(), ), - ), - ( - "capture_method", - payment_attempt.capture_method.map_or_else( - || "None".to_string(), - |capture_method| capture_method.to_string(), + ("merchant_connector_id", merchant_connector_id.to_string()), + ( + "payment_id", + payment_attempt.payment_id.get_string_repr().to_string(), ), - ), - ( - "authentication_type", - payment_attempt.authentication_type.map_or_else( - || "None".to_string(), - |authentication_type| authentication_type.to_string(), + ( + "success_based_routing_connector", + first_success_based_connector.to_string(), ), - ), - ("payment_status", payment_attempt.status.to_string()), - ("conclusive_classification", outcome.to_string()), - ]), - ); - - client - .update_success_rate( - tenant_business_profile_id, - success_based_routing_configs, - vec![routing_types::RoutableConnectorChoiceWithStatus::new( - routing_types::RoutableConnectorChoice { - choice_kind: api_models::routing::RoutableChoiceKind::FullStruct, - connector: common_enums::RoutableConnectors::from_str( - payment_connector.as_str(), - ) - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("unable to infer routable_connector from connector")?, - merchant_connector_id: payment_attempt.merchant_connector_id.clone(), - }, - payment_status_attribute == common_enums::AttemptStatus::Charged, - )], - ) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable( - "unable to update success based routing window in dynamic routing service", - )?; - Ok(()) + ("payment_connector", payment_connector.to_string()), + ( + "currency", + payment_attempt + .currency + .map_or_else(|| "None".to_string(), |currency| currency.to_string()), + ), + ( + "payment_method", + payment_attempt.payment_method.map_or_else( + || "None".to_string(), + |payment_method| payment_method.to_string(), + ), + ), + ( + "payment_method_type", + payment_attempt.payment_method_type.map_or_else( + || "None".to_string(), + |payment_method_type| payment_method_type.to_string(), + ), + ), + ( + "capture_method", + payment_attempt.capture_method.map_or_else( + || "None".to_string(), + |capture_method| capture_method.to_string(), + ), + ), + ( + "authentication_type", + payment_attempt.authentication_type.map_or_else( + || "None".to_string(), + |authentication_type| authentication_type.to_string(), + ), + ), + ("payment_status", payment_attempt.status.to_string()), + ("conclusive_classification", outcome.to_string()), + ]), + ); + logger::debug!("successfully pushed success_based_routing metrics"); + + client + .update_success_rate( + tenant_business_profile_id, + success_based_routing_configs, + vec![routing_types::RoutableConnectorChoiceWithStatus::new( + routing_types::RoutableConnectorChoice { + choice_kind: api_models::routing::RoutableChoiceKind::FullStruct, + connector: common_enums::RoutableConnectors::from_str( + payment_connector.as_str(), + ) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("unable to infer routable_connector from connector")?, + merchant_connector_id: payment_attempt.merchant_connector_id.clone(), + }, + payment_status_attribute == common_enums::AttemptStatus::Charged, + )], + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable( + "unable to update success based routing window in dynamic routing service", + )?; + Ok(()) + } else { + Ok(()) + } } #[cfg(all(feature = "v1", feature = "dynamic_routing"))] @@ -875,3 +892,67 @@ fn get_success_based_metrics_outcome_for_payment( _ => common_enums::SuccessBasedRoutingConclusiveState::NonDeterministic, } } + +/// generates cache key with tenant's redis key prefix and profile_id +pub fn generate_tenant_business_profile_id( + redis_key_prefix: &str, + business_profile_id: &str, +) -> String { + format!("{}:{}", redis_key_prefix, business_profile_id) +} + +/// default config setup for success_based_routing +#[cfg(feature = "v1")] +#[instrument(skip_all)] +pub async fn default_success_based_routing_setup( + state: &SessionState, + key_store: domain::MerchantKeyStore, + business_profile: domain::Profile, + feature_to_enable: routing_types::SuccessBasedRoutingFeatures, + merchant_id: id_type::MerchantId, + mut success_based_dynamic_routing_algo: routing_types::DynamicRoutingAlgorithmRef, +) -> RouterResult> { + let db = state.store.as_ref(); + let key_manager_state = &state.into(); + let profile_id = business_profile.get_id().to_owned(); + let default_success_based_routing_config = routing_types::SuccessBasedRoutingConfig::default(); + let algorithm_id = common_utils::generate_routing_id_of_default_length(); + let timestamp = common_utils::date_time::now(); + let algo = routing_algorithm::RoutingAlgorithm { + algorithm_id: algorithm_id.clone(), + profile_id: profile_id.clone(), + merchant_id, + name: SUCCESS_BASED_DYNAMIC_ROUTING_ALGORITHM.to_string(), + description: None, + kind: diesel_models::enums::RoutingAlgorithmKind::Dynamic, + algorithm_data: serde_json::json!(default_success_based_routing_config), + created_at: timestamp, + modified_at: timestamp, + algorithm_for: common_enums::TransactionType::Payment, + }; + + let record = db + .insert_routing_algorithm(algo) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to insert record in routing algorithm table")?; + + success_based_dynamic_routing_algo.update_algorithm_id(algorithm_id, feature_to_enable); + update_business_profile_active_dynamic_algorithm_ref( + db, + key_manager_state, + &key_store, + business_profile, + success_based_dynamic_routing_algo, + ) + .await?; + + let new_record = record.foreign_into(); + + core_metrics::ROUTING_CREATE_SUCCESS_RESPONSE.add( + &metrics::CONTEXT, + 1, + &add_attributes([("profile_id", profile_id.get_string_repr().to_string())]), + ); + Ok(ApplicationResponse::Json(new_record)) +} diff --git a/crates/router/src/core/user.rs b/crates/router/src/core/user.rs index 822c29b21d99..35b26926ed2b 100644 --- a/crates/router/src/core/user.rs +++ b/crates/router/src/core/user.rs @@ -1319,7 +1319,7 @@ pub async fn list_user_roles_details( )) .await .change_context(UserErrors::InternalServerError) - .attach_printable("Failed to construct proifle map")? + .attach_printable("Failed to construct profile map")? .into_iter() .map(|profile| (profile.get_id().to_owned(), profile.profile_name)) .collect::>(); @@ -1927,7 +1927,7 @@ pub async fn terminate_two_factor_auth( .change_context(UserErrors::InternalServerError)? .into(); - if !skip_two_factor_auth { + if state.conf.user.force_two_factor_auth || !skip_two_factor_auth { if !tfa_utils::check_totp_in_redis(&state, &user_token.user_id).await? && !tfa_utils::check_recovery_code_in_redis(&state, &user_token.user_id).await? { @@ -1997,9 +1997,12 @@ pub async fn check_two_factor_auth_status_with_attempts( .await .change_context(UserErrors::InternalServerError)? .into(); + + let is_skippable = state.conf.user.force_two_factor_auth.not(); if user_from_db.get_totp_status() == TotpStatus::NotSet { return Ok(ApplicationResponse::Json(user_api::TwoFactorStatus { status: None, + is_skippable, })); }; @@ -2018,6 +2021,7 @@ pub async fn check_two_factor_auth_status_with_attempts( totp, recovery_code, }), + is_skippable, })) } diff --git a/crates/router/src/core/user/sample_data.rs b/crates/router/src/core/user/sample_data.rs index 5058ad600e00..d098d1f76d92 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::{DisputeNew, RefundNew}; use error_stack::ResultExt; use hyperswitch_domain_models::payments::PaymentIntent; @@ -39,19 +39,23 @@ pub async fn generate_sample_data_for_user( .change_context(SampleDataError::InternalServerError) .attach_printable("Not able to fetch merchant key store")?; // If not able to fetch merchant key store for any reason, this should be an internal server error - let (payment_intents, payment_attempts, refunds): ( + let (payment_intents, payment_attempts, refunds, disputes): ( Vec, - Vec, + Vec, Vec, + Vec, ) = sample_data.into_iter().fold( - (Vec::new(), Vec::new(), Vec::new()), - |(mut pi, mut pa, mut rf), (payment_intent, payment_attempt, refund)| { + (Vec::new(), Vec::new(), Vec::new(), Vec::new()), + |(mut pi, mut pa, mut rf, mut dp), (payment_intent, payment_attempt, refund, dispute)| { pi.push(payment_intent); pa.push(payment_attempt); if let Some(refund) = refund { rf.push(refund); } - (pi, pa, rf) + if let Some(dispute) = dispute { + dp.push(dispute); + } + (pi, pa, rf, dp) }, ); @@ -70,6 +74,11 @@ pub async fn generate_sample_data_for_user( .insert_refunds_batch_for_sample_data(refunds) .await .switch()?; + state + .store + .insert_disputes_batch_for_sample_data(disputes) + .await + .switch()?; Ok(ApplicationResponse::StatusOk) } @@ -109,6 +118,11 @@ pub async fn delete_sample_data_for_user( .delete_refunds_for_sample_data(&merchant_id_del) .await .switch()?; + state + .store + .delete_disputes_for_sample_data(&merchant_id_del) + .await + .switch()?; Ok(ApplicationResponse::StatusOk) } diff --git a/crates/router/src/core/user_role.rs b/crates/router/src/core/user_role.rs index 1d188168e5cf..27c1e2ae4945 100644 --- a/crates/router/src/core/user_role.rs +++ b/crates/router/src/core/user_role.rs @@ -1,6 +1,9 @@ use std::collections::{HashMap, HashSet}; -use api_models::{user as user_api, user_role as user_role_api}; +use api_models::{ + user as user_api, + user_role::{self as user_role_api, role as role_api}, +}; use diesel_models::{ enums::{UserRoleVersion, UserStatus}, organization::OrganizationBridge, @@ -16,14 +19,18 @@ use crate::{ routes::{app::ReqState, SessionState}, services::{ authentication as auth, - authorization::{info, roles}, + authorization::{ + info, + permission_groups::{ParentGroupExt, PermissionGroupExt}, + roles, + }, ApplicationResponse, }, types::domain, utils, }; pub mod role; -use common_enums::{EntityType, PermissionGroup}; +use common_enums::{EntityType, ParentGroup, PermissionGroup}; use strum::IntoEnumIterator; // TODO: To be deprecated @@ -44,11 +51,10 @@ pub async fn get_authorization_info_with_group_tag( ) -> UserResponse { static GROUPS_WITH_PARENT_TAGS: Lazy> = Lazy::new(|| { PermissionGroup::iter() - .map(|value| (info::get_parent_name(value), value)) + .map(|group| (group.parent(), group)) .fold( HashMap::new(), - |mut acc: HashMap>, - (key, value)| { + |mut acc: HashMap>, (key, value)| { acc.entry(key).or_default().push(value); acc }, @@ -73,6 +79,40 @@ pub async fn get_authorization_info_with_group_tag( )) } +pub async fn get_parent_group_info( + state: SessionState, + user_from_token: auth::UserFromToken, +) -> UserResponse> { + let role_info = roles::RoleInfo::from_role_id_in_merchant_scope( + &state, + &user_from_token.role_id, + &user_from_token.merchant_id, + &user_from_token.org_id, + ) + .await + .to_not_found_response(UserErrors::InvalidRoleId)?; + + let parent_groups = ParentGroup::get_descriptions_for_groups( + role_info.get_entity_type(), + PermissionGroup::iter().collect(), + ) + .into_iter() + .map(|(parent_group, description)| role_api::ParentGroupInfo { + name: parent_group.clone(), + description, + scopes: PermissionGroup::iter() + .filter_map(|group| (group.parent() == parent_group).then_some(group.scope())) + // TODO: Remove this hashset conversion when merhant access + // and organization access groups are removed + .collect::>() + .into_iter() + .collect(), + }) + .collect::>(); + + Ok(ApplicationResponse::Json(parent_groups)) +} + pub async fn update_user_role( state: SessionState, user_from_token: auth::UserFromToken, diff --git a/crates/router/src/core/user_role/role.rs b/crates/router/src/core/user_role/role.rs index b5b5cab421f1..0250415d4fda 100644 --- a/crates/router/src/core/user_role/role.rs +++ b/crates/router/src/core/user_role/role.rs @@ -1,5 +1,7 @@ +use std::collections::HashSet; + use api_models::user_role::role::{self as role_api}; -use common_enums::{EntityType, RoleScope}; +use common_enums::{EntityType, ParentGroup, PermissionGroup, RoleScope}; use common_utils::generate_id_with_default_len; use diesel_models::role::{RoleNew, RoleUpdate}; use error_stack::{report, ResultExt}; @@ -9,7 +11,10 @@ use crate::{ routes::{app::ReqState, SessionState}, services::{ authentication::{blacklist, UserFromToken}, - authorization::roles::{self, predefined_roles::PREDEFINED_ROLES}, + authorization::{ + permission_groups::{ParentGroupExt, PermissionGroupExt}, + roles::{self, predefined_roles::PREDEFINED_ROLES}, + }, ApplicationResponse, }, types::domain::user::RoleName, @@ -19,7 +24,7 @@ use crate::{ pub async fn get_role_from_token_with_groups( state: SessionState, user_from_token: UserFromToken, -) -> UserResponse> { +) -> UserResponse> { let role_info = user_from_token .get_role_info_from_db(&state) .await @@ -30,6 +35,29 @@ pub async fn get_role_from_token_with_groups( Ok(ApplicationResponse::Json(permissions)) } +pub async fn get_groups_and_resources_for_role_from_token( + state: SessionState, + user_from_token: UserFromToken, +) -> UserResponse { + let role_info = user_from_token.get_role_info_from_db(&state).await?; + + let groups = role_info + .get_permission_groups() + .into_iter() + .collect::>(); + let resources = groups + .iter() + .flat_map(|group| group.resources()) + .collect::>() + .into_iter() + .collect(); + + Ok(ApplicationResponse::Json(role_api::GroupsAndResources { + groups, + resources, + })) +} + pub async fn create_role( state: SessionState, user_from_token: UserFromToken, @@ -64,7 +92,7 @@ pub async fn create_role( org_id: user_from_token.org_id, groups: req.groups, scope: req.role_scope, - entity_type: Some(EntityType::Merchant), + entity_type: EntityType::Merchant, created_by: user_from_token.user_id.clone(), last_modified_by: user_from_token.user_id, created_at: now, @@ -111,6 +139,52 @@ pub async fn get_role_with_groups( )) } +pub async fn get_parent_info_for_role( + state: SessionState, + user_from_token: UserFromToken, + role: role_api::GetRoleRequest, +) -> UserResponse { + let role_info = roles::RoleInfo::from_role_id_in_merchant_scope( + &state, + &role.role_id, + &user_from_token.merchant_id, + &user_from_token.org_id, + ) + .await + .to_not_found_response(UserErrors::InvalidRoleId)?; + + if role_info.is_internal() { + return Err(UserErrors::InvalidRoleId.into()); + } + + let parent_groups = ParentGroup::get_descriptions_for_groups( + role_info.get_entity_type(), + role_info.get_permission_groups().to_vec(), + ) + .into_iter() + .map(|(parent_group, description)| role_api::ParentGroupInfo { + name: parent_group.clone(), + description, + scopes: role_info + .get_permission_groups() + .iter() + .filter_map(|group| (group.parent() == parent_group).then_some(group.scope())) + // TODO: Remove this hashset conversion when merhant access + // and organization access groups are removed + .collect::>() + .into_iter() + .collect(), + }) + .collect(); + + Ok(ApplicationResponse::Json(role_api::RoleInfoWithParents { + role_id: role.role_id, + parent_groups, + role_name: role_info.get_role_name().to_string(), + role_scope: role_info.get_scope(), + })) +} + pub async fn update_role( state: SessionState, user_from_token: UserFromToken, diff --git a/crates/router/src/core/utils.rs b/crates/router/src/core/utils.rs index a6a9c36bfda3..abd602760fae 100644 --- a/crates/router/src/core/utils.rs +++ b/crates/router/src/core/utils.rs @@ -217,6 +217,7 @@ pub async fn construct_payout_router_data<'a, F>( integrity_check: Ok(()), additional_merchant_data: None, header_payload: None, + connector_mandate_request_reference_id: None, }; Ok(router_data) @@ -290,7 +291,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(); @@ -395,6 +396,7 @@ pub async fn construct_refund_router_data<'a, F>( integrity_check: Ok(()), additional_merchant_data: None, header_payload: None, + connector_mandate_request_reference_id: None, }; Ok(router_data) @@ -705,6 +707,7 @@ pub async fn construct_accept_dispute_router_data<'a>( integrity_check: Ok(()), additional_merchant_data: None, header_payload: None, + connector_mandate_request_reference_id: None, }; Ok(router_data) } @@ -800,6 +803,7 @@ pub async fn construct_submit_evidence_router_data<'a>( integrity_check: Ok(()), additional_merchant_data: None, header_payload: None, + connector_mandate_request_reference_id: None, }; Ok(router_data) } @@ -901,6 +905,7 @@ pub async fn construct_upload_file_router_data<'a>( integrity_check: Ok(()), additional_merchant_data: None, header_payload: None, + connector_mandate_request_reference_id: None, }; Ok(router_data) } @@ -1022,6 +1027,7 @@ pub async fn construct_payments_dynamic_tax_calculation_router_data<'a, F: Clone integrity_check: Ok(()), additional_merchant_data: None, header_payload: None, + connector_mandate_request_reference_id: None, }; Ok(router_data) } @@ -1120,6 +1126,7 @@ pub async fn construct_defend_dispute_router_data<'a>( integrity_check: Ok(()), additional_merchant_data: None, header_payload: None, + connector_mandate_request_reference_id: None, }; Ok(router_data) } @@ -1212,6 +1219,7 @@ pub async fn construct_retrieve_file_router_data<'a>( integrity_check: Ok(()), additional_merchant_data: None, header_payload: None, + connector_mandate_request_reference_id: None, }; Ok(router_data) } diff --git a/crates/router/src/core/verification/utils.rs b/crates/router/src/core/verification/utils.rs index 8193109c2508..a51b6c86a34f 100644 --- a/crates/router/src/core/verification/utils.rs +++ b/crates/router/src/core/verification/utils.rs @@ -68,36 +68,36 @@ pub async fn check_existence_and_add_domain_to_db( let updated_mca = storage::MerchantConnectorAccountUpdate::Update { connector_type: None, connector_name: None, - connector_account_details: None, + connector_account_details: Box::new(None), test_mode: None, disabled: None, merchant_connector_id: None, payment_methods_enabled: None, metadata: None, frm_configs: None, - connector_webhook_details: None, + connector_webhook_details: Box::new(None), applepay_verified_domains: Some(already_verified_domains.clone()), - pm_auth_config: None, + pm_auth_config: Box::new(None), connector_label: None, status: None, - connector_wallets_details: None, - additional_merchant_data: None, + connector_wallets_details: Box::new(None), + additional_merchant_data: Box::new(None), }; #[cfg(feature = "v2")] let updated_mca = storage::MerchantConnectorAccountUpdate::Update { connector_type: None, - connector_account_details: None, + connector_account_details: Box::new(None), disabled: None, payment_methods_enabled: None, metadata: None, frm_configs: None, connector_webhook_details: None, applepay_verified_domains: Some(already_verified_domains.clone()), - pm_auth_config: None, + pm_auth_config: Box::new(None), connector_label: None, status: None, - connector_wallets_details: None, - additional_merchant_data: None, + connector_wallets_details: Box::new(None), + additional_merchant_data: Box::new(None), }; state .store diff --git a/crates/router/src/core/webhooks/incoming.rs b/crates/router/src/core/webhooks/incoming.rs index 19670fc8ccb8..3627438547cd 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}, }; @@ -615,7 +613,7 @@ async fn payments_incoming_webhook_flow( enums::EventClass::Payments, payment_id.get_string_repr().to_owned(), enums::EventObjectType::PaymentDetails, - api::OutgoingWebhookContent::PaymentDetails(payments_response), + api::OutgoingWebhookContent::PaymentDetails(Box::new(payments_response)), primary_object_created_at, )) .await?; @@ -747,7 +745,7 @@ async fn payouts_incoming_webhook_flow( enums::EventClass::Payouts, updated_payout_attempt.payout_id.clone(), enums::EventObjectType::PayoutDetails, - api::OutgoingWebhookContent::PayoutDetails(payout_create_response), + api::OutgoingWebhookContent::PayoutDetails(Box::new(payout_create_response)), Some(updated_payout_attempt.created_at), )) .await?; @@ -854,7 +852,7 @@ async fn refunds_incoming_webhook_flow( enums::EventClass::Refunds, refund_id, enums::EventObjectType::RefundDetails, - api::OutgoingWebhookContent::RefundDetails(refund_response), + api::OutgoingWebhookContent::RefundDetails(Box::new(refund_response)), Some(updated_refund.created_at), )) .await?; @@ -1130,7 +1128,9 @@ async fn external_authentication_incoming_webhook_flow( enums::EventClass::Payments, payment_id.get_string_repr().to_owned(), enums::EventObjectType::PaymentDetails, - api::OutgoingWebhookContent::PaymentDetails(payments_response), + api::OutgoingWebhookContent::PaymentDetails(Box::new( + payments_response, + )), primary_object_created_at, )) .await?; @@ -1336,7 +1336,7 @@ async fn frm_incoming_webhook_flow( enums::EventClass::Payments, payment_id.get_string_repr().to_owned(), enums::EventObjectType::PaymentDetails, - api::OutgoingWebhookContent::PaymentDetails(payments_response), + api::OutgoingWebhookContent::PaymentDetails(Box::new(payments_response)), primary_object_created_at, )) .await?; @@ -1500,7 +1500,7 @@ async fn bank_transfer_webhook_flow( enums::EventClass::Payments, payment_id.get_string_repr().to_owned(), enums::EventObjectType::PaymentDetails, - api::OutgoingWebhookContent::PaymentDetails(payments_response), + api::OutgoingWebhookContent::PaymentDetails(Box::new(payments_response)), primary_object_created_at, )) .await?; diff --git a/crates/router/src/core/webhooks/outgoing.rs b/crates/router/src/core/webhooks/outgoing.rs index fbf692783571..0a9c17ed3a07 100644 --- a/crates/router/src/core/webhooks/outgoing.rs +++ b/crates/router/src/core/webhooks/outgoing.rs @@ -361,7 +361,7 @@ async fn trigger_webhook_to_merchant( &event_id, client_error, delivery_attempt, - ScheduleWebhookRetry::WithProcessTracker(process_tracker), + ScheduleWebhookRetry::WithProcessTracker(Box::new(process_tracker)), ) .await?; } @@ -391,7 +391,7 @@ async fn trigger_webhook_to_merchant( delivery_attempt, status_code.as_u16(), "An error occurred when sending webhook to merchant", - ScheduleWebhookRetry::WithProcessTracker(process_tracker), + ScheduleWebhookRetry::WithProcessTracker(Box::new(process_tracker)), ) .await?; } @@ -668,7 +668,7 @@ pub(crate) fn get_outgoing_webhook_request( #[derive(Debug)] enum ScheduleWebhookRetry { - WithProcessTracker(storage::ProcessTracker), + WithProcessTracker(Box), NoSchedule, } @@ -757,7 +757,7 @@ async fn api_client_error_handler( outgoing_webhook_retry::retry_webhook_delivery_task( &*state.store, merchant_id, - process_tracker, + *process_tracker, ) .await .change_context(errors::WebhooksFlowError::OutgoingWebhookRetrySchedulingFailed)?; @@ -903,7 +903,7 @@ async fn error_response_handler( outgoing_webhook_retry::retry_webhook_delivery_task( &*state.store, merchant_id, - process_tracker, + *process_tracker, ) .await .change_context(errors::WebhooksFlowError::OutgoingWebhookRetrySchedulingFailed)?; diff --git a/crates/router/src/core/webhooks/utils.rs b/crates/router/src/core/webhooks/utils.rs index 8680e43eff3b..fff675503ad4 100644 --- a/crates/router/src/core/webhooks/utils.rs +++ b/crates/router/src/core/webhooks/utils.rs @@ -64,7 +64,7 @@ pub async fn construct_webhook_router_data<'a>( request_details: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { let auth_type: types::ConnectorAuthType = - helpers::MerchantConnectorAccountType::DbVal(merchant_connector_account.clone()) + helpers::MerchantConnectorAccountType::DbVal(Box::new(merchant_connector_account.clone())) .get_connector_account_details() .parse_value("ConnectorAuthType") .change_context(errors::ApiErrorResponse::InternalServerError)?; @@ -122,6 +122,7 @@ pub async fn construct_webhook_router_data<'a>( integrity_check: Ok(()), additional_merchant_data: None, header_payload: None, + connector_mandate_request_reference_id: None, }; Ok(router_data) } diff --git a/crates/router/src/core/webhooks/webhook_events.rs b/crates/router/src/core/webhooks/webhook_events.rs index 34a7c69d91a0..64b52b7995e3 100644 --- a/crates/router/src/core/webhooks/webhook_events.rs +++ b/crates/router/src/core/webhooks/webhook_events.rs @@ -14,8 +14,8 @@ const INITIAL_DELIVERY_ATTEMPTS_LIST_MAX_LIMIT: i64 = 100; #[derive(Debug)] enum MerchantAccountOrProfile { - MerchantAccount(domain::MerchantAccount), - Profile(domain::Profile), + MerchantAccount(Box), + Profile(Box), } #[instrument(skip(state))] @@ -302,7 +302,7 @@ async fn get_account_and_key_store( })?; Ok(( - MerchantAccountOrProfile::Profile(business_profile), + MerchantAccountOrProfile::Profile(Box::new(business_profile)), merchant_key_store, )) } @@ -318,7 +318,7 @@ async fn get_account_and_key_store( .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?; Ok(( - MerchantAccountOrProfile::MerchantAccount(merchant_account), + MerchantAccountOrProfile::MerchantAccount(Box::new(merchant_account)), merchant_key_store, )) } diff --git a/crates/router/src/db/address.rs b/crates/router/src/db/address.rs index 3a8750feff93..2e2bb7dccbbe 100644 --- a/crates/router/src/db/address.rs +++ b/crates/router/src/db/address.rs @@ -493,12 +493,12 @@ mod storage { let redis_entry = kv::TypedSql { op: kv::DBOperation::Update { - updatable: kv::Updateable::AddressUpdate(Box::new( + updatable: Box::new(kv::Updateable::AddressUpdate(Box::new( kv::AddressUpdateMems { orig: address, update_data: address_update.into(), }, - )), + ))), }, }; @@ -597,7 +597,7 @@ mod storage { let redis_entry = kv::TypedSql { op: kv::DBOperation::Insert { - insertable: kv::Insertable::Address(Box::new(address_new)), + insertable: Box::new(kv::Insertable::Address(Box::new(address_new))), }, }; diff --git a/crates/router/src/db/api_keys.rs b/crates/router/src/db/api_keys.rs index 62d261aa3c4a..0d3ec5dc8c2e 100644 --- a/crates/router/src/db/api_keys.rs +++ b/crates/router/src/db/api_keys.rs @@ -20,20 +20,20 @@ pub trait ApiKeyInterface { async fn update_api_key( &self, merchant_id: common_utils::id_type::MerchantId, - key_id: String, + key_id: common_utils::id_type::ApiKeyId, api_key: storage::ApiKeyUpdate, ) -> CustomResult; async fn revoke_api_key( &self, merchant_id: &common_utils::id_type::MerchantId, - key_id: &str, + key_id: &common_utils::id_type::ApiKeyId, ) -> CustomResult; async fn find_api_key_by_merchant_id_key_id_optional( &self, merchant_id: &common_utils::id_type::MerchantId, - key_id: &str, + key_id: &common_utils::id_type::ApiKeyId, ) -> CustomResult, errors::StorageError>; async fn find_api_key_by_hash_optional( @@ -67,7 +67,7 @@ impl ApiKeyInterface for Store { async fn update_api_key( &self, merchant_id: common_utils::id_type::MerchantId, - key_id: String, + key_id: common_utils::id_type::ApiKeyId, api_key: storage::ApiKeyUpdate, ) -> CustomResult { let conn = connection::pg_connection_write(self).await?; @@ -99,7 +99,8 @@ impl ApiKeyInterface for Store { .await .map_err(|error| report!(errors::StorageError::from(error)))? .ok_or(report!(errors::StorageError::ValueNotFound(format!( - "ApiKey of {_key_id} not found" + "ApiKey of {} not found", + _key_id.get_string_repr() ))))?; cache::publish_and_redact( @@ -115,7 +116,7 @@ impl ApiKeyInterface for Store { async fn revoke_api_key( &self, merchant_id: &common_utils::id_type::MerchantId, - key_id: &str, + key_id: &common_utils::id_type::ApiKeyId, ) -> CustomResult { let conn = connection::pg_connection_write(self).await?; let delete_call = || async { @@ -141,7 +142,8 @@ impl ApiKeyInterface for Store { .await .map_err(|error| report!(errors::StorageError::from(error)))? .ok_or(report!(errors::StorageError::ValueNotFound(format!( - "ApiKey of {key_id} not found" + "ApiKey of {} not found", + key_id.get_string_repr() ))))?; cache::publish_and_redact( @@ -157,7 +159,7 @@ impl ApiKeyInterface for Store { async fn find_api_key_by_merchant_id_key_id_optional( &self, merchant_id: &common_utils::id_type::MerchantId, - key_id: &str, + key_id: &common_utils::id_type::ApiKeyId, ) -> CustomResult, errors::StorageError> { let conn = connection::pg_connection_read(self).await?; storage::ApiKey::find_optional_by_merchant_id_key_id(&conn, merchant_id, key_id) @@ -240,7 +242,7 @@ impl ApiKeyInterface for MockDb { async fn update_api_key( &self, merchant_id: common_utils::id_type::MerchantId, - key_id: String, + key_id: common_utils::id_type::ApiKeyId, api_key: storage::ApiKeyUpdate, ) -> CustomResult { let mut locked_api_keys = self.api_keys.lock().await; @@ -282,13 +284,13 @@ impl ApiKeyInterface for MockDb { async fn revoke_api_key( &self, merchant_id: &common_utils::id_type::MerchantId, - key_id: &str, + key_id: &common_utils::id_type::ApiKeyId, ) -> CustomResult { let mut locked_api_keys = self.api_keys.lock().await; // find the key to remove, if it exists if let Some(pos) = locked_api_keys .iter() - .position(|k| k.merchant_id == *merchant_id && k.key_id == key_id) + .position(|k| k.merchant_id == *merchant_id && k.key_id == *key_id) { // use `remove` instead of `swap_remove` so we have a consistent order, which might // matter to someone using limit/offset in `list_api_keys_by_merchant_id` @@ -302,14 +304,14 @@ impl ApiKeyInterface for MockDb { async fn find_api_key_by_merchant_id_key_id_optional( &self, merchant_id: &common_utils::id_type::MerchantId, - key_id: &str, + key_id: &common_utils::id_type::ApiKeyId, ) -> CustomResult, errors::StorageError> { Ok(self .api_keys .lock() .await .iter() - .find(|k| k.merchant_id == *merchant_id && k.key_id == key_id) + .find(|k| k.merchant_id == *merchant_id && k.key_id == *key_id) .cloned()) } @@ -397,9 +399,16 @@ mod tests { let merchant_id = common_utils::id_type::MerchantId::try_from(Cow::from("merchant1")).unwrap(); + let key_id1 = common_utils::id_type::ApiKeyId::try_from(Cow::from("key_id1")).unwrap(); + + let key_id2 = common_utils::id_type::ApiKeyId::try_from(Cow::from("key_id2")).unwrap(); + + let non_existent_key_id = + common_utils::id_type::ApiKeyId::try_from(Cow::from("does_not_exist")).unwrap(); + let key1 = mockdb .insert_api_key(storage::ApiKeyNew { - key_id: "key_id1".into(), + key_id: key_id1.clone(), merchant_id: merchant_id.clone(), name: "Key 1".into(), description: None, @@ -414,7 +423,7 @@ mod tests { mockdb .insert_api_key(storage::ApiKeyNew { - key_id: "key_id2".into(), + key_id: key_id2.clone(), merchant_id: merchant_id.clone(), name: "Key 2".into(), description: None, @@ -428,13 +437,13 @@ mod tests { .unwrap(); let found_key1 = mockdb - .find_api_key_by_merchant_id_key_id_optional(&merchant_id, "key_id1") + .find_api_key_by_merchant_id_key_id_optional(&merchant_id, &key_id1) .await .unwrap() .unwrap(); assert_eq!(found_key1.key_id, key1.key_id); assert!(mockdb - .find_api_key_by_merchant_id_key_id_optional(&merchant_id, "does_not_exist") + .find_api_key_by_merchant_id_key_id_optional(&merchant_id, &non_existent_key_id) .await .unwrap() .is_none()); @@ -442,7 +451,7 @@ mod tests { mockdb .update_api_key( merchant_id.clone(), - "key_id1".into(), + key_id1.clone(), storage::ApiKeyUpdate::LastUsedUpdate { last_used: datetime!(2023-02-04 1:11), }, @@ -450,7 +459,7 @@ mod tests { .await .unwrap(); let updated_key1 = mockdb - .find_api_key_by_merchant_id_key_id_optional(&merchant_id, "key_id1") + .find_api_key_by_merchant_id_key_id_optional(&merchant_id, &key_id1) .await .unwrap() .unwrap(); @@ -464,10 +473,7 @@ mod tests { .len(), 2 ); - mockdb - .revoke_api_key(&merchant_id, "key_id1") - .await - .unwrap(); + mockdb.revoke_api_key(&merchant_id, &key_id1).await.unwrap(); assert_eq!( mockdb .list_api_keys_by_merchant_id(&merchant_id, None, None) @@ -495,8 +501,10 @@ mod tests { .await .unwrap(); + let test_key = common_utils::id_type::ApiKeyId::try_from(Cow::from("test_ey")).unwrap(); + let api = storage::ApiKeyNew { - key_id: "test_key".into(), + key_id: test_key.clone(), merchant_id: merchant_id.clone(), name: "My test key".into(), description: None, diff --git a/crates/router/src/db/customers.rs b/crates/router/src/db/customers.rs index 5020c238e4a6..ae23f81e2ead 100644 --- a/crates/router/src/db/customers.rs +++ b/crates/router/src/db/customers.rs @@ -446,10 +446,12 @@ mod storage { let redis_entry = kv::TypedSql { op: kv::DBOperation::Update { - updatable: kv::Updateable::CustomerUpdate(kv::CustomerUpdateMems { - orig: customer, - update_data: customer_update.into(), - }), + updatable: Box::new(kv::Updateable::CustomerUpdate( + kv::CustomerUpdateMems { + orig: customer, + update_data: customer_update.into(), + }, + )), }, }; @@ -689,7 +691,7 @@ mod storage { let redis_entry = kv::TypedSql { op: kv::DBOperation::Insert { - insertable: kv::Insertable::Customer(new_customer.clone()), + insertable: Box::new(kv::Insertable::Customer(new_customer.clone())), }, }; let storage_customer = new_customer.into(); @@ -768,7 +770,7 @@ mod storage { let redis_entry = kv::TypedSql { op: kv::DBOperation::Insert { - insertable: kv::Insertable::Customer(new_customer.clone()), + insertable: Box::new(kv::Insertable::Customer(new_customer.clone())), }, }; let storage_customer = new_customer.into(); @@ -931,10 +933,12 @@ mod storage { let redis_entry = kv::TypedSql { op: kv::DBOperation::Update { - updatable: kv::Updateable::CustomerUpdate(kv::CustomerUpdateMems { - orig: customer, - update_data: customer_update.into(), - }), + updatable: Box::new(kv::Updateable::CustomerUpdate( + kv::CustomerUpdateMems { + orig: customer, + update_data: customer_update.into(), + }, + )), }, }; diff --git a/crates/router/src/db/kafka_store.rs b/crates/router/src/db/kafka_store.rs index e92fe6b41b0f..8ca0b2937666 100644 --- a/crates/router/src/db/kafka_store.rs +++ b/crates/router/src/db/kafka_store.rs @@ -226,7 +226,7 @@ impl ApiKeyInterface for KafkaStore { async fn update_api_key( &self, merchant_id: id_type::MerchantId, - key_id: String, + key_id: id_type::ApiKeyId, api_key: storage::ApiKeyUpdate, ) -> CustomResult { self.diesel_store @@ -237,7 +237,7 @@ impl ApiKeyInterface for KafkaStore { async fn revoke_api_key( &self, merchant_id: &id_type::MerchantId, - key_id: &str, + key_id: &id_type::ApiKeyId, ) -> CustomResult { self.diesel_store.revoke_api_key(merchant_id, key_id).await } @@ -245,7 +245,7 @@ impl ApiKeyInterface for KafkaStore { async fn find_api_key_by_merchant_id_key_id_optional( &self, merchant_id: &id_type::MerchantId, - key_id: &str, + key_id: &id_type::ApiKeyId, ) -> CustomResult, errors::StorageError> { self.diesel_store .find_api_key_by_merchant_id_key_id_optional(merchant_id, key_id) @@ -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(), @@ -1601,6 +1601,7 @@ impl PaymentAttemptInterface for KafkaStore { payment_method_type: Option>, authentication_type: Option>, merchant_connector_id: Option>, + card_network: Option>, storage_scheme: MerchantStorageScheme, ) -> CustomResult { self.diesel_store @@ -1612,6 +1613,7 @@ impl PaymentAttemptInterface for KafkaStore { payment_method_type, authentication_type, merchant_connector_id, + card_network, storage_scheme, ) .await diff --git a/crates/router/src/db/mandate.rs b/crates/router/src/db/mandate.rs index 95733805b436..076cb768e611 100644 --- a/crates/router/src/db/mandate.rs +++ b/crates/router/src/db/mandate.rs @@ -274,10 +274,12 @@ mod storage { let redis_entry = kv::TypedSql { op: kv::DBOperation::Update { - updatable: kv::Updateable::MandateUpdate(kv::MandateUpdateMems { - orig: mandate, - update_data: m_update, - }), + updatable: Box::new(kv::Updateable::MandateUpdate( + kv::MandateUpdateMems { + orig: mandate, + update_data: m_update, + }, + )), }, }; @@ -346,7 +348,7 @@ mod storage { let redis_entry = kv::TypedSql { op: kv::DBOperation::Insert { - insertable: kv::Insertable::Mandate(mandate), + insertable: Box::new(kv::Insertable::Mandate(mandate)), }, }; diff --git a/crates/router/src/db/merchant_account.rs b/crates/router/src/db/merchant_account.rs index 13a778001ae0..398445038922 100644 --- a/crates/router/src/db/merchant_account.rs +++ b/crates/router/src/db/merchant_account.rs @@ -482,91 +482,225 @@ impl MerchantAccountInterface for MockDb { merchant_key_store: &domain::MerchantKeyStore, ) -> CustomResult { let accounts = self.merchant_accounts.lock().await; - let account: Option = accounts + accounts .iter() .find(|account| account.get_id() == merchant_id) .cloned() - .async_map(|a| async { - a.convert( - state, - merchant_key_store.key.get_inner(), - merchant_key_store.merchant_id.clone().into(), - ) - .await - .change_context(errors::StorageError::DecryptionError) - }) + .ok_or(errors::StorageError::ValueNotFound(format!( + "Merchant ID: {:?} not found", + merchant_id + )))? + .convert( + state, + merchant_key_store.key.get_inner(), + merchant_key_store.merchant_id.clone().into(), + ) .await - .transpose()?; - - match account { - Some(account) => Ok(account), - // [#172]: Implement function for `MockDb` - None => Err(errors::StorageError::MockDbError)?, - } + .change_context(errors::StorageError::DecryptionError) } async fn update_merchant( &self, - _state: &KeyManagerState, - _this: domain::MerchantAccount, - _merchant_account: storage::MerchantAccountUpdate, - _merchant_key_store: &domain::MerchantKeyStore, + state: &KeyManagerState, + merchant_account: domain::MerchantAccount, + merchant_account_update: storage::MerchantAccountUpdate, + merchant_key_store: &domain::MerchantKeyStore, ) -> CustomResult { - // [#172]: Implement function for `MockDb` - Err(errors::StorageError::MockDbError)? + let merchant_id = merchant_account.get_id().to_owned(); + let mut accounts = self.merchant_accounts.lock().await; + accounts + .iter_mut() + .find(|account| account.get_id() == merchant_account.get_id()) + .async_map(|account| async { + let update = MerchantAccountUpdateInternal::from(merchant_account_update) + .apply_changeset( + Conversion::convert(merchant_account) + .await + .change_context(errors::StorageError::EncryptionError)?, + ); + *account = update.clone(); + update + .convert( + state, + merchant_key_store.key.get_inner(), + merchant_key_store.merchant_id.clone().into(), + ) + .await + .change_context(errors::StorageError::DecryptionError) + }) + .await + .transpose()? + .ok_or( + errors::StorageError::ValueNotFound(format!( + "Merchant ID: {:?} not found", + merchant_id + )) + .into(), + ) } async fn update_specific_fields_in_merchant( &self, - _state: &KeyManagerState, - _merchant_id: &common_utils::id_type::MerchantId, - _merchant_account: storage::MerchantAccountUpdate, - _merchant_key_store: &domain::MerchantKeyStore, + state: &KeyManagerState, + merchant_id: &common_utils::id_type::MerchantId, + merchant_account_update: storage::MerchantAccountUpdate, + merchant_key_store: &domain::MerchantKeyStore, ) -> CustomResult { - // [#TODO]: Implement function for `MockDb` - Err(errors::StorageError::MockDbError)? + let mut accounts = self.merchant_accounts.lock().await; + accounts + .iter_mut() + .find(|account| account.get_id() == merchant_id) + .async_map(|account| async { + let update = MerchantAccountUpdateInternal::from(merchant_account_update) + .apply_changeset(account.clone()); + *account = update.clone(); + update + .convert( + state, + merchant_key_store.key.get_inner(), + merchant_key_store.merchant_id.clone().into(), + ) + .await + .change_context(errors::StorageError::DecryptionError) + }) + .await + .transpose()? + .ok_or( + errors::StorageError::ValueNotFound(format!( + "Merchant ID: {:?} not found", + merchant_id + )) + .into(), + ) } async fn find_merchant_account_by_publishable_key( &self, - _state: &KeyManagerState, - _publishable_key: &str, + state: &KeyManagerState, + publishable_key: &str, ) -> CustomResult { - // [#172]: Implement function for `MockDb` - Err(errors::StorageError::MockDbError)? + let accounts = self.merchant_accounts.lock().await; + let account = accounts + .iter() + .find(|account| { + account + .publishable_key + .as_ref() + .is_some_and(|key| key == publishable_key) + }) + .ok_or(errors::StorageError::ValueNotFound(format!( + "Publishable Key: {} not found", + publishable_key + )))?; + let key_store = self + .get_merchant_key_store_by_merchant_id( + state, + account.get_id(), + &self.get_master_key().to_vec().into(), + ) + .await?; + Ok(authentication::AuthenticationData { + merchant_account: account + .clone() + .convert( + state, + key_store.key.get_inner(), + key_store.merchant_id.clone().into(), + ) + .await + .change_context(errors::StorageError::DecryptionError)?, + + key_store, + profile_id: None, + }) } async fn update_all_merchant_account( &self, - _merchant_account_update: storage::MerchantAccountUpdate, + merchant_account_update: storage::MerchantAccountUpdate, ) -> CustomResult { - Err(errors::StorageError::MockDbError)? + let mut accounts = self.merchant_accounts.lock().await; + Ok(accounts.iter_mut().fold(0, |acc, account| { + let update = MerchantAccountUpdateInternal::from(merchant_account_update.clone()) + .apply_changeset(account.clone()); + *account = update; + acc + 1 + })) } async fn delete_merchant_account_by_merchant_id( &self, - _merchant_id: &common_utils::id_type::MerchantId, + merchant_id: &common_utils::id_type::MerchantId, ) -> CustomResult { - // [#172]: Implement function for `MockDb` - Err(errors::StorageError::MockDbError)? + let mut accounts = self.merchant_accounts.lock().await; + accounts.retain(|x| x.get_id() != merchant_id); + Ok(true) } #[cfg(feature = "olap")] async fn list_merchant_accounts_by_organization_id( &self, - _state: &KeyManagerState, - _organization_id: &common_utils::id_type::OrganizationId, + state: &KeyManagerState, + organization_id: &common_utils::id_type::OrganizationId, ) -> CustomResult, errors::StorageError> { - Err(errors::StorageError::MockDbError)? + let accounts = self.merchant_accounts.lock().await; + let futures = accounts + .iter() + .filter(|account| account.organization_id == *organization_id) + .map(|account| async { + let key_store = self + .get_merchant_key_store_by_merchant_id( + state, + account.get_id(), + &self.get_master_key().to_vec().into(), + ) + .await; + match key_store { + Ok(key) => account + .clone() + .convert(state, key.key.get_inner(), key.merchant_id.clone().into()) + .await + .change_context(errors::StorageError::DecryptionError), + Err(err) => Err(err), + } + }); + futures::future::join_all(futures) + .await + .into_iter() + .collect() } #[cfg(feature = "olap")] async fn list_multiple_merchant_accounts( &self, - _state: &KeyManagerState, - _merchant_ids: Vec, + state: &KeyManagerState, + merchant_ids: Vec, ) -> CustomResult, errors::StorageError> { - Err(errors::StorageError::MockDbError)? + let accounts = self.merchant_accounts.lock().await; + let futures = accounts + .iter() + .filter(|account| merchant_ids.contains(account.get_id())) + .map(|account| async { + let key_store = self + .get_merchant_key_store_by_merchant_id( + state, + account.get_id(), + &self.get_master_key().to_vec().into(), + ) + .await; + match key_store { + Ok(key) => account + .clone() + .convert(state, key.key.get_inner(), key.merchant_id.clone().into()) + .await + .change_context(errors::StorageError::DecryptionError), + Err(err) => Err(err), + } + }); + futures::future::join_all(futures) + .await + .into_iter() + .collect() } } diff --git a/crates/router/src/db/payment_method.rs b/crates/router/src/db/payment_method.rs index e75fb940a35b..ac66ed707f13 100644 --- a/crates/router/src/db/payment_method.rs +++ b/crates/router/src/db/payment_method.rs @@ -496,7 +496,7 @@ mod storage { let redis_entry = kv::TypedSql { op: kv::DBOperation::Insert { - insertable: kv::Insertable::PaymentMethod(payment_method_new), + insertable: Box::new(kv::Insertable::PaymentMethod(payment_method_new)), }, }; @@ -588,12 +588,12 @@ mod storage { let redis_entry = kv::TypedSql { op: kv::DBOperation::Update { - updatable: kv::Updateable::PaymentMethodUpdate( + updatable: Box::new(kv::Updateable::PaymentMethodUpdate(Box::new( kv::PaymentMethodUpdateMems { orig: payment_method, update_data: p_update, }, - ), + ))), }, }; diff --git a/crates/router/src/db/refund.rs b/crates/router/src/db/refund.rs index 41cb3cef5c63..745170d70754 100644 --- a/crates/router/src/db/refund.rs +++ b/crates/router/src/db/refund.rs @@ -445,7 +445,7 @@ mod storage { let redis_entry = kv::TypedSql { op: kv::DBOperation::Insert { - insertable: kv::Insertable::Refund(new), + insertable: Box::new(kv::Insertable::Refund(new)), }, }; @@ -617,10 +617,12 @@ mod storage { let redis_entry = kv::TypedSql { op: kv::DBOperation::Update { - updatable: kv::Updateable::RefundUpdate(kv::RefundUpdateMems { - orig: this, - update_data: refund, - }), + updatable: Box::new(kv::Updateable::RefundUpdate( + kv::RefundUpdateMems { + orig: this, + update_data: refund, + }, + )), }, }; diff --git a/crates/router/src/db/reverse_lookup.rs b/crates/router/src/db/reverse_lookup.rs index 06bd84675b11..c022c70d9e23 100644 --- a/crates/router/src/db/reverse_lookup.rs +++ b/crates/router/src/db/reverse_lookup.rs @@ -116,7 +116,7 @@ mod storage { }; let redis_entry = kv::TypedSql { op: kv::DBOperation::Insert { - insertable: kv::Insertable::ReverseLookUp(new), + insertable: Box::new(kv::Insertable::ReverseLookUp(new)), }, }; diff --git a/crates/router/src/db/role.rs b/crates/router/src/db/role.rs index ce009d38a9ec..d13508356e5a 100644 --- a/crates/router/src/db/role.rs +++ b/crates/router/src/db/role.rs @@ -354,7 +354,7 @@ impl RoleInterface for MockDb { None => true, }; - matches_merchant && role.org_id == *org_id && role.entity_type == entity_type + matches_merchant && role.org_id == *org_id && Some(role.entity_type) == entity_type }) .take(limit_usize) .cloned() diff --git a/crates/router/src/db/user/sample_data.rs b/crates/router/src/db/user/sample_data.rs index 3add7b744d0c..37007b13f285 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/events/audit_events.rs b/crates/router/src/events/audit_events.rs index 367a573a93b3..9b7a688f7eba 100644 --- a/crates/router/src/events/audit_events.rs +++ b/crates/router/src/events/audit_events.rs @@ -18,7 +18,7 @@ pub enum AuditEventType { PaymentConfirm { client_src: Option, client_ver: Option, - frm_message: Option, + frm_message: Box>, }, PaymentCancelled { cancellation_reason: Option, diff --git a/crates/router/src/events/outgoing_webhook_logs.rs b/crates/router/src/events/outgoing_webhook_logs.rs index b2a8202e0e69..db5a40fc6ea7 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"})), }), diff --git a/crates/router/src/lib.rs b/crates/router/src/lib.rs index bb852300222f..06ab971925bc 100644 --- a/crates/router/src/lib.rs +++ b/crates/router/src/lib.rs @@ -66,6 +66,7 @@ pub mod headers { pub const X_API_VERSION: &str = "X-ApiVersion"; pub const X_FORWARDED_FOR: &str = "X-Forwarded-For"; pub const X_MERCHANT_ID: &str = "X-Merchant-Id"; + pub const X_ORGANIZATION_ID: &str = "X-Organization-Id"; pub const X_LOGIN: &str = "X-Login"; pub const X_TRANS_KEY: &str = "X-Trans-Key"; pub const X_VERSION: &str = "X-Version"; @@ -87,6 +88,8 @@ 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"; } pub mod pii { diff --git a/crates/router/src/middleware.rs b/crates/router/src/middleware.rs index c80d14b9e253..0185d8a0768a 100644 --- a/crates/router/src/middleware.rs +++ b/crates/router/src/middleware.rs @@ -147,10 +147,11 @@ where .and_then(|i| i.to_str().ok()) .map(|s| s.to_owned()); let response_fut = self.service.call(req); + let tenant_id_clone = tenant_id.clone(); Box::pin( async move { - if let Some(tenant_id) = tenant_id { - router_env::tracing::Span::current().record("tenant_id", &tenant_id); + if let Some(tenant) = tenant_id_clone { + router_env::tracing::Span::current().record("tenant_id", tenant); } let response = response_fut.await; router_env::tracing::Span::current().record("golden_log_line", true); @@ -166,7 +167,7 @@ where status_code = Empty, flow = "UNKNOWN", golden_log_line = Empty, - tenant_id = "ta" + tenant_id = &tenant_id ) .or_current(), ), diff --git a/crates/router/src/routes/admin.rs b/crates/router/src/routes/admin.rs index 78238d3af07c..0996838b4cfa 100644 --- a/crates/router/src/routes/admin.rs +++ b/crates/router/src/routes/admin.rs @@ -1,5 +1,4 @@ use actix_web::{web, HttpRequest, HttpResponse}; -use common_enums::EntityType; use router_env::{instrument, tracing, Flow}; use super::app::AppState; @@ -52,8 +51,7 @@ pub async fn organization_update( &auth::AdminApiAuth, &auth::JWTAuthOrganizationFromRoute { organization_id, - required_permission: Permission::MerchantAccountWrite, - minimum_entity_level: EntityType::Organization, + required_permission: Permission::OrganizationAccountWrite, }, req.headers(), ), @@ -85,8 +83,7 @@ pub async fn organization_retrieve( &auth::AdminApiAuth, &auth::JWTAuthOrganizationFromRoute { organization_id, - required_permission: Permission::MerchantAccountRead, - minimum_entity_level: EntityType::Organization, + required_permission: Permission::OrganizationAccountRead, }, req.headers(), ), @@ -95,7 +92,7 @@ pub async fn organization_retrieve( .await } -#[cfg(feature = "olap")] +#[cfg(all(feature = "olap", feature = "v1"))] #[instrument(skip_all, fields(flow = ?Flow::MerchantsAccountCreate))] pub async fn merchant_account_create( state: web::Data, @@ -115,6 +112,43 @@ pub async fn merchant_account_create( .await } +#[cfg(all(feature = "olap", feature = "v2"))] +#[instrument(skip_all, fields(flow = ?Flow::MerchantsAccountCreate))] +pub async fn merchant_account_create( + state: web::Data, + req: HttpRequest, + json_payload: web::Json, +) -> HttpResponse { + let flow = Flow::MerchantsAccountCreate; + let headers = req.headers(); + + let org_id = match auth::HeaderMapStruct::new(headers).get_organization_id_from_header() { + Ok(org_id) => org_id, + Err(e) => return api::log_and_return_error_response(e), + }; + + // Converting from MerchantAccountCreateWithoutOrgId to MerchantAccountCreate so we can use the existing + // `create_merchant_account` function for v2 as well + let json_payload = json_payload.into_inner(); + let new_request_payload_with_org_id = api_models::admin::MerchantAccountCreate { + merchant_name: json_payload.merchant_name, + merchant_details: json_payload.merchant_details, + metadata: json_payload.metadata, + organization_id: org_id, + }; + + Box::pin(api::server_wrap( + flow, + state, + &req, + new_request_payload_with_org_id, + |state, _, req, _| create_merchant_account(state, req), + &auth::AdminApiAuth, + api_locking::LockAction::NotApplicable, + )) + .await +} + /// Merchant Account - Retrieve /// /// Retrieve a merchant account details. @@ -139,8 +173,11 @@ pub async fn retrieve_merchant_account( &auth::AdminApiAuth, &auth::JWTAuthMerchantFromRoute { merchant_id, - required_permission: Permission::MerchantAccountRead, - minimum_entity_level: EntityType::Profile, + // This should ideally be MerchantAccountRead, but since FE is calling this API for + // profile level users currently keeping this as ProfileAccountRead. FE is removing + // this API call for profile level users. + // TODO: Convert this to MerchantAccountRead once FE changes are done. + required_permission: Permission::ProfileAccountRead, }, req.headers(), ), @@ -172,7 +209,6 @@ pub async fn merchant_account_list( &auth::AdminApiAuth, &auth::JWTAuthMerchantFromHeader { required_permission: Permission::MerchantAccountRead, - minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -200,7 +236,6 @@ pub async fn merchant_account_list( &auth::AdminApiAuth, &auth::JWTAuthMerchantFromHeader { required_permission: Permission::MerchantAccountRead, - minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -232,7 +267,6 @@ pub async fn update_merchant_account( &auth::JWTAuthMerchantFromRoute { merchant_id: merchant_id.clone(), required_permission: Permission::MerchantAccountWrite, - minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -298,8 +332,7 @@ pub async fn connector_create( &auth::AdminApiAuthWithMerchantIdFromRoute(merchant_id.clone()), &auth::JWTAuthMerchantFromRoute { merchant_id: merchant_id.clone(), - required_permission: Permission::MerchantConnectorAccountWrite, - minimum_entity_level: EntityType::Profile, + required_permission: Permission::ProfileConnectorWrite, }, req.headers(), ), @@ -336,8 +369,7 @@ pub async fn connector_create( auth::auth_type( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromHeader { - required_permission: Permission::MerchantConnectorAccountWrite, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantConnectorWrite, }, req.headers(), ), @@ -399,8 +431,7 @@ pub async fn connector_retrieve( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromRoute { merchant_id, - required_permission: Permission::MerchantConnectorAccountRead, - minimum_entity_level: EntityType::Profile, + required_permission: Permission::ProfileConnectorRead, }, req.headers(), ), @@ -438,8 +469,7 @@ pub async fn connector_retrieve( auth::auth_type( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromHeader { - required_permission: Permission::MerchantConnectorAccountRead, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantConnectorRead, }, req.headers(), ), @@ -469,8 +499,7 @@ pub async fn connector_list( auth::auth_type( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromHeader { - required_permission: Permission::MerchantConnectorAccountRead, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantConnectorRead, }, req.headers(), ), @@ -517,8 +546,7 @@ pub async fn connector_list( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromRoute { merchant_id, - required_permission: Permission::MerchantConnectorAccountRead, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantConnectorRead, }, req.headers(), ), @@ -569,8 +597,7 @@ pub async fn connector_list_profile( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromRoute { merchant_id, - required_permission: Permission::MerchantConnectorAccountRead, - minimum_entity_level: EntityType::Profile, + required_permission: Permission::ProfileConnectorRead, }, req.headers(), ), @@ -631,8 +658,7 @@ pub async fn connector_update( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromRoute { merchant_id: merchant_id.clone(), - required_permission: Permission::MerchantConnectorAccountWrite, - minimum_entity_level: EntityType::Profile, + required_permission: Permission::ProfileConnectorWrite, }, req.headers(), ), @@ -683,8 +709,7 @@ pub async fn connector_update( &auth::AdminApiAuth, &auth::JWTAuthMerchantFromRoute { merchant_id: merchant_id.clone(), - required_permission: Permission::MerchantConnectorAccountWrite, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantConnectorWrite, }, req.headers(), ), @@ -739,8 +764,7 @@ pub async fn connector_delete( &auth::AdminApiAuth, &auth::JWTAuthMerchantFromRoute { merchant_id, - required_permission: Permission::MerchantConnectorAccountWrite, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantConnectorWrite, }, req.headers(), ), @@ -778,8 +802,7 @@ pub async fn connector_delete( auth::auth_type( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromHeader { - required_permission: Permission::MerchantConnectorAccountWrite, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantConnectorWrite, }, req.headers(), ), diff --git a/crates/router/src/routes/api_keys.rs b/crates/router/src/routes/api_keys.rs index 047e0d9b8863..1a2f60bcccb4 100644 --- a/crates/router/src/routes/api_keys.rs +++ b/crates/router/src/routes/api_keys.rs @@ -1,5 +1,4 @@ use actix_web::{web, HttpRequest, Responder}; -use common_enums::EntityType; use router_env::{instrument, tracing, Flow}; use super::app::AppState; @@ -33,8 +32,7 @@ pub async fn api_key_create( &auth::AdminApiAuthWithMerchantIdFromRoute(merchant_id.clone()), &auth::JWTAuthMerchantFromRoute { merchant_id: merchant_id.clone(), - required_permission: Permission::ApiKeyWrite, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantApiKeyWrite, }, req.headers(), ), @@ -64,8 +62,7 @@ pub async fn api_key_create( auth::auth_type( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromHeader { - required_permission: Permission::ApiKeyWrite, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantApiKeyWrite, }, req.headers(), ), @@ -79,7 +76,7 @@ pub async fn api_key_create( pub async fn api_key_retrieve( state: web::Data, req: HttpRequest, - path: web::Path, + path: web::Path, ) -> impl Responder { let flow = Flow::ApiKeyRetrieve; let key_id = path.into_inner(); @@ -93,14 +90,13 @@ pub async fn api_key_retrieve( api_keys::retrieve_api_key( state, auth_data.merchant_account.get_id().to_owned(), - key_id, + key_id.to_owned(), ) }, auth::auth_type( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromHeader { - required_permission: Permission::ApiKeyRead, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantApiKeyRead, }, req.headers(), ), @@ -114,7 +110,10 @@ pub async fn api_key_retrieve( pub async fn api_key_retrieve( state: web::Data, req: HttpRequest, - path: web::Path<(common_utils::id_type::MerchantId, String)>, + path: web::Path<( + common_utils::id_type::MerchantId, + common_utils::id_type::ApiKeyId, + )>, ) -> impl Responder { let flow = Flow::ApiKeyRetrieve; let (merchant_id, key_id) = path.into_inner(); @@ -123,14 +122,13 @@ pub async fn api_key_retrieve( flow, state, &req, - (merchant_id.clone(), &key_id), + (merchant_id.clone(), key_id.clone()), |state, _, (merchant_id, key_id), _| api_keys::retrieve_api_key(state, merchant_id, key_id), auth::auth_type( &auth::AdminApiAuth, &auth::JWTAuthMerchantFromRoute { merchant_id: merchant_id.clone(), - required_permission: Permission::ApiKeyRead, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantApiKeyRead, }, req.headers(), ), @@ -144,7 +142,10 @@ pub async fn api_key_retrieve( pub async fn api_key_update( state: web::Data, req: HttpRequest, - path: web::Path<(common_utils::id_type::MerchantId, String)>, + path: web::Path<( + common_utils::id_type::MerchantId, + common_utils::id_type::ApiKeyId, + )>, json_payload: web::Json, ) -> impl Responder { let flow = Flow::ApiKeyUpdate; @@ -163,8 +164,7 @@ pub async fn api_key_update( &auth::AdminApiAuth, &auth::JWTAuthMerchantFromRoute { merchant_id, - required_permission: Permission::ApiKeyWrite, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantApiKeyWrite, }, req.headers(), ), @@ -177,7 +177,7 @@ pub async fn api_key_update( pub async fn api_key_update( state: web::Data, req: HttpRequest, - key_id: web::Path, + key_id: web::Path, json_payload: web::Json, ) -> impl Responder { let flow = Flow::ApiKeyUpdate; @@ -197,8 +197,7 @@ pub async fn api_key_update( auth::auth_type( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromHeader { - required_permission: Permission::ApiKeyRead, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantApiKeyRead, }, req.headers(), ), @@ -212,7 +211,10 @@ pub async fn api_key_update( pub async fn api_key_revoke( state: web::Data, req: HttpRequest, - path: web::Path<(common_utils::id_type::MerchantId, String)>, + path: web::Path<( + common_utils::id_type::MerchantId, + common_utils::id_type::ApiKeyId, + )>, ) -> impl Responder { let flow = Flow::ApiKeyRevoke; let (merchant_id, key_id) = path.into_inner(); @@ -227,8 +229,7 @@ pub async fn api_key_revoke( &auth::AdminApiAuth, &auth::JWTAuthMerchantFromRoute { merchant_id: merchant_id.clone(), - required_permission: Permission::ApiKeyWrite, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantApiKeyWrite, }, req.headers(), ), @@ -242,7 +243,10 @@ pub async fn api_key_revoke( pub async fn api_key_revoke( state: web::Data, req: HttpRequest, - path: web::Path<(common_utils::id_type::MerchantId, String)>, + path: web::Path<( + common_utils::id_type::MerchantId, + common_utils::id_type::ApiKeyId, + )>, ) -> impl Responder { let flow = Flow::ApiKeyRevoke; let (merchant_id, key_id) = path.into_inner(); @@ -257,8 +261,7 @@ pub async fn api_key_revoke( &auth::AdminApiAuth, &auth::JWTAuthMerchantFromRoute { merchant_id: merchant_id.clone(), - required_permission: Permission::ApiKeyWrite, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantApiKeyWrite, }, req.headers(), ), @@ -293,8 +296,7 @@ pub async fn api_key_list( &auth::AdminApiAuth, &auth::JWTAuthMerchantFromRoute { merchant_id, - required_permission: Permission::ApiKeyRead, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantApiKeyRead, }, req.headers(), ), @@ -324,8 +326,7 @@ pub async fn api_key_list( auth::auth_type( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromHeader { - required_permission: Permission::ApiKeyRead, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantApiKeyRead, }, req.headers(), ), diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs index 274ed6a5cc03..ae099a36e444 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")] @@ -207,7 +207,7 @@ pub struct AppState { } impl scheduler::SchedulerAppState for AppState { fn get_tenants(&self) -> Vec { - self.conf.multitenancy.get_tenant_names() + self.conf.multitenancy.get_tenant_ids() } } pub trait AppStateInfo { @@ -517,17 +517,25 @@ 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("/get-intent") + .route(web::get().to(payments::payments_get_intent)), + ) + .service( + web::resource("/create-external-sdk-tokens") + .route(web::post().to(payments::payments_connector_session)), + ), + ); route } @@ -543,106 +551,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 +1471,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)), + ) } } @@ -1805,9 +1823,14 @@ impl User { web::resource("/permission_info") .route(web::get().to(user_role::get_authorization_info)), ) + // TODO: To be deprecated .service( web::resource("/module/list").route(web::get().to(user_role::get_role_information)), ) + .service( + web::resource("/parent/list") + .route(web::get().to(user_role::get_parent_group_info)), + ) .service( web::resource("/update").route(web::post().to(user::update_user_account_details)), ) @@ -2003,6 +2026,9 @@ impl User { .route(web::get().to(user_role::get_role_from_token)) .route(web::post().to(user_role::create_role)), ) + .service(web::resource("/v2").route( + web::get().to(user_role::get_groups_and_resources_for_role_from_token), + )) // TODO: To be deprecated .service( web::resource("/v2/list") @@ -2025,6 +2051,10 @@ impl User { web::resource("/{role_id}") .route(web::get().to(user_role::get_role)) .route(web::put().to(user_role::update_role)), + ) + .service( + web::resource("/{role_id}/v2") + .route(web::get().to(user_role::get_parent_info_for_role)), ), ); diff --git a/crates/router/src/routes/blocklist.rs b/crates/router/src/routes/blocklist.rs index 4738df5ed2ca..f54f61d8a002 100644 --- a/crates/router/src/routes/blocklist.rs +++ b/crates/router/src/routes/blocklist.rs @@ -1,6 +1,5 @@ use actix_web::{web, HttpRequest, HttpResponse}; use api_models::blocklist as api_blocklist; -use common_enums::EntityType; use router_env::Flow; use crate::{ @@ -39,7 +38,6 @@ pub async fn add_entry_to_blocklist( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { permission: Permission::MerchantAccountWrite, - minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -78,7 +76,6 @@ pub async fn remove_entry_from_blocklist( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { permission: Permission::MerchantAccountWrite, - minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -119,7 +116,6 @@ pub async fn list_blocked_payment_methods( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { permission: Permission::MerchantAccountRead, - minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -160,7 +156,6 @@ pub async fn toggle_blocklist_guard( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { permission: Permission::MerchantAccountWrite, - minimum_entity_level: EntityType::Merchant, }, req.headers(), ), diff --git a/crates/router/src/routes/connector_onboarding.rs b/crates/router/src/routes/connector_onboarding.rs index f7494e182c19..8ecd321df948 100644 --- a/crates/router/src/routes/connector_onboarding.rs +++ b/crates/router/src/routes/connector_onboarding.rs @@ -1,6 +1,5 @@ use actix_web::{web, HttpRequest, HttpResponse}; use api_models::connector_onboarding as api_types; -use common_enums::EntityType; use router_env::Flow; use super::AppState; @@ -24,7 +23,6 @@ pub async fn get_action_url( core::get_action_url, &auth::JWTAuth { permission: Permission::MerchantAccountWrite, - minimum_entity_level: EntityType::Merchant, }, api_locking::LockAction::NotApplicable, )) @@ -46,7 +44,6 @@ pub async fn sync_onboarding_status( core::sync_onboarding_status, &auth::JWTAuth { permission: Permission::MerchantAccountWrite, - minimum_entity_level: EntityType::Merchant, }, api_locking::LockAction::NotApplicable, )) @@ -68,7 +65,6 @@ pub async fn reset_tracking_id( core::reset_tracking_id, &auth::JWTAuth { permission: Permission::MerchantAccountWrite, - minimum_entity_level: EntityType::Merchant, }, api_locking::LockAction::NotApplicable, )) diff --git a/crates/router/src/routes/customers.rs b/crates/router/src/routes/customers.rs index 536bca10f3df..5ff155966a0f 100644 --- a/crates/router/src/routes/customers.rs +++ b/crates/router/src/routes/customers.rs @@ -1,5 +1,4 @@ use actix_web::{web, HttpRequest, HttpResponse, Responder}; -use common_enums::EntityType; #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] use common_utils::id_type; use router_env::{instrument, tracing, Flow}; @@ -29,8 +28,7 @@ pub async fn customers_create( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::CustomerWrite, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantCustomerWrite, }, req.headers(), ), @@ -55,8 +53,7 @@ pub async fn customers_retrieve( let auth = if auth::is_jwt_auth(req.headers()) { Box::new(auth::JWTAuth { - permission: Permission::CustomerRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantCustomerRead, }) } else { match auth::is_ephemeral_auth(req.headers()) { @@ -98,8 +95,7 @@ pub async fn customers_retrieve( let auth = if auth::is_jwt_auth(req.headers()) { Box::new(auth::JWTAuth { - permission: Permission::CustomerRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantCustomerRead, }) } else { match auth::is_ephemeral_auth(req.headers()) { @@ -148,8 +144,7 @@ pub async fn customers_list( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::CustomerRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantCustomerRead, }, req.headers(), ), @@ -187,8 +182,7 @@ pub async fn customers_update( auth::auth_type( &auth::ApiKeyAuth, &auth::JWTAuth { - permission: Permission::CustomerWrite, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantCustomerWrite, }, req.headers(), ), @@ -225,8 +219,7 @@ pub async fn customers_update( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::CustomerWrite, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantCustomerWrite, }, req.headers(), ), @@ -256,8 +249,7 @@ pub async fn customers_delete( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::CustomerWrite, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantCustomerWrite, }, req.headers(), ), @@ -290,8 +282,7 @@ pub async fn customers_delete( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::CustomerWrite, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantCustomerWrite, }, req.headers(), ), @@ -328,8 +319,7 @@ pub async fn get_customer_mandates( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::MandateRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantMandateRead, }, req.headers(), ), diff --git a/crates/router/src/routes/disputes.rs b/crates/router/src/routes/disputes.rs index 22c1e3f19888..5577bb96ef01 100644 --- a/crates/router/src/routes/disputes.rs +++ b/crates/router/src/routes/disputes.rs @@ -1,7 +1,6 @@ use actix_multipart::Multipart; use actix_web::{web, HttpRequest, HttpResponse}; use api_models::disputes as dispute_models; -use common_enums::EntityType; use router_env::{instrument, tracing, Flow}; use crate::{core::api_locking, services::authorization::permissions::Permission}; @@ -50,8 +49,7 @@ pub async fn retrieve_dispute( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::DisputeRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileDisputeRead, }, req.headers(), ), @@ -102,8 +100,7 @@ pub async fn retrieve_disputes_list( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::DisputeRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantDisputeRead, }, req.headers(), ), @@ -160,8 +157,7 @@ pub async fn retrieve_disputes_list_profile( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::DisputeRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileDisputeRead, }, req.headers(), ), @@ -195,8 +191,7 @@ pub async fn get_disputes_filters(state: web::Data, req: HttpRequest) auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::DisputeRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantDisputeRead, }, req.headers(), ), @@ -237,8 +232,7 @@ pub async fn get_disputes_filters_profile( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::DisputeRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileDisputeRead, }, req.headers(), ), @@ -289,8 +283,7 @@ pub async fn accept_dispute( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::DisputeWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileDisputeWrite, }, req.headers(), ), @@ -335,8 +328,7 @@ pub async fn submit_dispute_evidence( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::DisputeWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileDisputeWrite, }, req.headers(), ), @@ -389,8 +381,7 @@ pub async fn attach_dispute_evidence( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::DisputeWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileDisputeWrite, }, req.headers(), ), @@ -435,8 +426,7 @@ pub async fn retrieve_dispute_evidence( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::DisputeRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileDisputeRead, }, req.headers(), ), @@ -478,8 +468,7 @@ pub async fn delete_dispute_evidence( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::DisputeWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileDisputeWrite, }, req.headers(), ), @@ -508,8 +497,7 @@ pub async fn get_disputes_aggregate( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::DisputeRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantDisputeRead, }, req.headers(), ), @@ -543,8 +531,7 @@ pub async fn get_disputes_aggregate_profile( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::DisputeRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileDisputeRead, }, req.headers(), ), diff --git a/crates/router/src/routes/lock_utils.rs b/crates/router/src/routes/lock_utils.rs index cb16d6e05058..43ddc35b8ae6 100644 --- a/crates/router/src/routes/lock_utils.rs +++ b/crates/router/src/routes/lock_utils.rs @@ -137,7 +137,9 @@ impl From for ApiIdentifier { | Flow::PaymentsCompleteAuthorize | Flow::PaymentsManualUpdate | Flow::SessionUpdateTaxCalculation + | Flow::PaymentsConfirmIntent | Flow::PaymentsCreateIntent + | Flow::PaymentsGetIntent | Flow::PaymentsPostSessionTokens => Self::Payments, Flow::PayoutsCreate @@ -262,10 +264,13 @@ impl From for ApiIdentifier { | Flow::ListInvitableRolesAtEntityLevel | Flow::ListUpdatableRolesAtEntityLevel | Flow::GetRole + | Flow::GetRoleV2 | Flow::GetRoleFromToken + | Flow::GetRoleFromTokenV2 | Flow::UpdateUserRole | Flow::GetAuthorizationInfo | Flow::GetRolesInfo + | Flow::GetParentGroupInfo | Flow::AcceptInvitationsV2 | Flow::AcceptInvitationsPreAuth | Flow::DeleteUserRole diff --git a/crates/router/src/routes/mandates.rs b/crates/router/src/routes/mandates.rs index c0ccbfa9f8fe..cb832d81a165 100644 --- a/crates/router/src/routes/mandates.rs +++ b/crates/router/src/routes/mandates.rs @@ -1,5 +1,4 @@ use actix_web::{web, HttpRequest, HttpResponse}; -use common_enums::EntityType; use router_env::{instrument, tracing, Flow}; use super::app::AppState; @@ -117,8 +116,7 @@ pub async fn retrieve_mandates_list( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::MandateRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantMandateRead, }, req.headers(), ), diff --git a/crates/router/src/routes/payment_methods.rs b/crates/router/src/routes/payment_methods.rs index 8d95ee64ad0d..3b47a06cf7c6 100644 --- a/crates/router/src/routes/payment_methods.rs +++ b/crates/router/src/routes/payment_methods.rs @@ -4,7 +4,6 @@ ))] use actix_multipart::form::MultipartForm; use actix_web::{web, HttpRequest, HttpResponse}; -use common_enums::EntityType; use common_utils::{errors::CustomResult, id_type}; use diesel_models::enums::IntentStatus; use error_stack::ResultExt; @@ -332,10 +331,13 @@ pub async fn migrate_payment_methods( MultipartForm(form): MultipartForm, ) -> HttpResponse { let flow = Flow::PaymentMethodsMigrate; - let (merchant_id, records) = match migration::get_payment_method_records(form) { - Ok((merchant_id, records)) => (merchant_id, records), - Err(e) => return api::log_and_return_error_response(e.into()), - }; + let (merchant_id, records, merchant_connector_id) = + match migration::get_payment_method_records(form) { + Ok((merchant_id, records, merchant_connector_id)) => { + (merchant_id, records, merchant_connector_id) + } + Err(e) => return api::log_and_return_error_response(e.into()), + }; Box::pin(api::server_wrap( flow, state, @@ -343,6 +345,7 @@ pub async fn migrate_payment_methods( records, |state, _, req, _| { let merchant_id = merchant_id.clone(); + let merchant_connector_id = merchant_connector_id.clone(); async move { let (key_store, merchant_account) = get_merchant_account(&state, &merchant_id).await?; @@ -350,7 +353,7 @@ pub async fn migrate_payment_methods( customers::migrate_customers( state.clone(), req.iter() - .map(|e| CustomerRequest::from(e.clone())) + .map(|e| CustomerRequest::from((e.clone(), merchant_id.clone()))) .collect(), merchant_account.clone(), key_store.clone(), @@ -363,6 +366,7 @@ pub async fn migrate_payment_methods( &merchant_id, &merchant_account, &key_store, + merchant_connector_id, )) .await } @@ -881,15 +885,13 @@ pub async fn list_countries_currencies_for_connector_payment_method( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::MerchantConnectorAccountWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileConnectorWrite, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuth { - permission: Permission::MerchantConnectorAccountWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileConnectorWrite, }, api_locking::LockAction::NotApplicable, )) diff --git a/crates/router/src/routes/payments.rs b/crates/router/src/routes/payments.rs index eba1fa84c985..62cb4a0b79b1 100644 --- a/crates/router/src/routes/payments.rs +++ b/crates/router/src/routes/payments.rs @@ -5,9 +5,8 @@ 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}; @@ -93,8 +92,7 @@ pub async fn payments_create( _ => auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::PaymentWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfilePaymentWrite, }, req.headers(), ), @@ -127,20 +125,19 @@ pub async fn payments_create_intent( json_payload.into_inner(), |state, auth: auth::AuthenticationDataV2, req, req_state| { payments::payments_intent_core::< - api_types::CreateIntent, - payment_types::PaymentsCreateIntentResponse, + api_types::PaymentCreateIntent, + payment_types::PaymentsIntentResponse, _, _, - PaymentIntentData, + PaymentIntentData, >( state, req_state, auth.merchant_account, auth.profile, auth.key_store, - payments::operations::PaymentCreateIntent, + payments::operations::PaymentIntentCreate, req, - api::AuthFlow::Client, header_payload.clone(), ) }, @@ -149,8 +146,7 @@ pub async fn payments_create_intent( _ => auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::PaymentWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfilePaymentWrite, }, req.headers(), ), @@ -160,6 +156,57 @@ pub async fn payments_create_intent( .await } +#[cfg(feature = "v2")] +#[instrument(skip_all, fields(flow = ?Flow::PaymentsGetIntent, payment_id))] +pub async fn payments_get_intent( + state: web::Data, + req: actix_web::HttpRequest, + path: web::Path, +) -> impl Responder { + use api_models::payments::PaymentsGetIntentRequest; + use hyperswitch_domain_models::payments::PaymentIntentData; + + let flow = Flow::PaymentsGetIntent; + let header_payload = match HeaderPayload::foreign_try_from(req.headers()) { + Ok(headers) => headers, + Err(err) => { + return api::log_and_return_error_response(err); + } + }; + + let payload = PaymentsGetIntentRequest { + id: path.into_inner(), + }; + + Box::pin(api::server_wrap( + flow, + state, + &req, + payload, + |state, auth: auth::AuthenticationDataV2, req, req_state| { + payments::payments_intent_core::< + api_types::PaymentGetIntent, + payment_types::PaymentsIntentResponse, + _, + _, + PaymentIntentData, + >( + state, + req_state, + auth.merchant_account, + auth.profile, + auth.key_store, + payments::operations::PaymentGetIntent, + req, + header_payload.clone(), + ) + }, + &auth::HeaderAuth(auth::ApiKeyAuth), + api_locking::LockAction::NotApplicable, + )) + .await +} + #[cfg(feature = "v1")] #[instrument(skip(state, req), fields(flow = ?Flow::PaymentsStart, payment_id))] pub async fn payments_start( @@ -286,8 +333,7 @@ pub async fn payments_retrieve( auth::auth_type( &*auth_type, &auth::JWTAuth { - permission: Permission::PaymentRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfilePaymentRead, }, req.headers(), ), @@ -996,8 +1042,7 @@ pub async fn payments_list( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::PaymentRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantPaymentRead, }, req.headers(), ), @@ -1032,8 +1077,7 @@ pub async fn profile_payments_list( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::PaymentRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfilePaymentRead, }, req.headers(), ), @@ -1066,8 +1110,7 @@ pub async fn payments_list_by_filter( ) }, &auth::JWTAuth { - permission: Permission::PaymentRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantPaymentRead, }, api_locking::LockAction::NotApplicable, )) @@ -1098,8 +1141,7 @@ pub async fn profile_payments_list_by_filter( ) }, &auth::JWTAuth { - permission: Permission::PaymentRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfilePaymentRead, }, api_locking::LockAction::NotApplicable, )) @@ -1124,8 +1166,7 @@ pub async fn get_filters_for_payments( payments::get_filters_for_payments(state, auth.merchant_account, auth.key_store, req) }, &auth::JWTAuth { - permission: Permission::PaymentRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantPaymentRead, }, api_locking::LockAction::NotApplicable, )) @@ -1148,8 +1189,7 @@ pub async fn get_payment_filters( payments::get_payment_filters(state, auth.merchant_account, None) }, &auth::JWTAuth { - permission: Permission::PaymentRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantPaymentRead, }, api_locking::LockAction::NotApplicable, )) @@ -1176,8 +1216,7 @@ pub async fn get_payment_filters_profile( ) }, &auth::JWTAuth { - permission: Permission::PaymentRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfilePaymentRead, }, api_locking::LockAction::NotApplicable, )) @@ -1202,8 +1241,7 @@ pub async fn get_payments_aggregates( payments::get_aggregates_for_payments(state, auth.merchant_account, None, req) }, &auth::JWTAuth { - permission: Permission::PaymentRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantPaymentRead, }, api_locking::LockAction::NotApplicable, )) @@ -1263,8 +1301,7 @@ pub async fn payments_approve( _ => auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::PaymentWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfilePaymentWrite, }, http_req.headers(), ), @@ -1328,8 +1365,7 @@ pub async fn payments_reject( _ => auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::PaymentWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfilePaymentWrite, }, http_req.headers(), ), @@ -1971,10 +2007,131 @@ pub async fn get_payments_aggregates_profile( ) }, &auth::JWTAuth { - permission: Permission::PaymentRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfilePaymentRead, }, api_locking::LockAction::NotApplicable, )) .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 7ff3f1d11ad9..5b0ef815b289 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/payouts.rs b/crates/router/src/routes/payouts.rs index ad860195a2a6..62d16c4c4d56 100644 --- a/crates/router/src/routes/payouts.rs +++ b/crates/router/src/routes/payouts.rs @@ -3,7 +3,6 @@ use actix_web::{ http::header::HeaderMap, web, HttpRequest, HttpResponse, Responder, }; -use common_enums::EntityType; use common_utils::consts; use router_env::{instrument, tracing, Flow}; @@ -84,8 +83,7 @@ pub async fn payouts_retrieve( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::PayoutRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfilePayoutRead, }, req.headers(), ), @@ -237,8 +235,7 @@ pub async fn payouts_list( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::PayoutRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantPayoutRead, }, req.headers(), ), @@ -277,8 +274,7 @@ pub async fn payouts_list_profile( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::PayoutRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfilePayoutRead, }, req.headers(), ), @@ -317,8 +313,7 @@ pub async fn payouts_list_by_filter( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::PayoutRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantPayoutRead, }, req.headers(), ), @@ -357,8 +352,7 @@ pub async fn payouts_list_by_filter_profile( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::PayoutRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfilePayoutRead, }, req.headers(), ), @@ -390,8 +384,7 @@ pub async fn payouts_list_available_filters_for_merchant( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::PayoutRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantPayoutRead, }, req.headers(), ), @@ -429,8 +422,7 @@ pub async fn payouts_list_available_filters_for_profile( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::PayoutRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfilePayoutRead, }, req.headers(), ), diff --git a/crates/router/src/routes/pm_auth.rs b/crates/router/src/routes/pm_auth.rs index cc0ab02b556e..31a2a0ba32eb 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 bbb2a9a63a39..aefda5892193 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/routes/profiles.rs b/crates/router/src/routes/profiles.rs index f2dc322af17c..cbb7957987fc 100644 --- a/crates/router/src/routes/profiles.rs +++ b/crates/router/src/routes/profiles.rs @@ -1,5 +1,4 @@ use actix_web::{web, HttpRequest, HttpResponse}; -use common_enums::EntityType; use router_env::{instrument, tracing, Flow}; use super::app::AppState; @@ -34,7 +33,6 @@ pub async fn profile_create( &auth::JWTAuthMerchantFromRoute { merchant_id, required_permission: permissions::Permission::MerchantAccountWrite, - minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -65,7 +63,6 @@ pub async fn profile_create( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromHeader { required_permission: permissions::Permission::MerchantAccountWrite, - minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -97,8 +94,7 @@ pub async fn profile_retrieve( &auth::AdminApiAuthWithMerchantIdFromRoute(merchant_id.clone()), &auth::JWTAuthMerchantFromRoute { merchant_id: merchant_id.clone(), - required_permission: permissions::Permission::MerchantAccountRead, - minimum_entity_level: EntityType::Profile, + required_permission: permissions::Permission::ProfileAccountRead, }, req.headers(), ), @@ -127,7 +123,6 @@ pub async fn profile_retrieve( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromHeader { required_permission: permissions::Permission::MerchantAccountRead, - minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -161,8 +156,7 @@ pub async fn profile_update( &auth::JWTAuthMerchantAndProfileFromRoute { merchant_id: merchant_id.clone(), profile_id: profile_id.clone(), - required_permission: permissions::Permission::MerchantAccountWrite, - minimum_entity_level: EntityType::Profile, + required_permission: permissions::Permission::ProfileAccountWrite, }, req.headers(), ), @@ -192,7 +186,6 @@ pub async fn profile_update( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromHeader { required_permission: permissions::Permission::MerchantAccountWrite, - minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -244,7 +237,6 @@ pub async fn profiles_list( &auth::JWTAuthMerchantFromRoute { merchant_id, required_permission: permissions::Permission::MerchantAccountRead, - minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -278,8 +270,7 @@ pub async fn profiles_list_at_profile_level( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromRoute { merchant_id, - required_permission: permissions::Permission::MerchantAccountRead, - minimum_entity_level: EntityType::Profile, + required_permission: permissions::Permission::ProfileAccountRead, }, req.headers(), ), @@ -312,8 +303,7 @@ pub async fn toggle_connector_agnostic_mit( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: permissions::Permission::RoutingWrite, - minimum_entity_level: EntityType::Merchant, + permission: permissions::Permission::MerchantRoutingWrite, }, req.headers(), ), @@ -372,8 +362,7 @@ pub async fn payment_connector_list_profile( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromRoute { merchant_id, - required_permission: permissions::Permission::MerchantConnectorAccountRead, - minimum_entity_level: EntityType::Profile, + required_permission: permissions::Permission::ProfileConnectorRead, }, req.headers(), ), diff --git a/crates/router/src/routes/recon.rs b/crates/router/src/routes/recon.rs index 1ec571ff7c90..cdc2ae758e92 100644 --- a/crates/router/src/routes/recon.rs +++ b/crates/router/src/routes/recon.rs @@ -1,5 +1,5 @@ use actix_web::{web, HttpRequest, HttpResponse}; -use api_models::{enums::EntityType, recon as recon_api}; +use api_models::recon as recon_api; use router_env::Flow; use super::AppState; @@ -38,8 +38,7 @@ pub async fn request_for_recon(state: web::Data, http_req: HttpRequest (), |state, user, _, _| recon::send_recon_request(state, user), &authentication::JWTAuth { - permission: Permission::ReconAdmin, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantReconWrite, }, api_locking::LockAction::NotApplicable, )) @@ -55,8 +54,7 @@ pub async fn get_recon_token(state: web::Data, req: HttpRequest) -> Ht (), |state, user, _, _| recon::generate_recon_token(state, user), &authentication::JWTAuth { - permission: Permission::ReconAdmin, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantReconWrite, }, api_locking::LockAction::NotApplicable, )) diff --git a/crates/router/src/routes/refunds.rs b/crates/router/src/routes/refunds.rs index c76ee600efe2..cbcfbcdcbf10 100644 --- a/crates/router/src/routes/refunds.rs +++ b/crates/router/src/routes/refunds.rs @@ -1,5 +1,4 @@ use actix_web::{web, HttpRequest, HttpResponse}; -use common_enums::EntityType; use router_env::{instrument, tracing, Flow}; use super::app::AppState; @@ -49,8 +48,7 @@ pub async fn refunds_create( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RefundWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileRefundWrite, }, req.headers(), ), @@ -113,8 +111,7 @@ pub async fn refunds_retrieve( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RefundRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileRefundRead, }, req.headers(), ), @@ -245,8 +242,7 @@ pub async fn refunds_list( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RefundRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantRefundRead, }, req.headers(), ), @@ -293,8 +289,7 @@ pub async fn refunds_list_profile( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RefundRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileRefundRead, }, req.headers(), ), @@ -336,8 +331,7 @@ pub async fn refunds_filter_list( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RefundRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantRefundRead, }, req.headers(), ), @@ -374,8 +368,7 @@ pub async fn get_refunds_filters(state: web::Data, req: HttpRequest) - auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RefundRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantRefundRead, }, req.headers(), ), @@ -419,8 +412,7 @@ pub async fn get_refunds_filters_profile( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RefundRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileRefundRead, }, req.headers(), ), @@ -449,8 +441,7 @@ pub async fn get_refunds_aggregates( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RefundRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantRefundRead, }, req.headers(), ), @@ -507,8 +498,7 @@ pub async fn get_refunds_aggregate_profile( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RefundRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileRefundRead, }, req.headers(), ), diff --git a/crates/router/src/routes/routing.rs b/crates/router/src/routes/routing.rs index 4c8d89fa87d5..f3a589524a16 100644 --- a/crates/router/src/routes/routing.rs +++ b/crates/router/src/routes/routing.rs @@ -5,7 +5,6 @@ use actix_web::{web, HttpRequest, Responder}; use api_models::{enums, routing as routing_types, routing::RoutingRetrieveQuery}; -use common_enums::EntityType; use router_env::{ tracing::{self, instrument}, Flow, @@ -44,15 +43,13 @@ pub async fn routing_create_config( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RoutingWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileRoutingWrite, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuth { - permission: Permission::RoutingWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileRoutingWrite, }, api_locking::LockAction::NotApplicable, )) @@ -87,15 +84,13 @@ pub async fn routing_link_config( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RoutingWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileRoutingWrite, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuth { - permission: Permission::RoutingWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileRoutingWrite, }, api_locking::LockAction::NotApplicable, )) @@ -137,16 +132,14 @@ pub async fn routing_link_config( &auth::ApiKeyAuth, &auth::JWTAuthProfileFromRoute { profile_id: wrapper.profile_id, - required_permission: Permission::RoutingWrite, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantRoutingWrite, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuthProfileFromRoute { profile_id: wrapper.profile_id, - required_permission: Permission::RoutingWrite, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantRoutingWrite, }, api_locking::LockAction::NotApplicable, )) @@ -180,15 +173,13 @@ pub async fn routing_retrieve_config( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RoutingRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileRoutingRead, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuth { - permission: Permission::RoutingRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileRoutingRead, }, api_locking::LockAction::NotApplicable, )) @@ -222,15 +213,13 @@ pub async fn list_routing_configs( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RoutingRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantRoutingRead, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuth { - permission: Permission::RoutingRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantRoutingRead, }, api_locking::LockAction::NotApplicable, )) @@ -264,15 +253,13 @@ pub async fn list_routing_configs_for_profile( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RoutingRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileRoutingRead, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuth { - permission: Permission::RoutingRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileRoutingRead, }, api_locking::LockAction::NotApplicable, )) @@ -308,16 +295,14 @@ pub async fn routing_unlink_config( &auth::ApiKeyAuth, &auth::JWTAuthProfileFromRoute { profile_id: path, - required_permission: Permission::RoutingWrite, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantRoutingWrite, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuthProfileFromRoute { profile_id: path, - required_permission: Permission::RoutingWrite, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantRoutingWrite, }, api_locking::LockAction::NotApplicable, )) @@ -352,15 +337,13 @@ pub async fn routing_unlink_config( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RoutingWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileRoutingWrite, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuth { - permission: Permission::RoutingWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileRoutingWrite, }, api_locking::LockAction::NotApplicable, )) @@ -397,15 +380,13 @@ pub async fn routing_update_default_config( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RoutingWrite, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantRoutingWrite, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuth { - permission: Permission::RoutingWrite, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantRoutingWrite, }, api_locking::LockAction::NotApplicable, )) @@ -437,15 +418,13 @@ pub async fn routing_update_default_config( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RoutingWrite, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantRoutingWrite, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuth { - permission: Permission::RoutingWrite, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantRoutingWrite, }, api_locking::LockAction::NotApplicable, )) @@ -478,16 +457,14 @@ pub async fn routing_retrieve_default_config( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuthProfileFromRoute { profile_id: path, - required_permission: Permission::RoutingRead, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantRoutingRead, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuthProfileFromRoute { profile_id: path, - required_permission: Permission::RoutingRead, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantRoutingRead, }, api_locking::LockAction::NotApplicable, )) @@ -513,15 +490,13 @@ pub async fn routing_retrieve_default_config( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RoutingRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileRoutingRead, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuth { - permission: Permission::RoutingRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileRoutingRead, }, api_locking::LockAction::NotApplicable, )) @@ -553,15 +528,13 @@ pub async fn upsert_surcharge_decision_manager_config( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::SurchargeDecisionManagerWrite, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantSurchargeDecisionManagerWrite, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuth { - permission: Permission::SurchargeDecisionManagerWrite, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantSurchargeDecisionManagerWrite, }, api_locking::LockAction::NotApplicable, )) @@ -590,15 +563,13 @@ pub async fn delete_surcharge_decision_manager_config( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::SurchargeDecisionManagerWrite, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantSurchargeDecisionManagerWrite, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuth { - permission: Permission::SurchargeDecisionManagerWrite, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantSurchargeDecisionManagerWrite, }, api_locking::LockAction::NotApplicable, )) @@ -627,15 +598,13 @@ pub async fn retrieve_surcharge_decision_manager_config( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::SurchargeDecisionManagerRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantSurchargeDecisionManagerRead, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuth { - permission: Permission::SurchargeDecisionManagerRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantSurchargeDecisionManagerRead, }, api_locking::LockAction::NotApplicable, )) @@ -667,15 +636,13 @@ pub async fn upsert_decision_manager_config( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::SurchargeDecisionManagerRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantThreeDsDecisionManagerWrite, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuth { - permission: Permission::SurchargeDecisionManagerRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantThreeDsDecisionManagerWrite, }, api_locking::LockAction::NotApplicable, )) @@ -705,15 +672,13 @@ pub async fn delete_decision_manager_config( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::SurchargeDecisionManagerWrite, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantThreeDsDecisionManagerWrite, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuth { - permission: Permission::SurchargeDecisionManagerWrite, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantThreeDsDecisionManagerWrite, }, api_locking::LockAction::NotApplicable, )) @@ -739,15 +704,13 @@ pub async fn retrieve_decision_manager_config( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::SurchargeDecisionManagerRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantThreeDsDecisionManagerRead, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuth { - permission: Permission::SurchargeDecisionManagerRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantThreeDsDecisionManagerRead, }, api_locking::LockAction::NotApplicable, )) @@ -786,16 +749,14 @@ pub async fn routing_retrieve_linked_config( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuthProfileFromRoute { profile_id, - required_permission: Permission::RoutingRead, - minimum_entity_level: EntityType::Profile, + required_permission: Permission::ProfileRoutingRead, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuthProfileFromRoute { profile_id, - required_permission: Permission::RoutingRead, - minimum_entity_level: EntityType::Profile, + required_permission: Permission::ProfileRoutingRead, }, api_locking::LockAction::NotApplicable, )) @@ -820,15 +781,13 @@ pub async fn routing_retrieve_linked_config( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RoutingRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileRoutingRead, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuth { - permission: Permission::RoutingRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileRoutingRead, }, api_locking::LockAction::NotApplicable, )) @@ -871,16 +830,14 @@ pub async fn routing_retrieve_linked_config( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuthProfileFromRoute { profile_id: wrapper.profile_id, - required_permission: Permission::RoutingRead, - minimum_entity_level: EntityType::Profile, + required_permission: Permission::ProfileRoutingRead, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuthProfileFromRoute { profile_id: wrapper.profile_id, - required_permission: Permission::RoutingRead, - minimum_entity_level: EntityType::Profile, + required_permission: Permission::ProfileRoutingRead, }, api_locking::LockAction::NotApplicable, )) @@ -911,8 +868,7 @@ pub async fn routing_retrieve_default_config_for_profiles( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RoutingRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantRoutingRead, }, req.headers(), ), @@ -920,8 +876,7 @@ pub async fn routing_retrieve_default_config_for_profiles( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RoutingRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantRoutingRead, }, req.headers(), ), @@ -963,16 +918,14 @@ pub async fn routing_update_default_config_for_profile( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuthProfileFromRoute { profile_id: routing_payload_wrapper.profile_id, - required_permission: Permission::RoutingWrite, - minimum_entity_level: EntityType::Profile, + required_permission: Permission::ProfileRoutingWrite, }, req.headers(), ), #[cfg(feature = "release")] &auth::JWTAuthProfileFromRoute { profile_id: routing_payload_wrapper.profile_id, - required_permission: Permission::RoutingWrite, - minimum_entity_level: EntityType::Profile, + required_permission: Permission::ProfileRoutingWrite, }, api_locking::LockAction::NotApplicable, )) @@ -989,7 +942,7 @@ pub async fn toggle_success_based_routing( ) -> impl Responder { let flow = Flow::ToggleDynamicRouting; let wrapper = routing_types::ToggleSuccessBasedRoutingWrapper { - status: query.into_inner().status, + feature_to_enable: query.into_inner().enable, profile_id: path.into_inner().profile_id, }; Box::pin(oss_api::server_wrap( @@ -1005,7 +958,7 @@ pub async fn toggle_success_based_routing( state, auth.merchant_account, auth.key_store, - wrapper.status, + wrapper.feature_to_enable, wrapper.profile_id, ) }, @@ -1013,8 +966,7 @@ pub async fn toggle_success_based_routing( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuthProfileFromRoute { profile_id: wrapper.profile_id, - required_permission: Permission::RoutingWrite, - minimum_entity_level: EntityType::Profile, + required_permission: Permission::ProfileRoutingWrite, }, req.headers(), ), diff --git a/crates/router/src/routes/user.rs b/crates/router/src/routes/user.rs index e07a2fa10ef4..f52d0dca7a83 100644 --- a/crates/router/src/routes/user.rs +++ b/crates/router/src/routes/user.rs @@ -5,7 +5,7 @@ use api_models::{ errors::types::ApiErrorResponse, user::{self as user_api}, }; -use common_enums::{EntityType, TokenPurpose}; +use common_enums::TokenPurpose; use common_utils::errors::ReportSwitchExt; use router_env::Flow; @@ -176,8 +176,7 @@ pub async fn set_dashboard_metadata( payload, user_core::dashboard_metadata::set_metadata, &auth::JWTAuth { - permission: Permission::MerchantAccountWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileAccountWrite, }, api_locking::LockAction::NotApplicable, )) @@ -243,8 +242,7 @@ pub async fn user_merchant_account_create( user_core::create_merchant_account(state, auth, json_payload) }, &auth::JWTAuth { - permission: Permission::MerchantAccountCreate, - minimum_entity_level: EntityType::Merchant, + permission: Permission::OrganizationAccountWrite, }, api_locking::LockAction::NotApplicable, )) @@ -267,8 +265,7 @@ pub async fn generate_sample_data( payload.into_inner(), sample_data::generate_sample_data_for_user, &auth::JWTAuth { - permission: Permission::PaymentWrite, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantPaymentWrite, }, api_locking::LockAction::NotApplicable, )) @@ -292,7 +289,6 @@ pub async fn delete_sample_data( sample_data::delete_sample_data_for_user, &auth::JWTAuth { permission: Permission::MerchantAccountWrite, - minimum_entity_level: EntityType::Merchant, }, api_locking::LockAction::NotApplicable, )) @@ -312,8 +308,7 @@ pub async fn list_user_roles_details( payload.into_inner(), user_core::list_user_roles_details, &auth::JWTAuth { - permission: Permission::UsersRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileUserRead, }, api_locking::LockAction::NotApplicable, )) @@ -395,8 +390,7 @@ pub async fn invite_multiple_user( user_core::invite_multiple_user(state, user, payload, req_state, auth_id.clone()) }, &auth::JWTAuth { - permission: Permission::UsersWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileUserWrite, }, api_locking::LockAction::NotApplicable, )) @@ -421,8 +415,7 @@ pub async fn resend_invite( user_core::resend_invite(state, user, req_payload, auth_id.clone()) }, &auth::JWTAuth { - permission: Permission::UsersWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileUserWrite, }, api_locking::LockAction::NotApplicable, )) @@ -504,8 +497,7 @@ pub async fn verify_recon_token(state: web::Data, http_req: HttpReques (), |state, user, _req, _| user_core::verify_token(state, user), &auth::JWTAuth { - permission: Permission::ReconAdmin, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantReconWrite, }, api_locking::LockAction::NotApplicable, )) diff --git a/crates/router/src/routes/user_role.rs b/crates/router/src/routes/user_role.rs index 777cbe1fd950..9910cef3950a 100644 --- a/crates/router/src/routes/user_role.rs +++ b/crates/router/src/routes/user_role.rs @@ -1,6 +1,6 @@ use actix_web::{web, HttpRequest, HttpResponse}; use api_models::user_role::{self as user_role_api, role as role_api}; -use common_enums::{EntityType, TokenPurpose}; +use common_enums::TokenPurpose; use router_env::Flow; use super::AppState; @@ -31,8 +31,7 @@ pub async fn get_authorization_info( user_role_core::get_authorization_info_with_groups(state).await }, &auth::JWTAuth { - permission: Permission::UsersRead, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantUserRead, }, api_locking::LockAction::NotApplicable, )) @@ -56,6 +55,26 @@ pub async fn get_role_from_token(state: web::Data, req: HttpRequest) - .await } +pub async fn get_groups_and_resources_for_role_from_token( + state: web::Data, + req: HttpRequest, +) -> HttpResponse { + let flow = Flow::GetRoleFromTokenV2; + + Box::pin(api::server_wrap( + flow, + state.clone(), + &req, + (), + |state, user, _, _| async move { + role_core::get_groups_and_resources_for_role_from_token(state, user).await + }, + &auth::DashboardNoPermissionAuth, + api_locking::LockAction::NotApplicable, + )) + .await +} + pub async fn create_role( state: web::Data, req: HttpRequest, @@ -69,8 +88,7 @@ pub async fn create_role( json_payload.into_inner(), role_core::create_role, &auth::JWTAuth { - permission: Permission::UsersWrite, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantUserWrite, }, api_locking::LockAction::NotApplicable, )) @@ -95,8 +113,32 @@ pub async fn get_role( role_core::get_role_with_groups(state, user, payload).await }, &auth::JWTAuth { - permission: Permission::UsersRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileUserRead, + }, + api_locking::LockAction::NotApplicable, + )) + .await +} + +pub async fn get_parent_info_for_role( + state: web::Data, + req: HttpRequest, + path: web::Path, +) -> HttpResponse { + let flow = Flow::GetRoleV2; + let request_payload = user_role_api::role::GetRoleRequest { + role_id: path.into_inner(), + }; + Box::pin(api::server_wrap( + flow, + state.clone(), + &req, + request_payload, + |state, user, payload, _| async move { + role_core::get_parent_info_for_role(state, user, payload).await + }, + &auth::JWTAuth { + permission: Permission::ProfileUserRead, }, api_locking::LockAction::NotApplicable, )) @@ -119,8 +161,7 @@ pub async fn update_role( json_payload.into_inner(), |state, user, req, _| role_core::update_role(state, user, req, &role_id), &auth::JWTAuth { - permission: Permission::UsersWrite, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantUserWrite, }, api_locking::LockAction::NotApplicable, )) @@ -141,8 +182,7 @@ pub async fn update_user_role( payload, user_role_core::update_user_role, &auth::JWTAuth { - permission: Permission::UsersWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileUserWrite, }, api_locking::LockAction::NotApplicable, )) @@ -202,8 +242,7 @@ pub async fn delete_user_role( payload.into_inner(), user_role_core::delete_user_role, &auth::JWTAuth { - permission: Permission::UsersWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileUserWrite, }, api_locking::LockAction::NotApplicable, )) @@ -225,8 +264,29 @@ pub async fn get_role_information( user_role_core::get_authorization_info_with_group_tag().await }, &auth::JWTAuth { - permission: Permission::UsersRead, - minimum_entity_level: EntityType::Profile + permission: Permission::ProfileUserRead, + }, + api_locking::LockAction::NotApplicable, + )) + .await +} + +pub async fn get_parent_group_info( + state: web::Data, + http_req: HttpRequest, +) -> HttpResponse { + let flow = Flow::GetParentGroupInfo; + + Box::pin(api::server_wrap( + flow, + state.clone(), + &http_req, + (), + |state, user_from_token, _, _| async move { + user_role_core::get_parent_group_info(state, user_from_token).await + }, + &auth::JWTAuth { + permission: Permission::ProfileUserRead, }, api_locking::LockAction::NotApplicable, )) @@ -270,8 +330,7 @@ pub async fn list_roles_with_info( role_core::list_roles_with_info(state, user_from_token, request) }, &auth::JWTAuth { - permission: Permission::UsersRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileUserRead, }, api_locking::LockAction::NotApplicable, )) @@ -299,8 +358,7 @@ pub async fn list_invitable_roles_at_entity_level( ) }, &auth::JWTAuth { - permission: Permission::UsersRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileUserRead, }, api_locking::LockAction::NotApplicable, )) @@ -328,8 +386,7 @@ pub async fn list_updatable_roles_at_entity_level( ) }, &auth::JWTAuth { - permission: Permission::UsersRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileUserRead, }, api_locking::LockAction::NotApplicable, )) diff --git a/crates/router/src/routes/verification.rs b/crates/router/src/routes/verification.rs index 17c946c4810b..56ad42947c24 100644 --- a/crates/router/src/routes/verification.rs +++ b/crates/router/src/routes/verification.rs @@ -1,6 +1,5 @@ use actix_web::{web, HttpRequest, Responder}; use api_models::verifications; -use common_enums::EntityType; use router_env::{instrument, tracing, Flow}; use super::app::AppState; @@ -34,8 +33,7 @@ pub async fn apple_pay_merchant_registration( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::MerchantAccountWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileAccountWrite, }, req.headers(), ), @@ -70,7 +68,6 @@ pub async fn retrieve_apple_pay_verified_domains( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { permission: Permission::MerchantAccountRead, - minimum_entity_level: EntityType::Merchant, }, req.headers(), ), diff --git a/crates/router/src/routes/verify_connector.rs b/crates/router/src/routes/verify_connector.rs index 29f8c154bc0d..b8e089f0660e 100644 --- a/crates/router/src/routes/verify_connector.rs +++ b/crates/router/src/routes/verify_connector.rs @@ -1,6 +1,5 @@ use actix_web::{web, HttpRequest, HttpResponse}; use api_models::verify_connector::VerifyConnectorRequest; -use common_enums::EntityType; use router_env::{instrument, tracing, Flow}; use super::AppState; @@ -25,8 +24,7 @@ pub async fn payment_connector_verify( verify_connector::verify_connector_credentials(state, req, auth.profile_id) }, &auth::JWTAuth { - permission: Permission::MerchantConnectorAccountWrite, - minimum_entity_level: EntityType::Merchant, + permission: Permission::MerchantConnectorWrite, }, api_locking::LockAction::NotApplicable, )) diff --git a/crates/router/src/routes/webhook_events.rs b/crates/router/src/routes/webhook_events.rs index 8b94fb61f56b..5039f72db31e 100644 --- a/crates/router/src/routes/webhook_events.rs +++ b/crates/router/src/routes/webhook_events.rs @@ -1,5 +1,4 @@ use actix_web::{web, HttpRequest, Responder}; -use common_enums::EntityType; use router_env::{instrument, tracing, Flow}; use crate::{ @@ -44,8 +43,7 @@ pub async fn list_initial_webhook_delivery_attempts( &auth::AdminApiAuth, &auth::JWTAuthMerchantFromRoute { merchant_id, - required_permission: Permission::WebhookEventRead, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantWebhookEventRead, }, req.headers(), ), @@ -84,8 +82,7 @@ pub async fn list_webhook_delivery_attempts( &auth::AdminApiAuth, &auth::JWTAuthMerchantFromRoute { merchant_id, - required_permission: Permission::WebhookEventRead, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantWebhookEventRead, }, req.headers(), ), @@ -124,8 +121,7 @@ pub async fn retry_webhook_delivery_attempt( &auth::AdminApiAuth, &auth::JWTAuthMerchantFromRoute { merchant_id, - required_permission: Permission::WebhookEventWrite, - minimum_entity_level: EntityType::Merchant, + required_permission: Permission::MerchantWebhookEventWrite, }, req.headers(), ), diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs index 579a4ac4ffd0..2cf8b721a057 100644 --- a/crates/router/src/services/api.rs +++ b/crates/router/src/services/api.rs @@ -721,31 +721,27 @@ where .change_context(errors::ApiErrorResponse::InternalServerError.switch())?; let mut event_type = payload.get_api_event_type(); - let tenants: HashSet<_> = state - .conf - .multitenancy - .get_tenant_names() - .into_iter() - .collect(); let tenant_id = if !state.conf.multitenancy.enabled { DEFAULT_TENANT.to_string() } else { - incoming_request_header + let request_tenant_id = incoming_request_header .get(TENANT_HEADER) .and_then(|value| value.to_str().ok()) - .ok_or_else(|| errors::ApiErrorResponse::MissingTenantId.switch()) - .map(|req_tenant_id| { - if !tenants.contains(req_tenant_id) { - Err(errors::ApiErrorResponse::InvalidTenant { - tenant_id: req_tenant_id.to_string(), - } - .switch()) - } else { - Ok(req_tenant_id.to_string()) + .ok_or_else(|| errors::ApiErrorResponse::MissingTenantId.switch())?; + + state + .conf + .multitenancy + .get_tenant(request_tenant_id) + .map(|tenant| tenant.tenant_id.clone()) + .ok_or( + errors::ApiErrorResponse::InvalidTenant { + tenant_id: request_tenant_id.to_string(), } - })?? + .switch(), + )? }; - // let tenant_id = "public".to_string(); + let mut session_state = Arc::new(app_state.clone()).get_session_state(tenant_id.as_str(), || { errors::ApiErrorResponse::InvalidTenant { @@ -1225,6 +1221,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() @@ -1262,10 +1259,8 @@ impl Authenticate for api_models::payments::PaymentsIncrementalAuthorizationRequ impl Authenticate for api_models::payments::PaymentsStartRequest {} // impl Authenticate for api_models::payments::PaymentsApproveRequest {} impl Authenticate for api_models::payments::PaymentsRejectRequest {} -#[cfg(feature = "v2")] -impl Authenticate for api_models::payments::PaymentsCreateIntentRequest {} // #[cfg(feature = "v2")] -// impl Authenticate for api_models::payments::PaymentsCreateIntentResponse {} +// impl Authenticate for api_models::payments::PaymentsIntentResponse {} pub fn build_redirection_form( form: &RedirectForm, @@ -1333,9 +1328,9 @@ pub fn build_redirection_form( } (PreEscaped(format!(r#" "#)) + (PreEscaped(r#" + + "#)) + h3 style="text-align: center;" { "Please wait while we process your payment..." } + + script { + (PreEscaped(format!( + r#" + function submitCollectionReference(collectionReference) {{ + var redirectPathname = window.location.pathname.replace(/payments\/redirect\/(\w+)\/(\w+)\/\w+/, "payments/$1/$2/redirect/complete/worldpay"); + var redirectUrl = window.location.origin + redirectPathname; + try {{ + if (typeof collectionReference === "string" && collectionReference.length > 0) {{ + var form = document.createElement("form"); + form.action = redirectPathname; + form.method = "GET"; + var input = document.createElement("input"); + input.type = "hidden"; + input.name = "collectionReference"; + input.value = collectionReference; + form.appendChild(input); + document.body.appendChild(form); + form.submit();; + }} else {{ + window.location.replace(redirectUrl); + }} + }} catch (error) {{ + window.location.replace(redirectUrl); + }} + }} + var allowedHost = "{}"; + var collectionField = "{}"; + window.addEventListener("message", function(event) {{ + if (event.origin === allowedHost) {{ + try {{ + var data = JSON.parse(event.data); + if (collectionField.length > 0) {{ + var collectionReference = data[collectionField]; + return submitCollectionReference(collectionReference); + }} else {{ + console.error("Collection field not found in event data (" + collectionField + ")"); + }} + }} catch (error) {{ + console.error("Error parsing event data: ", error); + }} + }} else {{ + console.error("Invalid origin: " + event.origin, "Expected origin: " + allowedHost); + }} + + submitCollectionReference(""); + }}); + + // Redirect within 8 seconds if no collection reference is received + window.setTimeout(submitCollectionReference, 8000); + "#, + endpoint.host_str().map_or(endpoint.as_ref().split('/').take(3).collect::>().join("/"), |host| format!("{}://{}", endpoint.scheme(), host)), + collection_id.clone().unwrap_or("".to_string()))) + ) + } + + iframe + style="display: none;" + srcdoc=( + maud::html! { + (maud::DOCTYPE) + html { + body { + form action=(PreEscaped(endpoint.to_string())) method=(method.to_string()) #payment_form { + @for (field, value) in form_fields { + input type="hidden" name=(field) value=(value); + } + } + (PreEscaped(format!(r#" + + "#))) + } + } + }.into_string() + ) + {} + } + } + }, } } diff --git a/crates/router/src/services/authentication.rs b/crates/router/src/services/authentication.rs index a731b7e6dbb7..a3cc54de34f9 100644 --- a/crates/router/src/services/authentication.rs +++ b/crates/router/src/services/authentication.rs @@ -10,7 +10,7 @@ use api_models::payment_methods::PaymentMethodIntentConfirm; use api_models::payouts; use api_models::{payment_methods::PaymentMethodListRequest, payments}; use async_trait::async_trait; -use common_enums::{EntityType, TokenPurpose}; +use common_enums::TokenPurpose; use common_utils::{date_time, id_type}; use error_stack::{report, ResultExt}; use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation}; @@ -58,6 +58,7 @@ pub struct AuthenticationData { pub profile_id: Option, } +#[cfg(feature = "v2")] #[derive(Clone, Debug)] pub struct AuthenticationDataV2 { pub merchant_account: domain::MerchantAccount, @@ -89,7 +90,7 @@ pub struct AuthenticationDataWithUser { pub enum AuthenticationType { ApiKey { merchant_id: id_type::MerchantId, - key_id: String, + key_id: id_type::ApiKeyId, }, AdminApiKey, AdminApiAuthWithMerchantId { @@ -282,6 +283,7 @@ impl AuthInfo for AuthenticationData { } } +#[cfg(feature = "v2")] impl AuthInfo for AuthenticationDataV2 { fn get_merchant_id(&self) -> Option<&id_type::MerchantId> { Some(self.merchant_account.get_id()) @@ -365,6 +367,7 @@ where } } +#[cfg(feature = "v2")] #[async_trait] impl AuthenticateAndFetch for ApiKeyAuth where @@ -383,9 +386,8 @@ where .attach_printable("API key is empty"); } - let profile_id = - get_id_type_by_key_from_headers(headers::X_PROFILE_ID.to_string(), request_headers)? - .get_required_value(headers::X_PROFILE_ID)?; + let profile_id = HeaderMapStruct::new(request_headers) + .get_id_type_from_header::(headers::X_PROFILE_ID)?; let api_key = api_keys::PlaintextApiKey::from(api_key); let hash_key = { @@ -638,7 +640,7 @@ where } } -#[cfg(feature = "partial-auth")] +#[cfg(all(feature = "partial-auth", feature = "v2"))] #[async_trait] impl AuthenticateAndFetch for HeaderAuth where @@ -658,9 +660,10 @@ where .0 .authenticate_and_fetch(request_headers, state) .await?; - let profile_id = - get_id_type_by_key_from_headers(headers::X_PROFILE_ID.to_string(), request_headers)? - .get_required_value(headers::X_PROFILE_ID)?; + + let profile_id = HeaderMapStruct::new(request_headers) + .get_id_type_from_header::(headers::X_PROFILE_ID)?; + let key_manager_state = &(&state.session_state()).into(); let profile = state .store() @@ -928,7 +931,7 @@ where } /// A helper struct to extract headers from the request -struct HeaderMapStruct<'a> { +pub(crate) struct HeaderMapStruct<'a> { headers: &'a HeaderMap, } @@ -939,17 +942,17 @@ impl<'a> HeaderMapStruct<'a> { fn get_mandatory_header_value_by_key( &self, - key: String, + key: &str, ) -> Result<&str, error_stack::Report> { self.headers - .get(&key) + .get(key) .ok_or(errors::ApiErrorResponse::InvalidRequestData { message: format!("Missing header key: `{}`", key), }) .attach_printable(format!("Failed to find header key: {}", key))? .to_str() .change_context(errors::ApiErrorResponse::InvalidDataValue { - field_name: "`X-Merchant-Id` in headers", + field_name: "`{key}` in headers", }) .attach_printable(format!( "Failed to convert header value to string for header key: {}", @@ -957,13 +960,35 @@ impl<'a> HeaderMapStruct<'a> { )) } - pub fn get_merchant_id_from_header(&self) -> RouterResult { - self.get_mandatory_header_value_by_key(headers::X_MERCHANT_ID.into()) + /// Get the id type from the header + /// This can be used to extract lineage ids from the headers + pub fn get_id_type_from_header< + T: TryFrom< + std::borrow::Cow<'static, str>, + Error = error_stack::Report, + >, + >( + &self, + key: &str, + ) -> RouterResult { + self.get_mandatory_header_value_by_key(key) .map(|val| val.to_owned()) - .and_then(|merchant_id| { - id_type::MerchantId::wrap(merchant_id).change_context( + .and_then(|header_value| { + T::try_from(std::borrow::Cow::Owned(header_value)).change_context( errors::ApiErrorResponse::InvalidRequestData { - message: format!("`{}` header is invalid", headers::X_MERCHANT_ID), + message: format!("`{}` header is invalid", key), + }, + ) + }) + } + #[cfg(feature = "v2")] + pub fn get_organization_id_from_header(&self) -> RouterResult { + self.get_mandatory_header_value_by_key(headers::X_ORGANIZATION_ID) + .map(|val| val.to_owned()) + .and_then(|organization_id| { + id_type::OrganizationId::wrap(organization_id).change_context( + errors::ApiErrorResponse::InvalidRequestData { + message: format!("`{}` header is invalid", headers::X_ORGANIZATION_ID), }, ) }) @@ -988,7 +1013,8 @@ where .authenticate_and_fetch(request_headers, state) .await?; - let merchant_id = HeaderMapStruct::new(request_headers).get_merchant_id_from_header()?; + let merchant_id = HeaderMapStruct::new(request_headers) + .get_id_type_from_header::(headers::X_MERCHANT_ID)?; let key_manager_state = &(&state.session_state()).into(); let key_store = state @@ -1161,10 +1187,63 @@ where } } +#[cfg(feature = "v2")] +#[async_trait] +impl AuthenticateAndFetch for PublishableKeyAuth +where + A: SessionStateInfo + Sync, +{ + async fn authenticate_and_fetch( + &self, + request_headers: &HeaderMap, + state: &A, + ) -> RouterResult<(AuthenticationDataV2, AuthenticationType)> { + let publishable_key = + get_api_key(request_headers).change_context(errors::ApiErrorResponse::Unauthorized)?; + let key_manager_state = &(&state.session_state()).into(); + let authentication_data = state + .store() + .find_merchant_account_by_publishable_key(key_manager_state, publishable_key) + .await + .map_err(|e| { + if e.current_context().is_db_not_found() { + e.change_context(errors::ApiErrorResponse::Unauthorized) + } else { + e.change_context(errors::ApiErrorResponse::InternalServerError) + } + })?; + + let profile_id = HeaderMapStruct::new(request_headers) + .get_id_type_from_header::(headers::X_PROFILE_ID)?; + + let profile = state + .store() + .find_business_profile_by_profile_id( + key_manager_state, + &authentication_data.key_store, + &profile_id, + ) + .await + .to_not_found_response(errors::ApiErrorResponse::ProfileNotFound { + id: profile_id.get_string_repr().to_owned(), + })?; + + let merchant_id = authentication_data.merchant_account.get_id().clone(); + + Ok(( + AuthenticationDataV2 { + merchant_account: authentication_data.merchant_account, + key_store: authentication_data.key_store, + profile, + }, + AuthenticationType::PublishableKey { merchant_id }, + )) + } +} + #[derive(Debug)] pub(crate) struct JWTAuth { pub permission: Permission, - pub minimum_entity_level: EntityType, } #[async_trait] @@ -1184,7 +1263,6 @@ where let role_info = authorization::get_role_info(state, &payload).await?; authorization::check_permission(&self.permission, &role_info)?; - authorization::check_entity(self.minimum_entity_level, &role_info)?; Ok(( (), @@ -1214,7 +1292,6 @@ where let role_info = authorization::get_role_info(state, &payload).await?; authorization::check_permission(&self.permission, &role_info)?; - authorization::check_entity(self.minimum_entity_level, &role_info)?; Ok(( UserFromToken { @@ -1250,7 +1327,6 @@ where let role_info = authorization::get_role_info(state, &payload).await?; authorization::check_permission(&self.permission, &role_info)?; - authorization::check_entity(self.minimum_entity_level, &role_info)?; let key_manager_state = &(&state.session_state()).into(); let key_store = state @@ -1291,7 +1367,6 @@ where pub struct JWTAuthOrganizationFromRoute { pub organization_id: id_type::OrganizationId, pub required_permission: Permission, - pub minimum_entity_level: EntityType, } #[async_trait] @@ -1311,7 +1386,6 @@ where let role_info = authorization::get_role_info(state, &payload).await?; authorization::check_permission(&self.required_permission, &role_info)?; - authorization::check_entity(self.minimum_entity_level, &role_info)?; // Check if token has access to Organization that has been requested in the route if payload.org_id != self.organization_id { @@ -1330,12 +1404,10 @@ where pub struct JWTAuthMerchantFromRoute { pub merchant_id: id_type::MerchantId, pub required_permission: Permission, - pub minimum_entity_level: EntityType, } pub struct JWTAuthMerchantFromHeader { pub required_permission: Permission, - pub minimum_entity_level: EntityType, } #[async_trait] @@ -1355,10 +1427,9 @@ where let role_info = authorization::get_role_info(state, &payload).await?; authorization::check_permission(&self.required_permission, &role_info)?; - authorization::check_entity(self.minimum_entity_level, &role_info)?; - let merchant_id_from_header = - HeaderMapStruct::new(request_headers).get_merchant_id_from_header()?; + let merchant_id_from_header = HeaderMapStruct::new(request_headers) + .get_id_type_from_header::(headers::X_MERCHANT_ID)?; // Check if token has access to MerchantId that has been requested through headers if payload.merchant_id != merchant_id_from_header { @@ -1391,10 +1462,9 @@ where let role_info = authorization::get_role_info(state, &payload).await?; authorization::check_permission(&self.required_permission, &role_info)?; - authorization::check_entity(self.minimum_entity_level, &role_info)?; - let merchant_id_from_header = - HeaderMapStruct::new(request_headers).get_merchant_id_from_header()?; + let merchant_id_from_header = HeaderMapStruct::new(request_headers) + .get_id_type_from_header::(headers::X_MERCHANT_ID)?; // Check if token has access to MerchantId that has been requested through headers if payload.merchant_id != merchant_id_from_header { @@ -1458,7 +1528,6 @@ where let role_info = authorization::get_role_info(state, &payload).await?; authorization::check_permission(&self.required_permission, &role_info)?; - authorization::check_entity(self.minimum_entity_level, &role_info)?; // Check if token has access to MerchantId that has been requested through query param if payload.merchant_id != self.merchant_id { @@ -1495,7 +1564,6 @@ where let role_info = authorization::get_role_info(state, &payload).await?; authorization::check_permission(&self.required_permission, &role_info)?; - authorization::check_entity(self.minimum_entity_level, &role_info)?; let key_manager_state = &(&state.session_state()).into(); let key_store = state @@ -1538,7 +1606,6 @@ pub struct JWTAuthMerchantAndProfileFromRoute { pub merchant_id: id_type::MerchantId, pub profile_id: id_type::ProfileId, pub required_permission: Permission, - pub minimum_entity_level: EntityType, } #[async_trait] @@ -1570,7 +1637,6 @@ where let role_info = authorization::get_role_info(state, &payload).await?; authorization::check_permission(&self.required_permission, &role_info)?; - authorization::check_entity(self.minimum_entity_level, &role_info)?; let key_manager_state = &(&state.session_state()).into(); let key_store = state @@ -1614,7 +1680,6 @@ where pub struct JWTAuthProfileFromRoute { pub profile_id: id_type::ProfileId, pub required_permission: Permission, - pub minimum_entity_level: EntityType, } #[async_trait] @@ -1634,7 +1699,6 @@ where let role_info = authorization::get_role_info(state, &payload).await?; authorization::check_permission(&self.required_permission, &role_info)?; - authorization::check_entity(self.minimum_entity_level, &role_info)?; let key_manager_state = &(&state.session_state()).into(); let key_store = state @@ -1730,7 +1794,6 @@ where let role_info = authorization::get_role_info(state, &payload).await?; authorization::check_permission(&self.permission, &role_info)?; - authorization::check_entity(self.minimum_entity_level, &role_info)?; let key_manager_state = &(&state.session_state()).into(); let key_store = state @@ -1770,6 +1833,7 @@ where } } +#[cfg(feature = "v2")] #[async_trait] impl AuthenticateAndFetch for JWTAuth where @@ -1785,13 +1849,11 @@ where return Err(errors::ApiErrorResponse::InvalidJwtToken.into()); } - let profile_id = - get_id_type_by_key_from_headers(headers::X_PROFILE_ID.to_string(), request_headers)? - .get_required_value(headers::X_PROFILE_ID)?; + let profile_id = HeaderMapStruct::new(request_headers) + .get_id_type_from_header::(headers::X_PROFILE_ID)?; let role_info = authorization::get_role_info(state, &payload).await?; authorization::check_permission(&self.permission, &role_info)?; - authorization::check_entity(self.minimum_entity_level, &role_info)?; let key_manager_state = &(&state.session_state()).into(); let key_store = state @@ -1855,7 +1917,6 @@ where let role_info = authorization::get_role_info(state, &payload).await?; authorization::check_permission(&self.permission, &role_info)?; - authorization::check_entity(self.minimum_entity_level, &role_info)?; let key_manager_state = &(&state.session_state()).into(); let key_store = state @@ -2006,6 +2067,7 @@ impl ClientSecretFetch for payouts::PayoutCreateRequest { } } +#[cfg(feature = "v1")] impl ClientSecretFetch for payments::PaymentsRequest { fn get_client_secret(&self) -> Option<&String> { self.client_secret.as_ref() @@ -2280,7 +2342,6 @@ where } let role_info = authorization::get_role_info(state, &payload).await?; authorization::check_permission(&self.permission, &role_info)?; - authorization::check_entity(self.minimum_entity_level, &role_info)?; let key_manager_state = &(&state.session_state()).into(); let key_store = state diff --git a/crates/router/src/services/authentication/decision.rs b/crates/router/src/services/authentication/decision.rs index d665b0caaf41..c31a4696bc90 100644 --- a/crates/router/src/services/authentication/decision.rs +++ b/crates/router/src/services/authentication/decision.rs @@ -67,7 +67,7 @@ pub enum Identifiers { /// [`ApiKey`] is an authentication method that uses an API key. This is used with [`ApiKey`] ApiKey { merchant_id: common_utils::id_type::MerchantId, - key_id: String, + key_id: common_utils::id_type::ApiKeyId, }, /// [`PublishableKey`] is an authentication method that uses a publishable key. This is used with [`PublishableKey`] PublishableKey { merchant_id: String }, @@ -80,7 +80,7 @@ pub async fn add_api_key( state: &SessionState, api_key: Secret, merchant_id: common_utils::id_type::MerchantId, - key_id: String, + key_id: common_utils::id_type::ApiKeyId, expiry: Option, ) -> CustomResult<(), ApiClientError> { let decision_config = if let Some(config) = &state.conf.decision { diff --git a/crates/router/src/services/authentication/detached.rs b/crates/router/src/services/authentication/detached.rs index af373d3e559d..9d77d2b1f072 100644 --- a/crates/router/src/services/authentication/detached.rs +++ b/crates/router/src/services/authentication/detached.rs @@ -1,7 +1,10 @@ use std::{borrow::Cow, string::ToString}; use actix_web::http::header::HeaderMap; -use common_utils::{crypto::VerifySignature, id_type::MerchantId}; +use common_utils::{ + crypto::VerifySignature, + id_type::{ApiKeyId, MerchantId}, +}; use error_stack::ResultExt; use hyperswitch_domain_models::errors::api_error_response::ApiErrorResponse; @@ -16,7 +19,7 @@ const HEADER_CHECKSUM: &str = "x-checksum"; pub struct ExtractedPayload { pub payload_type: PayloadType, pub merchant_id: Option, - pub key_id: Option, + pub key_id: Option, } #[derive(strum::EnumString, strum::Display, PartialEq, Debug)] @@ -61,13 +64,19 @@ impl ExtractedPayload { message: format!("`{}` header not present", HEADER_AUTH_TYPE), })?; + let key_id = headers + .get(HEADER_KEY_ID) + .and_then(|value| value.to_str().ok()) + .map(|key_id| ApiKeyId::try_from(Cow::from(key_id.to_string()))) + .transpose() + .change_context(ApiErrorResponse::InvalidRequestData { + message: format!("`{}` header is invalid or not present", HEADER_KEY_ID), + })?; + Ok(Self { payload_type: auth_type, merchant_id: Some(merchant_id), - key_id: headers - .get(HEADER_KEY_ID) - .and_then(|v| v.to_str().ok()) - .map(|v| v.to_string()), + key_id, }) } @@ -95,7 +104,7 @@ impl ExtractedPayload { &self .merchant_id .as_ref() - .map(|inner| append_option(inner.get_string_repr(), &self.key_id)), + .map(|inner| append_api_key(inner.get_string_repr(), &self.key_id)), ) } } @@ -107,3 +116,11 @@ fn append_option(prefix: &str, data: &Option) -> String { None => prefix.to_string(), } } + +#[inline] +fn append_api_key(prefix: &str, data: &Option) -> String { + match data { + Some(inner) => format!("{}:{}", prefix, inner.get_string_repr()), + None => prefix.to_string(), + } +} diff --git a/crates/router/src/services/authorization.rs b/crates/router/src/services/authorization.rs index 78af4c00884e..fe6ffac6ffc0 100644 --- a/crates/router/src/services/authorization.rs +++ b/crates/router/src/services/authorization.rs @@ -112,18 +112,6 @@ pub fn check_permission( ) } -pub fn check_entity( - required_minimum_entity: common_enums::EntityType, - role_info: &roles::RoleInfo, -) -> RouterResult<()> { - if required_minimum_entity > role_info.get_entity_type() { - Err(ApiErrorResponse::AccessForbidden { - resource: required_minimum_entity.to_string(), - })?; - } - Ok(()) -} - fn get_redis_connection(state: &A) -> RouterResult> { state .store() diff --git a/crates/router/src/services/authorization/info.rs b/crates/router/src/services/authorization/info.rs index 7cfde3efeea2..bd987e2fe9ae 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 common_enums::PermissionGroup; +use api_models::user_role::GroupInfo; +use common_enums::{ParentGroup, 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 @@ -54,32 +37,13 @@ fn get_group_description(group: PermissionGroup) -> &'static str { PermissionGroup::AnalyticsView => "View Analytics", PermissionGroup::UsersView => "View Users", PermissionGroup::UsersManage => "Manage and invite Users to the Team", - PermissionGroup::MerchantDetailsView => "View Merchant Details", - PermissionGroup::MerchantDetailsManage => "Create, modify and delete Merchant Details like api keys, webhooks, etc", + PermissionGroup::MerchantDetailsView | PermissionGroup::AccountView => "View Merchant Details", + PermissionGroup::MerchantDetailsManage | PermissionGroup::AccountManage => "Create, modify and delete Merchant Details like api keys, webhooks, etc", PermissionGroup::OrganizationManage => "Manage organization level tasks like create new Merchant accounts, Organization level roles, etc", PermissionGroup::ReconOps => "View and manage reconciliation reports", } } -pub fn get_parent_name(group: PermissionGroup) -> ParentGroup { - match group { - PermissionGroup::OperationsView | PermissionGroup::OperationsManage => { - ParentGroup::Operations - } - PermissionGroup::ConnectorsView | PermissionGroup::ConnectorsManage => { - ParentGroup::Connectors - } - PermissionGroup::WorkflowsView | PermissionGroup::WorkflowsManage => ParentGroup::Workflows, - PermissionGroup::AnalyticsView => ParentGroup::Analytics, - PermissionGroup::UsersView | PermissionGroup::UsersManage => ParentGroup::Users, - PermissionGroup::MerchantDetailsView | PermissionGroup::MerchantDetailsManage => { - ParentGroup::Merchant - } - PermissionGroup::OrganizationManage => ParentGroup::Organization, - PermissionGroup::ReconOps => ParentGroup::Recon, - } -} - pub fn get_parent_group_description(group: ParentGroup) -> &'static str { match group { ParentGroup::Operations => "Payments, Refunds, Payouts, Mandates, Disputes and Customers", @@ -87,8 +51,7 @@ pub fn get_parent_group_description(group: ParentGroup) -> &'static str { ParentGroup::Workflows => "Create, modify and delete Routing, 3DS Decision Manager, Surcharge Decision Manager", ParentGroup::Analytics => "View Analytics", ParentGroup::Users => "Manage and invite Users to the Team", - ParentGroup::Merchant => "Create, modify and delete Merchant Details like api keys, webhooks, etc", - ParentGroup::Organization =>"Manage organization level tasks like create new Merchant accounts, Organization level roles, etc", + ParentGroup::Account => "Create, modify and delete Merchant Details like api keys, webhooks, etc", ParentGroup::Recon => "View and manage reconciliation reports", } } diff --git a/crates/router/src/services/authorization/permission_groups.rs b/crates/router/src/services/authorization/permission_groups.rs index aafc9cee9430..57c385565a86 100644 --- a/crates/router/src/services/authorization/permission_groups.rs +++ b/crates/router/src/services/authorization/permission_groups.rs @@ -1,97 +1,170 @@ -use common_enums::PermissionGroup; - -use super::permissions::Permission; - -pub fn get_permissions_vec(permission_group: &PermissionGroup) -> &[Permission] { - match permission_group { - PermissionGroup::OperationsView => &OPERATIONS_VIEW, - PermissionGroup::OperationsManage => &OPERATIONS_MANAGE, - PermissionGroup::ConnectorsView => &CONNECTORS_VIEW, - PermissionGroup::ConnectorsManage => &CONNECTORS_MANAGE, - PermissionGroup::WorkflowsView => &WORKFLOWS_VIEW, - PermissionGroup::WorkflowsManage => &WORKFLOWS_MANAGE, - PermissionGroup::AnalyticsView => &ANALYTICS_VIEW, - PermissionGroup::UsersView => &USERS_VIEW, - PermissionGroup::UsersManage => &USERS_MANAGE, - PermissionGroup::MerchantDetailsView => &MERCHANT_DETAILS_VIEW, - PermissionGroup::MerchantDetailsManage => &MERCHANT_DETAILS_MANAGE, - PermissionGroup::OrganizationManage => &ORGANIZATION_MANAGE, - PermissionGroup::ReconOps => &RECON, - } +use std::collections::HashMap; + +use common_enums::{EntityType, ParentGroup, PermissionGroup, PermissionScope, Resource}; +use strum::IntoEnumIterator; + +use super::permissions::{self, ResourceExt}; + +pub trait PermissionGroupExt { + fn scope(&self) -> PermissionScope; + fn parent(&self) -> ParentGroup; + fn resources(&self) -> Vec; + fn accessible_groups(&self) -> Vec; } -pub static OPERATIONS_VIEW: [Permission; 8] = [ - Permission::PaymentRead, - Permission::RefundRead, - Permission::MandateRead, - Permission::DisputeRead, - Permission::CustomerRead, - Permission::GenerateReport, - Permission::PayoutRead, - Permission::MerchantAccountRead, -]; +impl PermissionGroupExt for PermissionGroup { + fn scope(&self) -> PermissionScope { + match self { + Self::OperationsView + | Self::ConnectorsView + | Self::WorkflowsView + | Self::AnalyticsView + | Self::UsersView + | Self::MerchantDetailsView + | Self::AccountView => PermissionScope::Read, -pub static OPERATIONS_MANAGE: [Permission; 7] = [ - Permission::PaymentWrite, - Permission::RefundWrite, - Permission::MandateWrite, - Permission::DisputeWrite, - Permission::CustomerWrite, - Permission::PayoutWrite, - Permission::MerchantAccountRead, -]; + Self::OperationsManage + | Self::ConnectorsManage + | Self::WorkflowsManage + | Self::UsersManage + | Self::MerchantDetailsManage + | Self::OrganizationManage + | Self::ReconOps + | Self::AccountManage => PermissionScope::Write, + } + } -pub static CONNECTORS_VIEW: [Permission; 2] = [ - Permission::MerchantConnectorAccountRead, - Permission::MerchantAccountRead, -]; + fn parent(&self) -> ParentGroup { + match self { + Self::OperationsView | Self::OperationsManage => ParentGroup::Operations, + Self::ConnectorsView | Self::ConnectorsManage => ParentGroup::Connectors, + Self::WorkflowsView | Self::WorkflowsManage => ParentGroup::Workflows, + Self::AnalyticsView => ParentGroup::Analytics, + Self::UsersView | Self::UsersManage => ParentGroup::Users, + Self::ReconOps => ParentGroup::Recon, + Self::MerchantDetailsView + | Self::OrganizationManage + | Self::MerchantDetailsManage + | Self::AccountView + | Self::AccountManage => ParentGroup::Account, + } + } -pub static CONNECTORS_MANAGE: [Permission; 2] = [ - Permission::MerchantConnectorAccountWrite, - Permission::MerchantAccountRead, -]; + fn resources(&self) -> Vec { + self.parent().resources() + } -pub static WORKFLOWS_VIEW: [Permission; 5] = [ - Permission::RoutingRead, - Permission::ThreeDsDecisionManagerRead, - Permission::SurchargeDecisionManagerRead, - Permission::MerchantConnectorAccountRead, - Permission::MerchantAccountRead, -]; + fn accessible_groups(&self) -> Vec { + match self { + Self::OperationsView => vec![Self::OperationsView], + Self::OperationsManage => vec![Self::OperationsView, Self::OperationsManage], -pub static WORKFLOWS_MANAGE: [Permission; 5] = [ - Permission::RoutingWrite, - Permission::ThreeDsDecisionManagerWrite, - Permission::SurchargeDecisionManagerWrite, - Permission::MerchantConnectorAccountRead, - Permission::MerchantAccountRead, -]; + Self::ConnectorsView => vec![Self::ConnectorsView], + Self::ConnectorsManage => vec![Self::ConnectorsView, Self::ConnectorsManage], -pub static ANALYTICS_VIEW: [Permission; 3] = [ - Permission::Analytics, - Permission::GenerateReport, - Permission::MerchantAccountRead, -]; + Self::WorkflowsView => vec![Self::WorkflowsView, Self::ConnectorsView], + Self::WorkflowsManage => vec![ + Self::WorkflowsView, + Self::WorkflowsManage, + Self::ConnectorsView, + ], + + Self::AnalyticsView => vec![Self::AnalyticsView, Self::OperationsView], + + Self::UsersView => vec![Self::UsersView], + Self::UsersManage => { + vec![Self::UsersView, Self::UsersManage] + } -pub static USERS_VIEW: [Permission; 2] = [Permission::UsersRead, Permission::MerchantAccountRead]; + Self::ReconOps => vec![Self::ReconOps], -pub static USERS_MANAGE: [Permission; 2] = - [Permission::UsersWrite, Permission::MerchantAccountRead]; + Self::MerchantDetailsView => vec![Self::MerchantDetailsView], + Self::MerchantDetailsManage => { + vec![Self::MerchantDetailsView, Self::MerchantDetailsManage] + } -pub static MERCHANT_DETAILS_VIEW: [Permission; 1] = [Permission::MerchantAccountRead]; + Self::OrganizationManage => vec![Self::OrganizationManage], -pub static MERCHANT_DETAILS_MANAGE: [Permission; 6] = [ - Permission::MerchantAccountWrite, - Permission::ApiKeyRead, - Permission::ApiKeyWrite, - Permission::MerchantAccountRead, - Permission::WebhookEventRead, - Permission::WebhookEventWrite, + Self::AccountView => vec![Self::AccountView], + Self::AccountManage => vec![Self::AccountView, Self::AccountManage], + } + } +} + +pub trait ParentGroupExt { + fn resources(&self) -> Vec; + fn get_descriptions_for_groups( + entity_type: EntityType, + groups: Vec, + ) -> HashMap; +} + +impl ParentGroupExt for ParentGroup { + fn resources(&self) -> Vec { + match self { + Self::Operations => OPERATIONS.to_vec(), + Self::Connectors => CONNECTORS.to_vec(), + Self::Workflows => WORKFLOWS.to_vec(), + Self::Analytics => ANALYTICS.to_vec(), + Self::Users => USERS.to_vec(), + Self::Account => ACCOUNT.to_vec(), + Self::Recon => RECON.to_vec(), + } + } + + fn get_descriptions_for_groups( + entity_type: EntityType, + groups: Vec, + ) -> HashMap { + Self::iter() + .filter_map(|parent| { + let scopes = groups + .iter() + .filter(|group| group.parent() == parent) + .map(|group| group.scope()) + .max()?; + + let resources = parent + .resources() + .iter() + .filter(|res| res.entities().iter().any(|entity| entity <= &entity_type)) + .map(|res| permissions::get_resource_name(res, &entity_type)) + .collect::>() + .join(", "); + + Some(( + parent, + format!("{} {}", permissions::get_scope_name(&scopes), resources), + )) + }) + .collect() + } +} + +pub static OPERATIONS: [Resource; 8] = [ + Resource::Payment, + Resource::Refund, + Resource::Mandate, + Resource::Dispute, + Resource::Customer, + Resource::Payout, + Resource::Report, + Resource::Account, ]; -pub static ORGANIZATION_MANAGE: [Permission; 2] = [ - Permission::MerchantAccountCreate, - Permission::MerchantAccountRead, +pub static CONNECTORS: [Resource; 2] = [Resource::Connector, Resource::Account]; + +pub static WORKFLOWS: [Resource; 4] = [ + Resource::Routing, + Resource::ThreeDsDecisionManager, + Resource::SurchargeDecisionManager, + Resource::Account, ]; -pub static RECON: [Permission; 1] = [Permission::ReconAdmin]; +pub static ANALYTICS: [Resource; 3] = [Resource::Analytics, Resource::Report, Resource::Account]; + +pub static USERS: [Resource; 2] = [Resource::User, Resource::Account]; + +pub static ACCOUNT: [Resource; 3] = [Resource::Account, Resource::ApiKey, Resource::WebhookEvent]; + +pub static RECON: [Resource; 1] = [Resource::Recon]; diff --git a/crates/router/src/services/authorization/permissions.rs b/crates/router/src/services/authorization/permissions.rs index 2f0617557caf..6e472d55623b 100644 --- a/crates/router/src/services/authorization/permissions.rs +++ b/crates/router/src/services/authorization/permissions.rs @@ -1,84 +1,106 @@ -use strum::Display; +use common_enums::{EntityType, PermissionScope, Resource}; +use router_derive::generate_permissions; -#[derive( - PartialEq, Display, Clone, Debug, Copy, Eq, Hash, serde::Deserialize, 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, - WebhookEventWrite, - PayoutRead, - PayoutWrite, - GenerateReport, - ReconAdmin, +generate_permissions! { + permissions: [ + Payment: { + scopes: [Read, Write], + entities: [Profile, Merchant] + }, + Refund: { + scopes: [Read, Write], + entities: [Profile, Merchant] + }, + Dispute: { + scopes: [Read, Write], + entities: [Profile, Merchant] + }, + Mandate: { + scopes: [Read, Write], + entities: [Merchant] + }, + Customer: { + scopes: [Read, Write], + entities: [Merchant] + }, + Payout: { + scopes: [Read], + entities: [Profile, Merchant] + }, + ApiKey: { + scopes: [Read, Write], + entities: [Merchant] + }, + Account: { + scopes: [Read, Write], + entities: [Profile, Merchant, Organization] + }, + Connector: { + scopes: [Read, Write], + entities: [Profile, Merchant] + }, + Routing: { + scopes: [Read, Write], + entities: [Profile, Merchant] + }, + ThreeDsDecisionManager: { + scopes: [Read, Write], + entities: [Merchant] + }, + SurchargeDecisionManager: { + scopes: [Read, Write], + entities: [Merchant] + }, + Analytics: { + scopes: [Read], + entities: [Profile, Merchant, Organization] + }, + Report: { + scopes: [Read], + entities: [Profile, Merchant, Organization] + }, + User: { + scopes: [Read, Write], + entities: [Profile, Merchant] + }, + WebhookEvent: { + scopes: [Read, Write], + entities: [Merchant] + }, + Recon: { + scopes: [Write], + entities: [Merchant] + }, + ] } -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", - } +pub fn get_resource_name(resource: &Resource, entity_type: &EntityType) -> &'static str { + match (resource, entity_type) { + (Resource::Payment, _) => "Payments", + (Resource::Refund, _) => "Refunds", + (Resource::Dispute, _) => "Disputes", + (Resource::Mandate, _) => "Mandates", + (Resource::Customer, _) => "Customers", + (Resource::Payout, _) => "Payouts", + (Resource::ApiKey, _) => "Api Keys", + (Resource::Connector, _) => "Payment Processors, Payout Processors, Fraud & Risk Managers", + (Resource::Routing, _) => "Routing", + (Resource::ThreeDsDecisionManager, _) => "3DS Decision Manager", + (Resource::SurchargeDecisionManager, _) => "Surcharge Decision Manager", + (Resource::Analytics, _) => "Analytics", + (Resource::Report, _) => "Operation Reports", + (Resource::User, _) => "Users", + (Resource::WebhookEvent, _) => "Webhook Events", + (Resource::Recon, _) => "Reconciliation Reports", + (Resource::Account, EntityType::Profile) => "Business Profile Account", + (Resource::Account, EntityType::Merchant) => "Merchant Account", + (Resource::Account, EntityType::Organization) => "Organization Account", + } +} + +pub fn get_scope_name(scope: &PermissionScope) -> &'static str { + match scope { + PermissionScope::Read => "View", + PermissionScope::Write => "View and Manage", } } diff --git a/crates/router/src/services/authorization/roles.rs b/crates/router/src/services/authorization/roles.rs index 19383f010f2f..bf66eb924669 100644 --- a/crates/router/src/services/authorization/roles.rs +++ b/crates/router/src/services/authorization/roles.rs @@ -1,9 +1,9 @@ use std::collections::HashSet; -use common_enums::{EntityType, PermissionGroup, RoleScope}; +use common_enums::{EntityType, PermissionGroup, Resource, RoleScope}; use common_utils::{errors::CustomResult, id_type}; -use super::{permission_groups::get_permissions_vec, permissions::Permission}; +use super::{permission_groups::PermissionGroupExt, permissions::Permission}; use crate::{core::errors, routes::SessionState}; pub mod predefined_roles; @@ -30,8 +30,13 @@ impl RoleInfo { &self.role_name } - pub fn get_permission_groups(&self) -> &Vec { - &self.groups + pub fn get_permission_groups(&self) -> Vec { + self.groups + .iter() + .flat_map(|group| group.accessible_groups()) + .collect::>() + .into_iter() + .collect() } pub fn get_scope(&self) -> RoleScope { @@ -58,17 +63,19 @@ impl RoleInfo { self.is_updatable } - pub fn get_permissions_set(&self) -> HashSet { - self.groups + pub fn get_resources_set(&self) -> HashSet { + self.get_permission_groups() .iter() - .flat_map(|group| get_permissions_vec(group).iter().copied()) + .flat_map(|group| group.resources()) .collect() } pub fn check_permission_exists(&self, required_permission: &Permission) -> bool { - self.groups - .iter() - .any(|group| get_permissions_vec(group).contains(required_permission)) + required_permission.entity_type() <= self.entity_type + && self.get_permission_groups().iter().any(|group| { + required_permission.scope() <= group.scope() + && group.resources().contains(&required_permission.resource()) + }) } pub async fn from_role_id_in_merchant_scope( @@ -112,7 +119,7 @@ impl From for RoleInfo { role_name: role.role_name, groups: role.groups.into_iter().map(Into::into).collect(), scope: role.scope, - entity_type: role.entity_type.unwrap_or(EntityType::Merchant), + entity_type: role.entity_type, is_invitable: true, is_deletable: true, is_updatable: true, diff --git a/crates/router/src/services/authorization/roles/predefined_roles.rs b/crates/router/src/services/authorization/roles/predefined_roles.rs index 33a1d5f53ca7..39f6d47f824b 100644 --- a/crates/router/src/services/authorization/roles/predefined_roles.rs +++ b/crates/router/src/services/authorization/roles/predefined_roles.rs @@ -24,7 +24,9 @@ pub static PREDEFINED_ROLES: Lazy> = Lazy::new(| PermissionGroup::UsersView, PermissionGroup::UsersManage, PermissionGroup::MerchantDetailsView, + PermissionGroup::AccountView, PermissionGroup::MerchantDetailsManage, + PermissionGroup::AccountManage, PermissionGroup::OrganizationManage, PermissionGroup::ReconOps, ], @@ -48,6 +50,7 @@ pub static PREDEFINED_ROLES: Lazy> = Lazy::new(| PermissionGroup::AnalyticsView, PermissionGroup::UsersView, PermissionGroup::MerchantDetailsView, + PermissionGroup::AccountView, ], role_id: common_utils::consts::ROLE_ID_INTERNAL_VIEW_ONLY_USER.to_string(), role_name: "internal_view_only".to_string(), @@ -75,7 +78,9 @@ pub static PREDEFINED_ROLES: Lazy> = Lazy::new(| PermissionGroup::UsersView, PermissionGroup::UsersManage, PermissionGroup::MerchantDetailsView, + PermissionGroup::AccountView, PermissionGroup::MerchantDetailsManage, + PermissionGroup::AccountManage, PermissionGroup::OrganizationManage, PermissionGroup::ReconOps, ], @@ -105,7 +110,9 @@ pub static PREDEFINED_ROLES: Lazy> = Lazy::new(| PermissionGroup::UsersView, PermissionGroup::UsersManage, PermissionGroup::MerchantDetailsView, + PermissionGroup::AccountView, PermissionGroup::MerchantDetailsManage, + PermissionGroup::AccountManage, PermissionGroup::ReconOps, ], role_id: consts::user_role::ROLE_ID_MERCHANT_ADMIN.to_string(), @@ -128,6 +135,7 @@ pub static PREDEFINED_ROLES: Lazy> = Lazy::new(| PermissionGroup::AnalyticsView, PermissionGroup::UsersView, PermissionGroup::MerchantDetailsView, + PermissionGroup::AccountView, ], role_id: consts::user_role::ROLE_ID_MERCHANT_VIEW_ONLY.to_string(), role_name: "merchant_view_only".to_string(), @@ -148,6 +156,7 @@ pub static PREDEFINED_ROLES: Lazy> = Lazy::new(| PermissionGroup::UsersView, PermissionGroup::UsersManage, PermissionGroup::MerchantDetailsView, + PermissionGroup::AccountView, ], role_id: consts::user_role::ROLE_ID_MERCHANT_IAM_ADMIN.to_string(), role_name: "merchant_iam".to_string(), @@ -168,7 +177,9 @@ pub static PREDEFINED_ROLES: Lazy> = Lazy::new(| PermissionGroup::AnalyticsView, PermissionGroup::UsersView, PermissionGroup::MerchantDetailsView, + PermissionGroup::AccountView, PermissionGroup::MerchantDetailsManage, + PermissionGroup::AccountManage, ], role_id: consts::user_role::ROLE_ID_MERCHANT_DEVELOPER.to_string(), role_name: "merchant_developer".to_string(), @@ -191,6 +202,7 @@ pub static PREDEFINED_ROLES: Lazy> = Lazy::new(| PermissionGroup::AnalyticsView, PermissionGroup::UsersView, PermissionGroup::MerchantDetailsView, + PermissionGroup::AccountView, ], role_id: consts::user_role::ROLE_ID_MERCHANT_OPERATOR.to_string(), role_name: "merchant_operator".to_string(), @@ -210,6 +222,7 @@ pub static PREDEFINED_ROLES: Lazy> = Lazy::new(| PermissionGroup::AnalyticsView, PermissionGroup::UsersView, PermissionGroup::MerchantDetailsView, + PermissionGroup::AccountView, ], role_id: consts::user_role::ROLE_ID_MERCHANT_CUSTOMER_SUPPORT.to_string(), role_name: "customer_support".to_string(), @@ -237,7 +250,9 @@ pub static PREDEFINED_ROLES: Lazy> = Lazy::new(| PermissionGroup::UsersView, PermissionGroup::UsersManage, PermissionGroup::MerchantDetailsView, + PermissionGroup::AccountView, PermissionGroup::MerchantDetailsManage, + PermissionGroup::AccountManage, ], role_id: consts::user_role::ROLE_ID_PROFILE_ADMIN.to_string(), role_name: "profile_admin".to_string(), @@ -259,6 +274,7 @@ pub static PREDEFINED_ROLES: Lazy> = Lazy::new(| PermissionGroup::AnalyticsView, PermissionGroup::UsersView, PermissionGroup::MerchantDetailsView, + PermissionGroup::AccountView, ], role_id: consts::user_role::ROLE_ID_PROFILE_VIEW_ONLY.to_string(), role_name: "profile_view_only".to_string(), @@ -279,6 +295,7 @@ pub static PREDEFINED_ROLES: Lazy> = Lazy::new(| PermissionGroup::UsersView, PermissionGroup::UsersManage, PermissionGroup::MerchantDetailsView, + PermissionGroup::AccountView, ], role_id: consts::user_role::ROLE_ID_PROFILE_IAM_ADMIN.to_string(), role_name: "profile_iam".to_string(), @@ -299,7 +316,9 @@ pub static PREDEFINED_ROLES: Lazy> = Lazy::new(| PermissionGroup::AnalyticsView, PermissionGroup::UsersView, PermissionGroup::MerchantDetailsView, + PermissionGroup::AccountView, PermissionGroup::MerchantDetailsManage, + PermissionGroup::AccountManage, ], role_id: consts::user_role::ROLE_ID_PROFILE_DEVELOPER.to_string(), role_name: "profile_developer".to_string(), @@ -322,6 +341,7 @@ pub static PREDEFINED_ROLES: Lazy> = Lazy::new(| PermissionGroup::AnalyticsView, PermissionGroup::UsersView, PermissionGroup::MerchantDetailsView, + PermissionGroup::AccountView, ], role_id: consts::user_role::ROLE_ID_PROFILE_OPERATOR.to_string(), role_name: "profile_operator".to_string(), @@ -341,6 +361,7 @@ pub static PREDEFINED_ROLES: Lazy> = Lazy::new(| PermissionGroup::AnalyticsView, PermissionGroup::UsersView, PermissionGroup::MerchantDetailsView, + PermissionGroup::AccountView, ], role_id: consts::user_role::ROLE_ID_PROFILE_CUSTOMER_SUPPORT.to_string(), role_name: "profile_customer_support".to_string(), diff --git a/crates/router/src/services/conversion_impls.rs b/crates/router/src/services/conversion_impls.rs index 22930916093d..33c655eed78a 100644 --- a/crates/router/src/services/conversion_impls.rs +++ b/crates/router/src/services/conversion_impls.rs @@ -76,6 +76,7 @@ fn get_default_router_data( integrity_check: Ok(()), additional_merchant_data: None, header_payload: None, + connector_mandate_request_reference_id: None, } } diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index 35857154332c..230ac7531103 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -441,6 +441,7 @@ impl Capturable for PaymentsIncrementalAuthorizationData { } } impl Capturable for PaymentsSyncData { + #[cfg(feature = "v1")] fn get_captured_amount(&self, payment_data: &PaymentData) -> Option where F: Clone, @@ -451,6 +452,21 @@ impl Capturable for PaymentsSyncData { .or_else(|| Some(payment_data.payment_attempt.get_total_amount())) .map(|amt| amt.get_amount_as_i64()) } + + #[cfg(feature = "v2")] + fn get_captured_amount(&self, payment_data: &PaymentData) -> Option + where + F: Clone, + { + // TODO: add a getter for this + payment_data + .payment_attempt + .amount_details + .amount_to_capture + .or_else(|| Some(payment_data.payment_attempt.get_total_amount())) + .map(|amt| amt.get_amount_as_i64()) + } + fn get_amount_capturable( &self, _payment_data: &PaymentData, @@ -863,6 +879,8 @@ impl ForeignFrom<&SetupMandateRouterData> for PaymentsAuthorizeData { charges: None, // TODO: allow charges on mandates? merchant_order_reference_id: None, integrity_object: None, + additional_payment_method_data: None, + shipping_cost: data.request.shipping_cost, } } } @@ -919,6 +937,9 @@ impl ForeignFrom<(&RouterData, T2) integrity_check: Ok(()), additional_merchant_data: data.additional_merchant_data.clone(), header_payload: data.header_payload.clone(), + connector_mandate_request_reference_id: data + .connector_mandate_request_reference_id + .clone(), } } } @@ -983,6 +1004,7 @@ impl integrity_check: Ok(()), additional_merchant_data: data.additional_merchant_data.clone(), header_payload: data.header_payload.clone(), + connector_mandate_request_reference_id: None, } } } diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index 5300e86afdb9..fbc55dce4445 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -88,9 +88,6 @@ pub trait ConnectorTransactionId: ConnectorCommon + Sync { .map(ToString::to_string)) } } - -pub trait Router {} - pub trait Connector: Send + Refund @@ -409,6 +406,7 @@ impl ConnectorData { enums::Connector::Ebanx => { Ok(ConnectorEnum::Old(Box::new(connector::Ebanx::new()))) } + // enums::Connector::Elavon => Ok(ConnectorEnum::Old(Box::new(connector::Elavon))), enums::Connector::Fiserv => Ok(ConnectorEnum::Old(Box::new(&connector::Fiserv))), enums::Connector::Fiservemea => { Ok(ConnectorEnum::Old(Box::new(connector::Fiservemea::new()))) @@ -431,9 +429,12 @@ impl ConnectorData { Ok(ConnectorEnum::Old(Box::new(connector::Iatapay::new()))) } enums::Connector::Itaubank => { + //enums::Connector::Jpmorgan => Ok(ConnectorEnum::Old(Box::new(connector::Jpmorgan))), Ok(ConnectorEnum::Old(Box::new(connector::Itaubank::new()))) } - enums::Connector::Klarna => Ok(ConnectorEnum::Old(Box::new(&connector::Klarna))), + enums::Connector::Klarna => { + Ok(ConnectorEnum::Old(Box::new(connector::Klarna::new()))) + } enums::Connector::Mollie => { Ok(ConnectorEnum::Old(Box::new(connector::Mollie::new()))) } @@ -459,7 +460,7 @@ impl ConnectorData { enums::Connector::Payone => { Ok(ConnectorEnum::Old(Box::new(connector::Payone::new()))) } - enums::Connector::Payu => Ok(ConnectorEnum::Old(Box::new(&connector::Payu))), + enums::Connector::Payu => Ok(ConnectorEnum::Old(Box::new(connector::Payu::new()))), enums::Connector::Placetopay => { Ok(ConnectorEnum::Old(Box::new(connector::Placetopay::new()))) } @@ -472,8 +473,12 @@ impl ConnectorData { enums::Connector::Razorpay => { Ok(ConnectorEnum::Old(Box::new(connector::Razorpay::new()))) } - enums::Connector::Rapyd => Ok(ConnectorEnum::Old(Box::new(&connector::Rapyd))), - enums::Connector::Shift4 => Ok(ConnectorEnum::Old(Box::new(&connector::Shift4))), + enums::Connector::Rapyd => { + Ok(ConnectorEnum::Old(Box::new(connector::Rapyd::new()))) + } + enums::Connector::Shift4 => { + Ok(ConnectorEnum::Old(Box::new(connector::Shift4::new()))) + } enums::Connector::Square => Ok(ConnectorEnum::Old(Box::new(&connector::Square))), enums::Connector::Stax => Ok(ConnectorEnum::Old(Box::new(&connector::Stax))), enums::Connector::Stripe => { @@ -508,11 +513,11 @@ impl ConnectorData { enums::Connector::Trustpay => { Ok(ConnectorEnum::Old(Box::new(connector::Trustpay::new()))) } - enums::Connector::Tsys => Ok(ConnectorEnum::Old(Box::new(&connector::Tsys))), + enums::Connector::Tsys => Ok(ConnectorEnum::Old(Box::new(connector::Tsys::new()))), enums::Connector::Volt => Ok(ConnectorEnum::Old(Box::new(connector::Volt::new()))), enums::Connector::Wellsfargo => { - Ok(ConnectorEnum::Old(Box::new(&connector::Wellsfargo))) + Ok(ConnectorEnum::Old(Box::new(connector::Wellsfargo::new()))) } // enums::Connector::Wellsfargopayout => { diff --git a/crates/router/src/types/api/payments.rs b/crates/router/src/types/api/payments.rs index 1bd3d484418e..57ef1d3336f5 100644 --- a/crates/router/src/types/api/payments.rs +++ b/crates/router/src/types/api/payments.rs @@ -1,8 +1,10 @@ +#[cfg(feature = "v1")] +pub use api_models::payments::PaymentsRequest; pub use api_models::payments::{ AcceptanceType, Address, AddressDetails, Amount, AuthenticationForStartResponse, Card, - CryptoData, CustomerAcceptance, CustomerDetailsResponse, HeaderPayload, MandateAmountData, - MandateData, MandateTransactionType, MandateType, MandateValidationFields, NextActionType, - OnlineMandate, OpenBankingSessionToken, PayLaterData, PaymentIdType, PaymentListConstraints, + CryptoData, CustomerAcceptance, CustomerDetailsResponse, MandateAmountData, MandateData, + MandateTransactionType, MandateType, MandateValidationFields, NextActionType, OnlineMandate, + OpenBankingSessionToken, PayLaterData, PaymentIdType, PaymentListConstraints, PaymentListFilterConstraints, PaymentListFilters, PaymentListFiltersV2, PaymentListResponse, PaymentListResponseV2, PaymentMethodData, PaymentMethodDataRequest, PaymentMethodDataResponse, PaymentOp, PaymentRetrieveBody, PaymentRetrieveBodyWithCredentials, PaymentsAggregateResponse, @@ -11,19 +13,19 @@ pub use api_models::payments::{ PaymentsDynamicTaxCalculationResponse, PaymentsExternalAuthenticationRequest, PaymentsIncrementalAuthorizationRequest, PaymentsManualUpdateRequest, PaymentsPostSessionTokensRequest, PaymentsPostSessionTokensResponse, PaymentsRedirectRequest, - PaymentsRedirectionResponse, PaymentsRejectRequest, PaymentsRequest, PaymentsResponse, - PaymentsResponseForm, PaymentsRetrieveRequest, PaymentsSessionRequest, PaymentsSessionResponse, - PaymentsStartRequest, PgRedirectResponse, PhoneDetails, RedirectionResponse, SessionToken, - UrlDetails, VerifyRequest, VerifyResponse, WalletData, + PaymentsRedirectionResponse, PaymentsRejectRequest, PaymentsResponse, PaymentsResponseForm, + PaymentsRetrieveRequest, PaymentsSessionRequest, PaymentsSessionResponse, PaymentsStartRequest, + PgRedirectResponse, PhoneDetails, RedirectionResponse, SessionToken, UrlDetails, VerifyRequest, + VerifyResponse, WalletData, }; #[cfg(feature = "v2")] -pub use api_models::payments::{PaymentsCreateIntentRequest, PaymentsCreateIntentResponse}; +pub use api_models::payments::{PaymentsCreateIntentRequest, PaymentsIntentResponse}; use error_stack::ResultExt; pub use hyperswitch_domain_models::router_flow_types::payments::{ Approve, Authorize, AuthorizeSessionToken, Balance, CalculateTax, Capture, CompleteAuthorize, - CreateConnectorCustomer, CreateIntent, IncrementalAuthorization, InitPayment, PSync, - PaymentMethodToken, PostProcessing, PostSessionTokens, PreProcessing, Reject, SdkSessionUpdate, - Session, SetupMandate, Void, + CreateConnectorCustomer, IncrementalAuthorization, InitPayment, PSync, PaymentCreateIntent, + PaymentGetIntent, PaymentMethodToken, PostProcessing, PostSessionTokens, PreProcessing, Reject, + SdkSessionUpdate, Session, SetupMandate, Void, }; pub use hyperswitch_interfaces::api::payments::{ ConnectorCustomer, MandateSetup, Payment, PaymentApprove, PaymentAuthorize, @@ -42,8 +44,6 @@ pub use super::payments_v2::{ }; use crate::core::errors; -impl super::Router for PaymentsRequest {} - pub trait PaymentIdTypeExt { fn get_payment_intent_id( &self, @@ -89,6 +89,7 @@ impl MandateValidationFieldsExt for MandateValidationFields { } } +#[cfg(feature = "v1")] #[cfg(test)] mod payments_test { #![allow(clippy::expect_used, clippy::unwrap_used)] diff --git a/crates/router/src/types/api/verify_connector.rs b/crates/router/src/types/api/verify_connector.rs index 6c92b1b801a9..a472296d2a75 100644 --- a/crates/router/src/types/api/verify_connector.rs +++ b/crates/router/src/types/api/verify_connector.rs @@ -57,6 +57,8 @@ impl VerifyConnectorData { charges: None, merchant_order_reference_id: None, integrity_object: None, + additional_payment_method_data: None, + shipping_cost: None, } } @@ -115,6 +117,7 @@ impl VerifyConnectorData { integrity_check: Ok(()), additional_merchant_data: None, header_payload: None, + connector_mandate_request_reference_id: None, } } } diff --git a/crates/router/src/types/domain/address.rs b/crates/router/src/types/domain/address.rs index 5d9af527cd4b..2d1e98ec1b8c 100644 --- a/crates/router/src/types/domain/address.rs +++ b/crates/router/src/types/domain/address.rs @@ -4,30 +4,38 @@ use common_utils::{ date_time, encryption::Encryption, errors::{CustomResult, ValidationError}, - id_type, type_name, + id_type, pii, type_name, types::keymanager::{Identifier, KeyManagerState, ToEncryptable}, }; use diesel_models::{address::AddressUpdateInternal, enums}; use error_stack::ResultExt; -use masking::{PeekInterface, Secret}; +use masking::{PeekInterface, Secret, SwitchStrategy}; use rustc_hash::FxHashMap; use time::{OffsetDateTime, PrimitiveDateTime}; use super::{behaviour, types}; -#[derive(Clone, Debug, serde::Serialize)] +#[derive(Clone, Debug, serde::Serialize, router_derive::ToEncryption)] pub struct Address { pub address_id: String, pub city: Option, pub country: Option, - pub line1: crypto::OptionalEncryptableSecretString, - pub line2: crypto::OptionalEncryptableSecretString, - pub line3: crypto::OptionalEncryptableSecretString, - pub state: crypto::OptionalEncryptableSecretString, - pub zip: crypto::OptionalEncryptableSecretString, - pub first_name: crypto::OptionalEncryptableSecretString, - pub last_name: crypto::OptionalEncryptableSecretString, - pub phone_number: crypto::OptionalEncryptableSecretString, + #[encrypt] + pub line1: Option>>, + #[encrypt] + pub line2: Option>>, + #[encrypt] + pub line3: Option>>, + #[encrypt] + pub state: Option>>, + #[encrypt] + pub zip: Option>>, + #[encrypt] + pub first_name: Option>>, + #[encrypt] + pub last_name: Option>>, + #[encrypt] + pub phone_number: Option>>, pub country_code: Option, #[serde(skip_serializing)] #[serde(with = "custom_serde::iso8601")] @@ -37,7 +45,8 @@ pub struct Address { pub modified_at: PrimitiveDateTime, pub merchant_id: id_type::MerchantId, pub updated_by: String, - pub email: crypto::OptionalEncryptableEmail, + #[encrypt] + pub email: Option>>, } /// Based on the flow, appropriate address has to be used @@ -191,8 +200,18 @@ impl behaviour::Conversion for Address { let decrypted: FxHashMap>> = types::crypto_operation( state, type_name!(Self::DstType), - types::CryptoOperation::BatchDecrypt(diesel_models::Address::to_encryptable( - other.clone(), + types::CryptoOperation::BatchDecrypt(EncryptedAddress::to_encryptable( + EncryptedAddress { + line1: other.line1, + line2: other.line2, + line3: other.line3, + state: other.state, + zip: other.zip, + first_name: other.first_name, + last_name: other.last_name, + phone_number: other.phone_number, + email: other.email, + }, )), identifier.clone(), key.peek(), @@ -202,10 +221,11 @@ impl behaviour::Conversion for Address { .change_context(ValidationError::InvalidValue { message: "Failed while decrypting".to_string(), })?; - let encryptable_address = diesel_models::Address::from_encryptable(decrypted) - .change_context(ValidationError::InvalidValue { + let encryptable_address = EncryptedAddress::from_encryptable(decrypted).change_context( + ValidationError::InvalidValue { message: "Failed while decrypting".to_string(), - })?; + }, + )?; Ok(Self { address_id: other.address_id, city: other.city, @@ -223,7 +243,13 @@ impl behaviour::Conversion for Address { modified_at: other.modified_at, updated_by: other.updated_by, merchant_id: other.merchant_id, - email: encryptable_address.email, + email: encryptable_address.email.map(|email| { + let encryptable: Encryptable> = Encryptable::new( + email.clone().into_inner().switch_strategy(), + email.into_encrypted(), + ); + encryptable + }), }) } diff --git a/crates/router/src/types/domain/event.rs b/crates/router/src/types/domain/event.rs index badbb9df7b4f..db2d75301643 100644 --- a/crates/router/src/types/domain/event.rs +++ b/crates/router/src/types/domain/event.rs @@ -1,22 +1,23 @@ use common_utils::{ - crypto::OptionalEncryptableSecretString, + crypto::{Encryptable, OptionalEncryptableSecretString}, + encryption::Encryption, type_name, types::keymanager::{KeyManagerState, ToEncryptable}, }; use diesel_models::{ enums::{EventClass, EventObjectType, EventType, WebhookDeliveryAttempt}, events::{EventMetadata, EventUpdateInternal}, - EventWithEncryption, }; use error_stack::ResultExt; use masking::{PeekInterface, Secret}; +use rustc_hash::FxHashMap; use crate::{ errors::{CustomResult, ValidationError}, types::domain::types, }; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, router_derive::ToEncryption)] pub struct Event { pub event_id: String, pub event_type: EventType, @@ -30,8 +31,10 @@ pub struct Event { pub primary_object_created_at: Option, pub idempotent_event_id: Option, pub initial_attempt_id: Option, - pub request: OptionalEncryptableSecretString, - pub response: OptionalEncryptableSecretString, + #[encrypt] + pub request: Option>>, + #[encrypt] + pub response: Option>>, pub delivery_attempt: Option, pub metadata: Option, } @@ -96,12 +99,10 @@ impl super::behaviour::Conversion for Event { let decrypted = types::crypto_operation( state, type_name!(Self::DstType), - types::CryptoOperation::BatchDecrypt(EventWithEncryption::to_encryptable( - EventWithEncryption { - request: item.request.clone(), - response: item.response.clone(), - }, - )), + types::CryptoOperation::BatchDecrypt(EncryptedEvent::to_encryptable(EncryptedEvent { + request: item.request.clone(), + response: item.response.clone(), + })), key_manager_identifier, key.peek(), ) @@ -110,7 +111,7 @@ impl super::behaviour::Conversion for Event { .change_context(ValidationError::InvalidValue { message: "Failed while decrypting event data".to_string(), })?; - let encryptable_event = EventWithEncryption::from_encryptable(decrypted).change_context( + let encryptable_event = EncryptedEvent::from_encryptable(decrypted).change_context( ValidationError::InvalidValue { message: "Failed while decrypting event data".to_string(), }, diff --git a/crates/router/src/types/storage.rs b/crates/router/src/types/storage.rs index 13a5291062c4..41ece363b4f8 100644 --- a/crates/router/src/types/storage.rs +++ b/crates/router/src/types/storage.rs @@ -46,8 +46,10 @@ pub use diesel_models::{ process_tracker::business_status, ProcessTracker, ProcessTrackerNew, ProcessTrackerRunner, ProcessTrackerUpdate, }; +#[cfg(feature = "v1")] +pub use hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptNew; pub use hyperswitch_domain_models::payments::{ - payment_attempt::{PaymentAttempt, PaymentAttemptNew, PaymentAttemptUpdate}, + payment_attempt::{PaymentAttempt, PaymentAttemptUpdate}, payment_intent::{PaymentIntentUpdate, PaymentIntentUpdateFields}, PaymentIntent, }; diff --git a/crates/router/src/types/storage/payment_attempt.rs b/crates/router/src/types/storage/payment_attempt.rs index 502e03b7293f..0291374d54f6 100644 --- a/crates/router/src/types/storage/payment_attempt.rs +++ b/crates/router/src/types/storage/payment_attempt.rs @@ -2,7 +2,7 @@ use common_utils::types::MinorUnit; use diesel_models::{capture::CaptureNew, enums}; use error_stack::ResultExt; pub use hyperswitch_domain_models::payments::payment_attempt::{ - PaymentAttempt, PaymentAttemptNew, PaymentAttemptUpdate, + PaymentAttempt, PaymentAttemptUpdate, }; use crate::{ @@ -123,10 +123,10 @@ impl AttemptStatusExt for enums::AttemptStatus { ))] mod tests { #![allow(clippy::expect_used, clippy::unwrap_used, clippy::print_stderr)] + use hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptNew; use tokio::sync::oneshot; use uuid::Uuid; - use super::*; use crate::{ configs::settings::Settings, db::StorageImpl, @@ -221,7 +221,7 @@ mod tests { let store = state .stores - .get(state.conf.multitenancy.get_tenant_names().first().unwrap()) + .get(state.conf.multitenancy.get_tenant_ids().first().unwrap()) .unwrap(); let response = store .insert_payment_attempt(payment_attempt, enums::MerchantStorageScheme::PostgresOnly) @@ -304,7 +304,7 @@ mod tests { }; let store = state .stores - .get(state.conf.multitenancy.get_tenant_names().first().unwrap()) + .get(state.conf.multitenancy.get_tenant_ids().first().unwrap()) .unwrap(); store .insert_payment_attempt(payment_attempt, enums::MerchantStorageScheme::PostgresOnly) @@ -401,7 +401,7 @@ mod tests { }; let store = state .stores - .get(state.conf.multitenancy.get_tenant_names().first().unwrap()) + .get(state.conf.multitenancy.get_tenant_ids().first().unwrap()) .unwrap(); store .insert_payment_attempt(payment_attempt, enums::MerchantStorageScheme::PostgresOnly) diff --git a/crates/router/src/types/storage/payment_method.rs b/crates/router/src/types/storage/payment_method.rs index 20d0ee74b011..7739c0f0ba8f 100644 --- a/crates/router/src/types/storage/payment_method.rs +++ b/crates/router/src/types/storage/payment_method.rs @@ -126,6 +126,7 @@ pub struct PaymentsMandateReferenceRecord { pub original_payment_authorized_currency: Option, pub mandate_metadata: Option, pub connector_mandate_status: Option, + pub connector_mandate_request_reference_id: Option, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index 2146ab342713..bc72431bd9c8 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -265,6 +265,7 @@ impl ForeignTryFrom for common_enums::RoutableConnectors { api_enums::Connector::Deutschebank => Self::Deutschebank, api_enums::Connector::Dlocal => Self::Dlocal, api_enums::Connector::Ebanx => Self::Ebanx, + // api_enums::Connector::Elavon => Self::Elavon, api_enums::Connector::Fiserv => Self::Fiserv, api_enums::Connector::Fiservemea => Self::Fiservemea, api_enums::Connector::Fiuu => Self::Fiuu, @@ -280,6 +281,7 @@ impl ForeignTryFrom for common_enums::RoutableConnectors { api_enums::Connector::Helcim => Self::Helcim, api_enums::Connector::Iatapay => Self::Iatapay, api_enums::Connector::Itaubank => Self::Itaubank, + //api_enums::Connector::Jpmorgan => Self::Jpmorgan, api_enums::Connector::Klarna => Self::Klarna, api_enums::Connector::Mifinity => Self::Mifinity, api_enums::Connector::Mollie => Self::Mollie, @@ -1400,7 +1402,8 @@ impl ForeignFrom for api_enums::PaymentMethod { } } -impl ForeignTryFrom<&HeaderMap> for payments::HeaderPayload { +#[cfg(feature = "v1")] +impl ForeignTryFrom<&HeaderMap> for hyperswitch_domain_models::payments::HeaderPayload { type Error = error_stack::Report; fn foreign_try_from(headers: &HeaderMap) -> Result { let payment_confirm_source: Option = @@ -1483,6 +1486,103 @@ impl ForeignTryFrom<&HeaderMap> for payments::HeaderPayload { } } +#[cfg(feature = "v2")] +impl ForeignTryFrom<&HeaderMap> for hyperswitch_domain_models::payments::HeaderPayload { + type Error = error_stack::Report; + fn foreign_try_from(headers: &HeaderMap) -> Result { + use std::str::FromStr; + + use crate::headers::X_CLIENT_SECRET; + + let payment_confirm_source: Option = + get_header_value_by_key(X_PAYMENT_CONFIRM_SOURCE.into(), headers)? + .map(|source| { + source + .to_owned() + .parse_enum("PaymentSource") + .change_context(errors::ApiErrorResponse::InvalidRequestData { + message: "Invalid data received in payment_confirm_source header" + .into(), + }) + .attach_printable( + "Failed while paring PaymentConfirmSource header value to enum", + ) + }) + .transpose()?; + when( + payment_confirm_source.is_some_and(|payment_confirm_source| { + payment_confirm_source.is_for_internal_use_only() + }), + || { + Err(report!(errors::ApiErrorResponse::InvalidRequestData { + message: "Invalid data received in payment_confirm_source header".into(), + })) + }, + )?; + let locale = + get_header_value_by_key(ACCEPT_LANGUAGE.into(), headers)?.map(|val| val.to_string()); + let x_hs_latency = get_header_value_by_key(X_HS_LATENCY.into(), headers) + .map(|value| value == Some("true")) + .unwrap_or(false); + + let client_source = + get_header_value_by_key(X_CLIENT_SOURCE.into(), headers)?.map(|val| val.to_string()); + + let client_version = + get_header_value_by_key(X_CLIENT_VERSION.into(), headers)?.map(|val| val.to_string()); + + let browser_name_str = + get_header_value_by_key(BROWSER_NAME.into(), headers)?.map(|val| val.to_string()); + + let browser_name: Option = browser_name_str.map(|browser_name| { + browser_name + .parse_enum("BrowserName") + .unwrap_or(api_enums::BrowserName::Unknown) + }); + + let x_client_platform_str = + get_header_value_by_key(X_CLIENT_PLATFORM.into(), headers)?.map(|val| val.to_string()); + + let x_client_platform: Option = + x_client_platform_str.map(|x_client_platform| { + x_client_platform + .parse_enum("ClientPlatform") + .unwrap_or(api_enums::ClientPlatform::Unknown) + }); + + let x_merchant_domain = + get_header_value_by_key(X_MERCHANT_DOMAIN.into(), headers)?.map(|val| val.to_string()); + + let x_app_id = + get_header_value_by_key(X_APP_ID.into(), headers)?.map(|val| val.to_string()); + + let x_redirect_uri = + get_header_value_by_key(X_REDIRECT_URI.into(), headers)?.map(|val| val.to_string()); + + // TODO: combine publishable key and client secret when we unify the auth + let client_secret = get_header_value_by_key(X_CLIENT_SECRET.into(), headers)? + .map(common_utils::types::ClientSecret::from_str) + .transpose() + .change_context(errors::ApiErrorResponse::InvalidRequestData { + message: "Invalid data received in client_secret header".into(), + })?; + + Ok(Self { + payment_confirm_source, + // client_source, + // client_version, + x_hs_latency: Some(x_hs_latency), + browser_name, + x_client_platform, + x_merchant_domain, + locale, + x_app_id, + x_redirect_uri, + client_secret, + }) + } +} + #[cfg(feature = "v1")] impl ForeignTryFrom<( diff --git a/crates/router/src/utils.rs b/crates/router/src/utils.rs index a54c2bc8ad6b..515c9a94ce86 100644 --- a/crates/router/src/utils.rs +++ b/crates/router/src/utils.rs @@ -13,8 +13,6 @@ pub mod user_role; pub mod verify_connector; use std::fmt::Debug; -#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] -use api_models::payments::AddressDetailsWithPhone; use api_models::{ enums, payments::{self}, @@ -22,10 +20,10 @@ use api_models::{ }; use common_utils::types::keymanager::KeyManagerState; pub use common_utils::{ - crypto, + crypto::{self, Encryptable}, ext_traits::{ByteSliceExt, BytesExt, Encode, StringExt, ValueExt}, fp_utils::when, - id_type, + id_type, pii, validation::validate_email, }; #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] @@ -38,6 +36,7 @@ pub use hyperswitch_connectors::utils::QrImage; use hyperswitch_domain_models::payments::PaymentIntent; #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] use hyperswitch_domain_models::type_encryption::{crypto_operation, CryptoOperation}; +use masking::{ExposeInterface, SwitchStrategy}; use nanoid::nanoid; use router_env::metrics::add_attributes; use serde::de::DeserializeOwned; @@ -779,20 +778,32 @@ impl CustomerAddress for api_models::customers::CustomerRequest { let encrypted_data = crypto_operation( &state.into(), type_name!(storage::Address), - CryptoOperation::BatchEncrypt(AddressDetailsWithPhone::to_encryptable( - AddressDetailsWithPhone { - address: Some(address_details.clone()), + CryptoOperation::BatchEncrypt(domain::FromRequestEncryptableAddress::to_encryptable( + domain::FromRequestEncryptableAddress { + line1: address_details.line1.clone(), + line2: address_details.line2.clone(), + line3: address_details.line3.clone(), + state: address_details.state.clone(), + first_name: address_details.first_name.clone(), + last_name: address_details.last_name.clone(), + zip: address_details.zip.clone(), phone_number: self.phone.clone(), - email: self.email.clone(), + email: self + .email + .as_ref() + .map(|a| a.clone().expose().switch_strategy()), }, )), - Identifier::Merchant(merchant_id), + Identifier::Merchant(merchant_id.to_owned()), key, ) .await .and_then(|val| val.try_into_batchoperation())?; - let encryptable_address = AddressDetailsWithPhone::from_encryptable(encrypted_data) - .change_context(common_utils::errors::CryptoError::EncodingFailed)?; + + let encryptable_address = + domain::FromRequestEncryptableAddress::from_encryptable(encrypted_data) + .change_context(common_utils::errors::CryptoError::EncodingFailed)?; + Ok(storage::AddressUpdate::Update { city: address_details.city, country: address_details.country, @@ -806,7 +817,14 @@ impl CustomerAddress for api_models::customers::CustomerRequest { phone_number: encryptable_address.phone_number, country_code: self.phone_country_code.clone(), updated_by: storage_scheme.to_string(), - email: encryptable_address.email, + email: encryptable_address.email.map(|email| { + let encryptable: Encryptable> = + Encryptable::new( + email.clone().into_inner().switch_strategy(), + email.into_encrypted(), + ); + encryptable + }), }) } @@ -822,11 +840,20 @@ impl CustomerAddress for api_models::customers::CustomerRequest { let encrypted_data = crypto_operation( &state.into(), type_name!(storage::Address), - CryptoOperation::BatchEncrypt(AddressDetailsWithPhone::to_encryptable( - AddressDetailsWithPhone { - address: Some(address_details.clone()), + CryptoOperation::BatchEncrypt(domain::FromRequestEncryptableAddress::to_encryptable( + domain::FromRequestEncryptableAddress { + line1: address_details.line1.clone(), + line2: address_details.line2.clone(), + line3: address_details.line3.clone(), + state: address_details.state.clone(), + first_name: address_details.first_name.clone(), + last_name: address_details.last_name.clone(), + zip: address_details.zip.clone(), phone_number: self.phone.clone(), - email: self.email.clone(), + email: self + .email + .as_ref() + .map(|a| a.clone().expose().switch_strategy()), }, )), Identifier::Merchant(merchant_id.to_owned()), @@ -834,8 +861,11 @@ impl CustomerAddress for api_models::customers::CustomerRequest { ) .await .and_then(|val| val.try_into_batchoperation())?; - let encryptable_address = AddressDetailsWithPhone::from_encryptable(encrypted_data) - .change_context(common_utils::errors::CryptoError::EncodingFailed)?; + + let encryptable_address = + domain::FromRequestEncryptableAddress::from_encryptable(encrypted_data) + .change_context(common_utils::errors::CryptoError::EncodingFailed)?; + let address = domain::Address { city: address_details.city, country: address_details.country, @@ -853,7 +883,14 @@ impl CustomerAddress for api_models::customers::CustomerRequest { created_at: common_utils::date_time::now(), modified_at: common_utils::date_time::now(), updated_by: storage_scheme.to_string(), - email: encryptable_address.email, + email: encryptable_address.email.map(|email| { + let encryptable: Encryptable> = + Encryptable::new( + email.clone().into_inner().switch_strategy(), + email.into_encrypted(), + ); + encryptable + }), }; Ok(domain::CustomerAddress { @@ -877,20 +914,31 @@ impl CustomerAddress for api_models::customers::CustomerUpdateRequest { let encrypted_data = crypto_operation( &state.into(), type_name!(storage::Address), - CryptoOperation::BatchEncrypt(AddressDetailsWithPhone::to_encryptable( - AddressDetailsWithPhone { - address: Some(address_details.clone()), + CryptoOperation::BatchEncrypt(domain::FromRequestEncryptableAddress::to_encryptable( + domain::FromRequestEncryptableAddress { + line1: address_details.line1.clone(), + line2: address_details.line2.clone(), + line3: address_details.line3.clone(), + state: address_details.state.clone(), + first_name: address_details.first_name.clone(), + last_name: address_details.last_name.clone(), + zip: address_details.zip.clone(), phone_number: self.phone.clone(), - email: self.email.clone(), + email: self + .email + .as_ref() + .map(|a| a.clone().expose().switch_strategy()), }, )), - Identifier::Merchant(merchant_id), + Identifier::Merchant(merchant_id.to_owned()), key, ) .await .and_then(|val| val.try_into_batchoperation())?; - let encryptable_address = AddressDetailsWithPhone::from_encryptable(encrypted_data) - .change_context(common_utils::errors::CryptoError::EncodingFailed)?; + + let encryptable_address = + domain::FromRequestEncryptableAddress::from_encryptable(encrypted_data) + .change_context(common_utils::errors::CryptoError::EncodingFailed)?; Ok(storage::AddressUpdate::Update { city: address_details.city, country: address_details.country, @@ -904,7 +952,14 @@ impl CustomerAddress for api_models::customers::CustomerUpdateRequest { phone_number: encryptable_address.phone_number, country_code: self.phone_country_code.clone(), updated_by: storage_scheme.to_string(), - email: encryptable_address.email, + email: encryptable_address.email.map(|email| { + let encryptable: Encryptable> = + Encryptable::new( + email.clone().into_inner().switch_strategy(), + email.into_encrypted(), + ); + encryptable + }), }) } @@ -920,11 +975,20 @@ impl CustomerAddress for api_models::customers::CustomerUpdateRequest { let encrypted_data = crypto_operation( &state.into(), type_name!(storage::Address), - CryptoOperation::BatchEncrypt(AddressDetailsWithPhone::to_encryptable( - AddressDetailsWithPhone { - address: Some(address_details.clone()), + CryptoOperation::BatchEncrypt(domain::FromRequestEncryptableAddress::to_encryptable( + domain::FromRequestEncryptableAddress { + line1: address_details.line1.clone(), + line2: address_details.line2.clone(), + line3: address_details.line3.clone(), + state: address_details.state.clone(), + first_name: address_details.first_name.clone(), + last_name: address_details.last_name.clone(), + zip: address_details.zip.clone(), phone_number: self.phone.clone(), - email: self.email.clone(), + email: self + .email + .as_ref() + .map(|a| a.clone().expose().switch_strategy()), }, )), Identifier::Merchant(merchant_id.to_owned()), @@ -932,8 +996,10 @@ impl CustomerAddress for api_models::customers::CustomerUpdateRequest { ) .await .and_then(|val| val.try_into_batchoperation())?; - let encryptable_address = AddressDetailsWithPhone::from_encryptable(encrypted_data) - .change_context(common_utils::errors::CryptoError::EncodingFailed)?; + + let encryptable_address = + domain::FromRequestEncryptableAddress::from_encryptable(encrypted_data) + .change_context(common_utils::errors::CryptoError::EncodingFailed)?; let address = domain::Address { city: address_details.city, country: address_details.country, @@ -951,7 +1017,14 @@ impl CustomerAddress for api_models::customers::CustomerUpdateRequest { created_at: common_utils::date_time::now(), modified_at: common_utils::date_time::now(), updated_by: storage_scheme.to_string(), - email: encryptable_address.email, + email: encryptable_address.email.map(|email| { + let encryptable: Encryptable> = + Encryptable::new( + email.clone().into_inner().switch_strategy(), + email.into_encrypted(), + ); + encryptable + }), }; Ok(domain::CustomerAddress { @@ -1166,9 +1239,9 @@ where diesel_models::enums::EventClass::Payments, payment_id.get_string_repr().to_owned(), diesel_models::enums::EventObjectType::PaymentDetails, - webhooks::OutgoingWebhookContent::PaymentDetails( + webhooks::OutgoingWebhookContent::PaymentDetails(Box::new( payments_response_json, - ), + )), primary_object_created_at, )) .await diff --git a/crates/router/src/utils/currency.rs b/crates/router/src/utils/currency.rs index dcfe0347d6fa..2173478ab673 100644 --- a/crates/router/src/utils/currency.rs +++ b/crates/router/src/utils/currency.rs @@ -26,7 +26,7 @@ const FALLBACK_FOREX_API_CURRENCY_PREFIX: &str = "USD"; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct FxExchangeRatesCacheEntry { - data: Arc, + pub data: Arc, timestamp: i64, } @@ -421,7 +421,13 @@ pub async fn fallback_fetch_forex_rates( conversions.insert(enum_curr, currency_factors); } None => { - logger::error!("Rates for {} not received from API", &enum_curr); + if enum_curr == enums::Currency::USD { + let currency_factors = + CurrencyFactors::new(Decimal::new(1, 0), Decimal::new(1, 0)); + conversions.insert(enum_curr, currency_factors); + } else { + logger::error!("Rates for {} not received from API", &enum_curr); + } } }; } diff --git a/crates/router/src/utils/user/sample_data.rs b/crates/router/src/utils/user/sample_data.rs index 7faafb14ec18..4f859d8e56a9 100644 --- a/crates/router/src/utils/user/sample_data.rs +++ b/crates/router/src/utils/user/sample_data.rs @@ -6,7 +6,9 @@ use common_utils::{ id_type, types::{ConnectorTransactionId, MinorUnit}, }; -use diesel_models::{user::sample_data::PaymentAttemptBatchNew, RefundNew}; +#[cfg(feature = "v1")] +use diesel_models::user::sample_data::PaymentAttemptBatchNew; +use diesel_models::{enums as storage_enums, DisputeNew, RefundNew}; use error_stack::ResultExt; use hyperswitch_domain_models::payments::PaymentIntent; use rand::{prelude::SliceRandom, thread_rng, Rng}; @@ -25,7 +27,14 @@ pub async fn generate_sample_data( req: SampleDataRequest, merchant_id: &id_type::MerchantId, org_id: &id_type::OrganizationId, -) -> SampleDataResult)>> { +) -> SampleDataResult< + Vec<( + PaymentIntent, + PaymentAttemptBatchNew, + Option, + Option, + )>, +> { let sample_data_size: usize = req.record.unwrap_or(100); let key_manager_state = &state.into(); if !(10..=100).contains(&sample_data_size) { @@ -118,13 +127,23 @@ pub async fn generate_sample_data( let mut refunds_count = 0; + // 2 disputes if generated data size is between 50 and 100, 1 dispute if it is less than 50. + let number_of_disputes: usize = if sample_data_size >= 50 { 2 } else { 1 }; + + let mut disputes_count = 0; + let mut random_array: Vec = (1..=sample_data_size).collect(); // Shuffle the array let mut rng = thread_rng(); random_array.shuffle(&mut rng); - let mut res: Vec<(PaymentIntent, PaymentAttemptBatchNew, Option)> = Vec::new(); + let mut res: Vec<( + PaymentIntent, + PaymentAttemptBatchNew, + Option, + Option, + )> = Vec::new(); let start_time = req .start_time .unwrap_or(common_utils::date_time::now() - time::Duration::days(7)) @@ -351,7 +370,7 @@ pub async fn generate_sample_data( internal_reference_id: common_utils::generate_id_with_default_len("test"), external_reference_id: None, payment_id: payment_id.clone(), - attempt_id, + attempt_id: attempt_id.clone(), merchant_id: merchant_id.clone(), connector_transaction_id, connector_refund_id: None, @@ -385,7 +404,43 @@ pub async fn generate_sample_data( None }; - res.push((payment_intent, payment_attempt, refund)); + let dispute = + if disputes_count < number_of_disputes && !is_failed_payment && refund.is_none() { + disputes_count += 1; + Some(DisputeNew { + dispute_id: common_utils::generate_id_with_default_len("test"), + amount: (amount * 100).to_string(), + currency: payment_intent + .currency + .unwrap_or(common_enums::Currency::USD) + .to_string(), + dispute_stage: storage_enums::DisputeStage::Dispute, + dispute_status: storage_enums::DisputeStatus::DisputeOpened, + payment_id: payment_id.clone(), + attempt_id: attempt_id.clone(), + merchant_id: merchant_id.clone(), + connector_status: "Sample connector status".into(), + connector_dispute_id: common_utils::generate_id_with_default_len("test"), + connector_reason: Some("Sample Dispute".into()), + connector_reason_code: Some("123".into()), + challenge_required_by: None, + connector_created_at: None, + connector_updated_at: None, + connector: payment_attempt + .connector + .clone() + .unwrap_or(DummyConnector4.to_string()), + evidence: None, + profile_id: payment_intent.profile_id.clone(), + merchant_connector_id: payment_attempt.merchant_connector_id.clone(), + dispute_amount: amount * 100, + organization_id: org_id.clone(), + }) + } else { + None + }; + + res.push((payment_intent, payment_attempt, refund, dispute)); } Ok(res) } diff --git a/crates/router/src/utils/user_role.rs b/crates/router/src/utils/user_role.rs index 0ea423989f5d..6f0d94d2927f 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)) diff --git a/crates/router/src/workflows/outgoing_webhook_retry.rs b/crates/router/src/workflows/outgoing_webhook_retry.rs index 89fd3200d7de..1bfcc8ebe7bb 100644 --- a/crates/router/src/workflows/outgoing_webhook_retry.rs +++ b/crates/router/src/workflows/outgoing_webhook_retry.rs @@ -344,7 +344,7 @@ async fn get_outgoing_webhook_content_and_event_type( ) -> Result<(OutgoingWebhookContent, Option), errors::ProcessTrackerError> { use api_models::{ mandates::MandateId, - payments::{HeaderPayload, PaymentIdType, PaymentsResponse, PaymentsRetrieveRequest}, + payments::{PaymentIdType, PaymentsResponse, PaymentsRetrieveRequest}, refunds::{RefundResponse, RefundsRetrieveRequest}, }; @@ -399,7 +399,7 @@ async fn get_outgoing_webhook_content_and_event_type( AuthFlow::Client, CallConnectorAction::Avoid, None, - HeaderPayload::default(), + hyperswitch_domain_models::payments::HeaderPayload::default(), )) .await? { @@ -423,7 +423,7 @@ async fn get_outgoing_webhook_content_and_event_type( logger::debug!(current_resource_status=%payments_response.status); Ok(( - OutgoingWebhookContent::PaymentDetails(payments_response), + OutgoingWebhookContent::PaymentDetails(Box::new(payments_response)), event_type, )) } @@ -449,7 +449,7 @@ async fn get_outgoing_webhook_content_and_event_type( let refund_response = RefundResponse::foreign_from(refund); Ok(( - OutgoingWebhookContent::RefundDetails(refund_response), + OutgoingWebhookContent::RefundDetails(Box::new(refund_response)), event_type, )) } @@ -548,7 +548,7 @@ async fn get_outgoing_webhook_content_and_event_type( logger::debug!(current_resource_status=%payout_data.payout_attempt.status); Ok(( - OutgoingWebhookContent::PayoutDetails(payout_create_response), + OutgoingWebhookContent::PayoutDetails(Box::new(payout_create_response)), event_type, )) } diff --git a/crates/router/src/workflows/payment_sync.rs b/crates/router/src/workflows/payment_sync.rs index f34d707b6c83..b4fcf69241b8 100644 --- a/crates/router/src/workflows/payment_sync.rs +++ b/crates/router/src/workflows/payment_sync.rs @@ -90,7 +90,7 @@ impl ProcessTrackerWorkflow for PaymentsSyncWorkflow { payment_flows::CallConnectorAction::Trigger, services::AuthFlow::Client, None, - api::HeaderPayload::default(), + hyperswitch_domain_models::payments::HeaderPayload::default(), )) .await?; diff --git a/crates/router/tests/connectors/aci.rs b/crates/router/tests/connectors/aci.rs index 5d48a0188ff5..6f4855d1e22a 100644 --- a/crates/router/tests/connectors/aci.rs +++ b/crates/router/tests/connectors/aci.rs @@ -128,6 +128,7 @@ fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData { integrity_check: Ok(()), additional_merchant_data: None, header_payload: None, + connector_mandate_request_reference_id: None, } } @@ -197,6 +198,7 @@ fn construct_refund_router_data() -> types::RefundsRouterData { integrity_check: Ok(()), additional_merchant_data: None, header_payload: None, + connector_mandate_request_reference_id: None, } } diff --git a/crates/router/tests/connectors/elavon.rs b/crates/router/tests/connectors/elavon.rs new file mode 100644 index 000000000000..af00ab909a1d --- /dev/null +++ b/crates/router/tests/connectors/elavon.rs @@ -0,0 +1,427 @@ +use hyperswitch_domain_models::payment_method_data::{Card, PaymentMethodData}; +use masking::Secret; +use router::types::{self, api, storage::enums}; +use test_utils::connector_auth; + +use crate::utils::{self, ConnectorActions}; + +#[derive(Clone, Copy)] +struct ElavonTest; +impl ConnectorActions for ElavonTest {} +impl utils::Connector for ElavonTest { + fn get_data(&self) -> api::ConnectorData { + use router::connector::Elavon; + utils::construct_connector_data_old( + Box::new(Elavon::new()), + types::Connector::Plaid, + api::GetToken::Connector, + None, + ) + // api::ConnectorData { + // connector: Box::new(Elavon::new()), + // connector_name: types::Connector::Elavon, + // get_token: types::api::GetToken::Connector, + // merchant_connector_id: None, + // } + } + + fn get_auth_token(&self) -> types::ConnectorAuthType { + utils::to_connector_auth_type( + connector_auth::ConnectorAuthentication::new() + .elavon + .expect("Missing connector authentication configuration") + .into(), + ) + } + + fn get_name(&self) -> String { + "elavon".to_string() + } +} + +static CONNECTOR: ElavonTest = ElavonTest {}; + +fn get_default_payment_info() -> Option { + None +} + +fn payment_method_details() -> Option { + None +} + +// Cards Positive Tests +// Creates a payment using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_only_authorize_payment() { + let response = CONNECTOR + .authorize_payment(payment_method_details(), get_default_payment_info()) + .await + .expect("Authorize payment response"); + assert_eq!(response.status, enums::AttemptStatus::Authorized); +} + +// Captures a payment using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_capture_authorized_payment() { + let response = CONNECTOR + .authorize_and_capture_payment(payment_method_details(), None, get_default_payment_info()) + .await + .expect("Capture payment response"); + assert_eq!(response.status, enums::AttemptStatus::Charged); +} + +// Partially captures a payment using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_partially_capture_authorized_payment() { + let response = CONNECTOR + .authorize_and_capture_payment( + payment_method_details(), + Some(types::PaymentsCaptureData { + amount_to_capture: 50, + ..utils::PaymentCaptureType::default().0 + }), + get_default_payment_info(), + ) + .await + .expect("Capture payment response"); + assert_eq!(response.status, enums::AttemptStatus::Charged); +} + +// Synchronizes a payment using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_sync_authorized_payment() { + let authorize_response = CONNECTOR + .authorize_payment(payment_method_details(), get_default_payment_info()) + .await + .expect("Authorize payment response"); + let txn_id = utils::get_connector_transaction_id(authorize_response.response); + let response = CONNECTOR + .psync_retry_till_status_matches( + enums::AttemptStatus::Authorized, + Some(types::PaymentsSyncData { + connector_transaction_id: types::ResponseId::ConnectorTransactionId( + txn_id.unwrap(), + ), + ..Default::default() + }), + get_default_payment_info(), + ) + .await + .expect("PSync response"); + assert_eq!(response.status, enums::AttemptStatus::Authorized,); +} + +// Voids a payment using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_void_authorized_payment() { + let response = CONNECTOR + .authorize_and_void_payment( + payment_method_details(), + Some(types::PaymentsCancelData { + connector_transaction_id: String::from(""), + cancellation_reason: Some("requested_by_customer".to_string()), + ..Default::default() + }), + get_default_payment_info(), + ) + .await + .expect("Void payment response"); + assert_eq!(response.status, enums::AttemptStatus::Voided); +} + +// Refunds a payment using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_refund_manually_captured_payment() { + let response = CONNECTOR + .capture_payment_and_refund( + payment_method_details(), + None, + None, + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap().refund_status, + enums::RefundStatus::Success, + ); +} + +// Partially refunds a payment using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_partially_refund_manually_captured_payment() { + let response = CONNECTOR + .capture_payment_and_refund( + payment_method_details(), + None, + Some(types::RefundsData { + refund_amount: 50, + ..utils::PaymentRefundType::default().0 + }), + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap().refund_status, + enums::RefundStatus::Success, + ); +} + +// Synchronizes a refund using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_sync_manually_captured_refund() { + let refund_response = CONNECTOR + .capture_payment_and_refund( + payment_method_details(), + None, + None, + get_default_payment_info(), + ) + .await + .unwrap(); + let response = CONNECTOR + .rsync_retry_till_status_matches( + enums::RefundStatus::Success, + refund_response.response.unwrap().connector_refund_id, + None, + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap().refund_status, + enums::RefundStatus::Success, + ); +} + +// Creates a payment using the automatic capture flow (Non 3DS). +#[actix_web::test] +async fn should_make_payment() { + let authorize_response = CONNECTOR + .make_payment(payment_method_details(), get_default_payment_info()) + .await + .unwrap(); + assert_eq!(authorize_response.status, enums::AttemptStatus::Charged); +} + +// Synchronizes a payment using the automatic capture flow (Non 3DS). +#[actix_web::test] +async fn should_sync_auto_captured_payment() { + let authorize_response = CONNECTOR + .make_payment(payment_method_details(), get_default_payment_info()) + .await + .unwrap(); + assert_eq!(authorize_response.status, enums::AttemptStatus::Charged); + let txn_id = utils::get_connector_transaction_id(authorize_response.response); + assert_ne!(txn_id, None, "Empty connector transaction id"); + let response = CONNECTOR + .psync_retry_till_status_matches( + enums::AttemptStatus::Charged, + Some(types::PaymentsSyncData { + connector_transaction_id: types::ResponseId::ConnectorTransactionId( + txn_id.unwrap(), + ), + capture_method: Some(enums::CaptureMethod::Automatic), + ..Default::default() + }), + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!(response.status, enums::AttemptStatus::Charged,); +} + +// Refunds a payment using the automatic capture flow (Non 3DS). +#[actix_web::test] +async fn should_refund_auto_captured_payment() { + let response = CONNECTOR + .make_payment_and_refund(payment_method_details(), None, get_default_payment_info()) + .await + .unwrap(); + assert_eq!( + response.response.unwrap().refund_status, + enums::RefundStatus::Success, + ); +} + +// Partially refunds a payment using the automatic capture flow (Non 3DS). +#[actix_web::test] +async fn should_partially_refund_succeeded_payment() { + let refund_response = CONNECTOR + .make_payment_and_refund( + payment_method_details(), + Some(types::RefundsData { + refund_amount: 50, + ..utils::PaymentRefundType::default().0 + }), + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + refund_response.response.unwrap().refund_status, + enums::RefundStatus::Success, + ); +} + +// Creates multiple refunds against a payment using the automatic capture flow (Non 3DS). +#[actix_web::test] +async fn should_refund_succeeded_payment_multiple_times() { + CONNECTOR + .make_payment_and_multiple_refund( + payment_method_details(), + Some(types::RefundsData { + refund_amount: 50, + ..utils::PaymentRefundType::default().0 + }), + get_default_payment_info(), + ) + .await; +} + +// Synchronizes a refund using the automatic capture flow (Non 3DS). +#[actix_web::test] +async fn should_sync_refund() { + let refund_response = CONNECTOR + .make_payment_and_refund(payment_method_details(), None, get_default_payment_info()) + .await + .unwrap(); + let response = CONNECTOR + .rsync_retry_till_status_matches( + enums::RefundStatus::Success, + refund_response.response.unwrap().connector_refund_id, + None, + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap().refund_status, + enums::RefundStatus::Success, + ); +} + +// Cards Negative scenarios +// Creates a payment with incorrect CVC. +#[actix_web::test] +async fn should_fail_payment_for_incorrect_cvc() { + let response = CONNECTOR + .make_payment( + Some(types::PaymentsAuthorizeData { + payment_method_data: PaymentMethodData::Card(Card { + card_cvc: Secret::new("12345".to_string()), + ..utils::CCardType::default().0 + }), + ..utils::PaymentAuthorizeType::default().0 + }), + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap_err().message, + "Your card's security code is invalid.".to_string(), + ); +} + +// Creates a payment with incorrect expiry month. +#[actix_web::test] +async fn should_fail_payment_for_invalid_exp_month() { + let response = CONNECTOR + .make_payment( + Some(types::PaymentsAuthorizeData { + payment_method_data: PaymentMethodData::Card(Card { + card_exp_month: Secret::new("20".to_string()), + ..utils::CCardType::default().0 + }), + ..utils::PaymentAuthorizeType::default().0 + }), + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap_err().message, + "Your card's expiration month is invalid.".to_string(), + ); +} + +// Creates a payment with incorrect expiry year. +#[actix_web::test] +async fn should_fail_payment_for_incorrect_expiry_year() { + let response = CONNECTOR + .make_payment( + Some(types::PaymentsAuthorizeData { + payment_method_data: PaymentMethodData::Card(Card { + card_exp_year: Secret::new("2000".to_string()), + ..utils::CCardType::default().0 + }), + ..utils::PaymentAuthorizeType::default().0 + }), + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap_err().message, + "Your card's expiration year is invalid.".to_string(), + ); +} + +// Voids a payment using automatic capture flow (Non 3DS). +#[actix_web::test] +async fn should_fail_void_payment_for_auto_capture() { + let authorize_response = CONNECTOR + .make_payment(payment_method_details(), get_default_payment_info()) + .await + .unwrap(); + assert_eq!(authorize_response.status, enums::AttemptStatus::Charged); + let txn_id = utils::get_connector_transaction_id(authorize_response.response); + assert_ne!(txn_id, None, "Empty connector transaction id"); + let void_response = CONNECTOR + .void_payment(txn_id.unwrap(), None, get_default_payment_info()) + .await + .unwrap(); + assert_eq!( + void_response.response.unwrap_err().message, + "You cannot cancel this PaymentIntent because it has a status of succeeded." + ); +} + +// Captures a payment using invalid connector payment id. +#[actix_web::test] +async fn should_fail_capture_for_invalid_payment() { + let capture_response = CONNECTOR + .capture_payment("123456789".to_string(), None, get_default_payment_info()) + .await + .unwrap(); + assert_eq!( + capture_response.response.unwrap_err().message, + String::from("No such payment_intent: '123456789'") + ); +} + +// Refunds a payment with refund amount higher than payment amount. +#[actix_web::test] +async fn should_fail_for_refund_amount_higher_than_payment_amount() { + let response = CONNECTOR + .make_payment_and_refund( + payment_method_details(), + Some(types::RefundsData { + refund_amount: 150, + ..utils::PaymentRefundType::default().0 + }), + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap_err().message, + "Refund amount (₹1.50) is greater than charge amount (₹1.00)", + ); +} + +// Connector dependent test cases goes here + +// [#478]: add unit tests for non 3DS, wallets & webhooks in connector tests diff --git a/crates/router/tests/connectors/jpmorgan.rs b/crates/router/tests/connectors/jpmorgan.rs new file mode 100644 index 000000000000..9e364a3bbb61 --- /dev/null +++ b/crates/router/tests/connectors/jpmorgan.rs @@ -0,0 +1,427 @@ +use hyperswitch_domain_models::payment_method_data::{Card, PaymentMethodData}; +use masking::Secret; +use router::types::{self, api, storage::enums}; +use test_utils::connector_auth; + +use crate::utils::{self, ConnectorActions}; + +#[derive(Clone, Copy)] +struct JpmorganTest; +impl JpmorganTest { + #[allow(dead_code)] + fn new() -> Self { + Self + } +} +impl ConnectorActions for JpmorganTest {} +impl utils::Connector for JpmorganTest { + fn get_data(&self) -> api::ConnectorData { + use router::connector::Jpmorgan; + utils::construct_connector_data_old( + Box::new(Jpmorgan::new()), + types::Connector::Plaid, + api::GetToken::Connector, + None, + ) + } + + fn get_auth_token(&self) -> types::ConnectorAuthType { + utils::to_connector_auth_type( + connector_auth::ConnectorAuthentication::new() + .jpmorgan + .expect("Missing connector authentication configuration") + .into(), + ) + } + + fn get_name(&self) -> String { + "jpmorgan".to_string() + } +} + +static CONNECTOR: JpmorganTest = JpmorganTest {}; + +fn get_default_payment_info() -> Option { + None +} + +fn payment_method_details() -> Option { + None +} + +// Cards Positive Tests +// Creates a payment using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_only_authorize_payment() { + let response = CONNECTOR + .authorize_payment(payment_method_details(), get_default_payment_info()) + .await + .expect("Authorize payment response"); + assert_eq!(response.status, enums::AttemptStatus::Authorized); +} + +// Captures a payment using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_capture_authorized_payment() { + let response = CONNECTOR + .authorize_and_capture_payment(payment_method_details(), None, get_default_payment_info()) + .await + .expect("Capture payment response"); + assert_eq!(response.status, enums::AttemptStatus::Charged); +} + +// Partially captures a payment using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_partially_capture_authorized_payment() { + let response = CONNECTOR + .authorize_and_capture_payment( + payment_method_details(), + Some(types::PaymentsCaptureData { + amount_to_capture: 50, + ..utils::PaymentCaptureType::default().0 + }), + get_default_payment_info(), + ) + .await + .expect("Capture payment response"); + assert_eq!(response.status, enums::AttemptStatus::Charged); +} + +// Synchronizes a payment using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_sync_authorized_payment() { + let authorize_response = CONNECTOR + .authorize_payment(payment_method_details(), get_default_payment_info()) + .await + .expect("Authorize payment response"); + let txn_id = utils::get_connector_transaction_id(authorize_response.response); + let response = CONNECTOR + .psync_retry_till_status_matches( + enums::AttemptStatus::Authorized, + Some(types::PaymentsSyncData { + connector_transaction_id: types::ResponseId::ConnectorTransactionId( + txn_id.unwrap(), + ), + ..Default::default() + }), + get_default_payment_info(), + ) + .await + .expect("PSync response"); + assert_eq!(response.status, enums::AttemptStatus::Authorized,); +} + +// Voids a payment using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_void_authorized_payment() { + let response = CONNECTOR + .authorize_and_void_payment( + payment_method_details(), + Some(types::PaymentsCancelData { + connector_transaction_id: String::from(""), + cancellation_reason: Some("requested_by_customer".to_string()), + ..Default::default() + }), + get_default_payment_info(), + ) + .await + .expect("Void payment response"); + assert_eq!(response.status, enums::AttemptStatus::Voided); +} + +// Refunds a payment using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_refund_manually_captured_payment() { + let response = CONNECTOR + .capture_payment_and_refund( + payment_method_details(), + None, + None, + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap().refund_status, + enums::RefundStatus::Success, + ); +} + +// Partially refunds a payment using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_partially_refund_manually_captured_payment() { + let response = CONNECTOR + .capture_payment_and_refund( + payment_method_details(), + None, + Some(types::RefundsData { + refund_amount: 50, + ..utils::PaymentRefundType::default().0 + }), + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap().refund_status, + enums::RefundStatus::Success, + ); +} + +// Synchronizes a refund using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_sync_manually_captured_refund() { + let refund_response = CONNECTOR + .capture_payment_and_refund( + payment_method_details(), + None, + None, + get_default_payment_info(), + ) + .await + .unwrap(); + let response = CONNECTOR + .rsync_retry_till_status_matches( + enums::RefundStatus::Success, + refund_response.response.unwrap().connector_refund_id, + None, + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap().refund_status, + enums::RefundStatus::Success, + ); +} + +// Creates a payment using the automatic capture flow (Non 3DS). +#[actix_web::test] +async fn should_make_payment() { + let authorize_response = CONNECTOR + .make_payment(payment_method_details(), get_default_payment_info()) + .await + .unwrap(); + assert_eq!(authorize_response.status, enums::AttemptStatus::Charged); +} + +// Synchronizes a payment using the automatic capture flow (Non 3DS). +#[actix_web::test] +async fn should_sync_auto_captured_payment() { + let authorize_response = CONNECTOR + .make_payment(payment_method_details(), get_default_payment_info()) + .await + .unwrap(); + assert_eq!(authorize_response.status, enums::AttemptStatus::Charged); + let txn_id = utils::get_connector_transaction_id(authorize_response.response); + assert_ne!(txn_id, None, "Empty connector transaction id"); + let response = CONNECTOR + .psync_retry_till_status_matches( + enums::AttemptStatus::Charged, + Some(types::PaymentsSyncData { + connector_transaction_id: types::ResponseId::ConnectorTransactionId( + txn_id.unwrap(), + ), + capture_method: Some(enums::CaptureMethod::Automatic), + ..Default::default() + }), + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!(response.status, enums::AttemptStatus::Charged,); +} + +// Refunds a payment using the automatic capture flow (Non 3DS). +#[actix_web::test] +async fn should_refund_auto_captured_payment() { + let response = CONNECTOR + .make_payment_and_refund(payment_method_details(), None, get_default_payment_info()) + .await + .unwrap(); + assert_eq!( + response.response.unwrap().refund_status, + enums::RefundStatus::Success, + ); +} + +// Partially refunds a payment using the automatic capture flow (Non 3DS). +#[actix_web::test] +async fn should_partially_refund_succeeded_payment() { + let refund_response = CONNECTOR + .make_payment_and_refund( + payment_method_details(), + Some(types::RefundsData { + refund_amount: 50, + ..utils::PaymentRefundType::default().0 + }), + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + refund_response.response.unwrap().refund_status, + enums::RefundStatus::Success, + ); +} + +// Creates multiple refunds against a payment using the automatic capture flow (Non 3DS). +#[actix_web::test] +async fn should_refund_succeeded_payment_multiple_times() { + CONNECTOR + .make_payment_and_multiple_refund( + payment_method_details(), + Some(types::RefundsData { + refund_amount: 50, + ..utils::PaymentRefundType::default().0 + }), + get_default_payment_info(), + ) + .await; +} + +// Synchronizes a refund using the automatic capture flow (Non 3DS). +#[actix_web::test] +async fn should_sync_refund() { + let refund_response = CONNECTOR + .make_payment_and_refund(payment_method_details(), None, get_default_payment_info()) + .await + .unwrap(); + let response = CONNECTOR + .rsync_retry_till_status_matches( + enums::RefundStatus::Success, + refund_response.response.unwrap().connector_refund_id, + None, + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap().refund_status, + enums::RefundStatus::Success, + ); +} + +// Cards Negative scenarios +// Creates a payment with incorrect CVC. +#[actix_web::test] +async fn should_fail_payment_for_incorrect_cvc() { + let response = CONNECTOR + .make_payment( + Some(types::PaymentsAuthorizeData { + payment_method_data: PaymentMethodData::Card(Card { + card_cvc: Secret::new("12345".to_string()), + ..utils::CCardType::default().0 + }), + ..utils::PaymentAuthorizeType::default().0 + }), + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap_err().message, + "Your card's security code is invalid.".to_string(), + ); +} + +// Creates a payment with incorrect expiry month. +#[actix_web::test] +async fn should_fail_payment_for_invalid_exp_month() { + let response = CONNECTOR + .make_payment( + Some(types::PaymentsAuthorizeData { + payment_method_data: PaymentMethodData::Card(Card { + card_exp_month: Secret::new("20".to_string()), + ..utils::CCardType::default().0 + }), + ..utils::PaymentAuthorizeType::default().0 + }), + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap_err().message, + "Your card's expiration month is invalid.".to_string(), + ); +} + +// Creates a payment with incorrect expiry year. +#[actix_web::test] +async fn should_fail_payment_for_incorrect_expiry_year() { + let response = CONNECTOR + .make_payment( + Some(types::PaymentsAuthorizeData { + payment_method_data: PaymentMethodData::Card(Card { + card_exp_year: Secret::new("2000".to_string()), + ..utils::CCardType::default().0 + }), + ..utils::PaymentAuthorizeType::default().0 + }), + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap_err().message, + "Your card's expiration year is invalid.".to_string(), + ); +} + +// Voids a payment using automatic capture flow (Non 3DS). +#[actix_web::test] +async fn should_fail_void_payment_for_auto_capture() { + let authorize_response = CONNECTOR + .make_payment(payment_method_details(), get_default_payment_info()) + .await + .unwrap(); + assert_eq!(authorize_response.status, enums::AttemptStatus::Charged); + let txn_id = utils::get_connector_transaction_id(authorize_response.response); + assert_ne!(txn_id, None, "Empty connector transaction id"); + let void_response = CONNECTOR + .void_payment(txn_id.unwrap(), None, get_default_payment_info()) + .await + .unwrap(); + assert_eq!( + void_response.response.unwrap_err().message, + "You cannot cancel this PaymentIntent because it has a status of succeeded." + ); +} + +// Captures a payment using invalid connector payment id. +#[actix_web::test] +async fn should_fail_capture_for_invalid_payment() { + let capture_response = CONNECTOR + .capture_payment("123456789".to_string(), None, get_default_payment_info()) + .await + .unwrap(); + assert_eq!( + capture_response.response.unwrap_err().message, + String::from("No such payment_intent: '123456789'") + ); +} + +// Refunds a payment with refund amount higher than payment amount. +#[actix_web::test] +async fn should_fail_for_refund_amount_higher_than_payment_amount() { + let response = CONNECTOR + .make_payment_and_refund( + payment_method_details(), + Some(types::RefundsData { + refund_amount: 150, + ..utils::PaymentRefundType::default().0 + }), + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap_err().message, + "Refund amount (₹1.50) is greater than charge amount (₹1.00)", + ); +} + +// Connector dependent test cases goes here + +// [#478]: add unit tests for non 3DS, wallets & webhooks in connector tests diff --git a/crates/router/tests/connectors/main.rs b/crates/router/tests/connectors/main.rs index 433f2d03eea6..c2a0d75411be 100644 --- a/crates/router/tests/connectors/main.rs +++ b/crates/router/tests/connectors/main.rs @@ -31,6 +31,7 @@ mod dlocal; #[cfg(feature = "dummy_connector")] mod dummyconnector; mod ebanx; +mod elavon; mod fiserv; mod fiservemea; mod fiuu; @@ -42,6 +43,7 @@ mod gpayments; mod helcim; mod iatapay; mod itaubank; +mod jpmorgan; mod mifinity; mod mollie; mod multisafepay; diff --git a/crates/router/tests/connectors/payme.rs b/crates/router/tests/connectors/payme.rs index e85c57df622f..3b4cf5195f5e 100644 --- a/crates/router/tests/connectors/payme.rs +++ b/crates/router/tests/connectors/payme.rs @@ -1,7 +1,7 @@ use std::str::FromStr; use api_models::payments::{Address, AddressDetails, OrderDetailsWithAmount}; -use common_utils::pii::Email; +use common_utils::{pii::Email, types::MinorUnit}; use masking::Secret; use router::types::{self, domain, storage::enums, PaymentAddress}; @@ -80,7 +80,7 @@ fn payment_method_details() -> Option { order_details: Some(vec![OrderDetailsWithAmount { product_name: "iphone 13".to_string(), quantity: 1, - amount: 1000, + amount: MinorUnit::new(1000), product_img_link: None, requires_shipping: None, product_id: None, @@ -381,7 +381,7 @@ async fn should_fail_payment_for_incorrect_cvc() { order_details: Some(vec![OrderDetailsWithAmount { product_name: "iphone 13".to_string(), quantity: 1, - amount: 100, + amount: MinorUnit::new(100), product_img_link: None, requires_shipping: None, product_id: None, @@ -421,7 +421,7 @@ async fn should_fail_payment_for_invalid_exp_month() { order_details: Some(vec![OrderDetailsWithAmount { product_name: "iphone 13".to_string(), quantity: 1, - amount: 100, + amount: MinorUnit::new(100), product_img_link: None, requires_shipping: None, product_id: None, @@ -461,7 +461,7 @@ async fn should_fail_payment_for_incorrect_expiry_year() { order_details: Some(vec![OrderDetailsWithAmount { product_name: "iphone 13".to_string(), quantity: 1, - amount: 100, + amount: MinorUnit::new(100), product_img_link: None, requires_shipping: None, product_id: None, diff --git a/crates/router/tests/connectors/payu.rs b/crates/router/tests/connectors/payu.rs index b0e5e9ec6a1d..9bb3785bbd6a 100644 --- a/crates/router/tests/connectors/payu.rs +++ b/crates/router/tests/connectors/payu.rs @@ -11,7 +11,7 @@ impl Connector for Payu { fn get_data(&self) -> types::api::ConnectorData { use router::connector::Payu; utils::construct_connector_data_old( - Box::new(&Payu), + Box::new(Payu::new()), types::Connector::Payu, types::api::GetToken::Connector, None, diff --git a/crates/router/tests/connectors/rapyd.rs b/crates/router/tests/connectors/rapyd.rs index fe6bc34cf18f..ff083a37e595 100644 --- a/crates/router/tests/connectors/rapyd.rs +++ b/crates/router/tests/connectors/rapyd.rs @@ -16,7 +16,7 @@ impl utils::Connector for Rapyd { fn get_data(&self) -> types::api::ConnectorData { use router::connector::Rapyd; utils::construct_connector_data_old( - Box::new(&Rapyd), + Box::new(Rapyd::new()), types::Connector::Rapyd, types::api::GetToken::Connector, None, diff --git a/crates/router/tests/connectors/sample_auth.toml b/crates/router/tests/connectors/sample_auth.toml index 2b20ed4cf167..caaafcdb6cf5 100644 --- a/crates/router/tests/connectors/sample_auth.toml +++ b/crates/router/tests/connectors/sample_auth.toml @@ -283,3 +283,9 @@ api_secret = "Client Key" [thunes] api_key="API Key" + +[jpmorgan] +api_key="API Key" + +[elavon] +api_key="API Key" \ No newline at end of file diff --git a/crates/router/tests/connectors/shift4.rs b/crates/router/tests/connectors/shift4.rs index fdaa1ebedefc..ce10c9dad1a6 100644 --- a/crates/router/tests/connectors/shift4.rs +++ b/crates/router/tests/connectors/shift4.rs @@ -15,7 +15,7 @@ impl utils::Connector for Shift4Test { fn get_data(&self) -> types::api::ConnectorData { use router::connector::Shift4; utils::construct_connector_data_old( - Box::new(&Shift4), + Box::new(Shift4::new()), types::Connector::Shift4, types::api::GetToken::Connector, None, diff --git a/crates/router/tests/connectors/tsys.rs b/crates/router/tests/connectors/tsys.rs index 4cda0b479b24..6a4843ac2cd1 100644 --- a/crates/router/tests/connectors/tsys.rs +++ b/crates/router/tests/connectors/tsys.rs @@ -16,7 +16,7 @@ impl utils::Connector for TsysTest { fn get_data(&self) -> types::api::ConnectorData { use router::connector::Tsys; utils::construct_connector_data_old( - Box::new(&Tsys), + Box::new(Tsys::new()), types::Connector::Tsys, types::api::GetToken::Connector, None, diff --git a/crates/router/tests/connectors/utils.rs b/crates/router/tests/connectors/utils.rs index 5acfd67c5470..52218b211ac1 100644 --- a/crates/router/tests/connectors/utils.rs +++ b/crates/router/tests/connectors/utils.rs @@ -546,6 +546,7 @@ pub trait ConnectorActions: Connector { integrity_check: Ok(()), additional_merchant_data: None, header_payload: None, + connector_mandate_request_reference_id: None, } } @@ -947,6 +948,8 @@ impl Default for PaymentAuthorizeType { charges: None, integrity_object: None, merchant_order_reference_id: None, + additional_payment_method_data: None, + shipping_cost: None, }; Self(data) } diff --git a/crates/router/tests/connectors/wellsfargo.rs b/crates/router/tests/connectors/wellsfargo.rs index 4425c0773772..cab82c59ac85 100644 --- a/crates/router/tests/connectors/wellsfargo.rs +++ b/crates/router/tests/connectors/wellsfargo.rs @@ -11,7 +11,7 @@ impl utils::Connector for WellsfargoTest { fn get_data(&self) -> api::ConnectorData { use router::connector::Wellsfargo; utils::construct_connector_data_old( - Box::new(&Wellsfargo), + Box::new(Wellsfargo::new()), types::Connector::Wellsfargo, api::GetToken::Connector, None, diff --git a/crates/router/tests/connectors/zen.rs b/crates/router/tests/connectors/zen.rs index 20948a90c6d3..da83bdc7d415 100644 --- a/crates/router/tests/connectors/zen.rs +++ b/crates/router/tests/connectors/zen.rs @@ -325,7 +325,7 @@ async fn should_fail_payment_for_incorrect_card_number() { order_details: Some(vec![OrderDetailsWithAmount { product_name: "test".to_string(), quantity: 1, - amount: 1000, + amount: MinorUnit::new(1000), product_img_link: None, requires_shipping: None, product_id: None, @@ -368,7 +368,7 @@ async fn should_fail_payment_for_incorrect_cvc() { order_details: Some(vec![OrderDetailsWithAmount { product_name: "test".to_string(), quantity: 1, - amount: 1000, + amount: MinorUnit::new(1000), product_img_link: None, requires_shipping: None, product_id: None, @@ -411,7 +411,7 @@ async fn should_fail_payment_for_invalid_exp_month() { order_details: Some(vec![OrderDetailsWithAmount { product_name: "test".to_string(), quantity: 1, - amount: 1000, + amount: MinorUnit::new(1000), product_img_link: None, requires_shipping: None, product_id: None, @@ -454,7 +454,7 @@ async fn should_fail_payment_for_incorrect_expiry_year() { order_details: Some(vec![OrderDetailsWithAmount { product_name: "test".to_string(), quantity: 1, - amount: 1000, + amount: MinorUnit::new(1000), product_img_link: None, requires_shipping: None, product_id: None, diff --git a/crates/router/tests/payments.rs b/crates/router/tests/payments.rs index 2638792e10c6..df4340a353e7 100644 --- a/crates/router/tests/payments.rs +++ b/crates/router/tests/payments.rs @@ -468,7 +468,7 @@ async fn payments_create_core() { services::AuthFlow::Merchant, payments::CallConnectorAction::Trigger, None, - api::HeaderPayload::default(), + hyperswitch_domain_models::payments::HeaderPayload::default(), )) .await .unwrap(); @@ -727,7 +727,7 @@ async fn payments_create_core_adyen_no_redirect() { services::AuthFlow::Merchant, payments::CallConnectorAction::Trigger, None, - api::HeaderPayload::default(), + hyperswitch_domain_models::payments::HeaderPayload::default(), )) .await .unwrap(); diff --git a/crates/router/tests/payments2.rs b/crates/router/tests/payments2.rs index 07764606d141..b5962d454fa1 100644 --- a/crates/router/tests/payments2.rs +++ b/crates/router/tests/payments2.rs @@ -230,7 +230,7 @@ async fn payments_create_core() { services::AuthFlow::Merchant, payments::CallConnectorAction::Trigger, None, - api::HeaderPayload::default(), + hyperswitch_domain_models::payments::HeaderPayload::default(), )) .await .unwrap(); @@ -497,7 +497,7 @@ async fn payments_create_core_adyen_no_redirect() { services::AuthFlow::Merchant, payments::CallConnectorAction::Trigger, None, - api::HeaderPayload::default(), + hyperswitch_domain_models::payments::HeaderPayload::default(), )) .await .unwrap(); diff --git a/crates/router_derive/src/lib.rs b/crates/router_derive/src/lib.rs index 02179934e384..33edd5e215e0 100644 --- a/crates/router_derive/src/lib.rs +++ b/crates/router_derive/src/lib.rs @@ -644,6 +644,7 @@ pub fn try_get_enum_variant(input: proc_macro::TokenStream) -> proc_macro::Token /// ("address.zip", "941222"), /// ("email", "test@example.com"), /// ] +/// #[proc_macro_derive(FlatStruct)] pub fn flat_struct_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = parse_macro_input!(input as syn::DeriveInput); @@ -694,3 +695,73 @@ pub fn flat_struct_derive(input: proc_macro::TokenStream) -> proc_macro::TokenSt proc_macro::TokenStream::from(expanded) } + +/// Generates the permissions enum and implematations for the permissions +/// +/// **NOTE:** You have to make sure that all the identifiers used +/// in the macro input are present in the respective enums as well. +/// +/// ## Usage +/// ``` +/// use router_derive::generate_permissions; +/// +/// enum Scope { +/// Read, +/// Write, +/// } +/// +/// enum EntityType { +/// Profile, +/// Merchant, +/// Org, +/// } +/// +/// enum Resource { +/// Payments, +/// Refunds, +/// } +/// +/// generate_permissions! { +/// permissions: [ +/// Payments: { +/// scopes: [Read, Write], +/// entities: [Profile, Merchant, Org] +/// }, +/// Refunds: { +/// scopes: [Read], +/// entities: [Profile, Org] +/// } +/// ] +/// } +/// ``` +/// This will generate the following enum. +/// ``` +/// enum Permission { +/// ProfilePaymentsRead, +/// ProfilePaymentsWrite, +/// MerchantPaymentsRead, +/// MerchantPaymentsWrite, +/// OrgPaymentsRead, +/// OrgPaymentsWrite, +/// ProfileRefundsRead, +/// OrgRefundsRead, +/// ``` +#[proc_macro] +pub fn generate_permissions(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + macros::generate_permissions_inner(input) +} + +/// Generates the ToEncryptable trait for a type +/// +/// This macro generates the temporary structs which has the fields that needs to be encrypted +/// +/// fn to_encryptable: Convert the temp struct to a hashmap that can be sent over the network +/// fn from_encryptable: Convert the hashmap back to temp struct +#[proc_macro_derive(ToEncryption, attributes(encrypt))] +pub fn derive_to_encryption_attr(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input = syn::parse_macro_input!(input as syn::DeriveInput); + + macros::derive_to_encryption(input) + .unwrap_or_else(|err| err.into_compile_error()) + .into() +} diff --git a/crates/router_derive/src/macros.rs b/crates/router_derive/src/macros.rs index 9a8e514c5c11..e227c6533e9b 100644 --- a/crates/router_derive/src/macros.rs +++ b/crates/router_derive/src/macros.rs @@ -1,8 +1,10 @@ pub(crate) mod api_error; pub(crate) mod diesel; +pub(crate) mod generate_permissions; pub(crate) mod generate_schema; pub(crate) mod misc; pub(crate) mod operation; +pub(crate) mod to_encryptable; pub(crate) mod try_get_enum; mod helpers; @@ -14,7 +16,9 @@ use syn::DeriveInput; pub(crate) use self::{ api_error::api_error_derive_inner, diesel::{diesel_enum_derive_inner, diesel_enum_text_derive_inner}, + generate_permissions::generate_permissions_inner, generate_schema::polymorphic_macro_derive_inner, + to_encryptable::derive_to_encryption, }; pub(crate) fn debug_as_display_inner(ast: &DeriveInput) -> syn::Result { diff --git a/crates/router_derive/src/macros/generate_permissions.rs b/crates/router_derive/src/macros/generate_permissions.rs new file mode 100644 index 000000000000..9b388f102cb6 --- /dev/null +++ b/crates/router_derive/src/macros/generate_permissions.rs @@ -0,0 +1,135 @@ +use proc_macro::TokenStream; +use quote::{format_ident, quote}; +use syn::{ + braced, bracketed, + parse::{Parse, ParseBuffer, ParseStream}, + parse_macro_input, + punctuated::Punctuated, + token::Comma, + Ident, Token, +}; + +struct ResourceInput { + resource_name: Ident, + scopes: Punctuated, + entities: Punctuated, +} + +struct Input { + permissions: Punctuated, +} + +impl Parse for Input { + fn parse(input: ParseStream<'_>) -> syn::Result { + let (_permission_label, permissions) = parse_label_with_punctuated_data(input)?; + + Ok(Self { permissions }) + } +} + +impl Parse for ResourceInput { + fn parse(input: ParseStream<'_>) -> syn::Result { + let resource_name: Ident = input.parse()?; + input.parse::()?; // Expect ':' + + let content; + braced!(content in input); + + let (_scopes_label, scopes) = parse_label_with_punctuated_data(&content)?; + content.parse::()?; + + let (_entities_label, entities) = parse_label_with_punctuated_data(&content)?; + + Ok(Self { + resource_name, + scopes, + entities, + }) + } +} + +fn parse_label_with_punctuated_data( + input: &ParseBuffer<'_>, +) -> syn::Result<(Ident, Punctuated)> { + let label: Ident = input.parse()?; + input.parse::()?; // Expect ':' + + let content; + bracketed!(content in input); // Parse the list inside [] + let data = Punctuated::::parse_terminated(&content)?; + + Ok((label, data)) +} + +pub fn generate_permissions_inner(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as Input); + + let res = input.permissions.iter(); + + let mut enum_keys = Vec::new(); + let mut scope_impl_per = Vec::new(); + let mut entity_impl_per = Vec::new(); + let mut resource_impl_per = Vec::new(); + + let mut entity_impl_res = Vec::new(); + + for per in res { + let resource_name = &per.resource_name; + let mut permissions = Vec::new(); + + for scope in per.scopes.iter() { + for entity in per.entities.iter() { + let key = format_ident!("{}{}{}", entity, per.resource_name, scope); + + enum_keys.push(quote! { #key }); + scope_impl_per.push(quote! { Permission::#key => PermissionScope::#scope }); + entity_impl_per.push(quote! { Permission::#key => EntityType::#entity }); + resource_impl_per.push(quote! { Permission::#key => Resource::#resource_name }); + permissions.push(quote! { Permission::#key }); + } + let entities_iter = per.entities.iter(); + entity_impl_res + .push(quote! { Resource::#resource_name => vec![#(EntityType::#entities_iter),*] }); + } + } + + let expanded = quote! { + #[derive( + Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, serde::Serialize, serde::Deserialize, strum::Display + )] + pub enum Permission { + #(#enum_keys),* + } + + impl Permission { + pub fn scope(&self) -> PermissionScope { + match self { + #(#scope_impl_per),* + } + } + pub fn entity_type(&self) -> EntityType { + match self { + #(#entity_impl_per),* + } + } + pub fn resource(&self) -> Resource { + match self { + #(#resource_impl_per),* + } + } + } + + pub trait ResourceExt { + fn entities(&self) -> Vec; + } + + impl ResourceExt for Resource { + fn entities(&self) -> Vec { + match self { + #(#entity_impl_res),* + } + } + } + }; + expanded.into() +} diff --git a/crates/router_derive/src/macros/to_encryptable.rs b/crates/router_derive/src/macros/to_encryptable.rs new file mode 100644 index 000000000000..dfcfb72169b3 --- /dev/null +++ b/crates/router_derive/src/macros/to_encryptable.rs @@ -0,0 +1,326 @@ +use std::iter::Iterator; + +use quote::{format_ident, quote}; +use syn::{parse::Parse, punctuated::Punctuated, token::Comma, Field, Ident, Type as SynType}; + +use crate::macros::{helpers::get_struct_fields, misc::get_field_type}; + +pub struct FieldMeta { + _meta_type: Ident, + pub value: Ident, +} + +impl Parse for FieldMeta { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + let _meta_type: Ident = input.parse()?; + input.parse::()?; + let value: Ident = input.parse()?; + Ok(Self { _meta_type, value }) + } +} + +impl quote::ToTokens for FieldMeta { + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + self.value.to_tokens(tokens); + } +} + +fn get_encryption_ty_meta(field: &Field) -> Option { + let attrs = &field.attrs; + + attrs + .iter() + .flat_map(|s| s.parse_args::()) + .find(|s| s._meta_type.eq("ty")) +} + +fn get_inner_type(path: &syn::TypePath) -> syn::Result { + path.path + .segments + .last() + .and_then(|segment| match &segment.arguments { + syn::PathArguments::AngleBracketed(args) => args.args.first(), + _ => None, + }) + .and_then(|arg| match arg { + syn::GenericArgument::Type(SynType::Path(path)) => Some(path.clone()), + _ => None, + }) + .ok_or_else(|| { + syn::Error::new( + proc_macro2::Span::call_site(), + "Only path fields are supported", + ) + }) +} + +/// This function returns the inner most type recursively +/// For example: +/// +/// In the case of `Encryptable>> this returns String +fn get_inner_most_type(ty: SynType) -> syn::Result { + fn get_inner_type_recursive(path: syn::TypePath) -> syn::Result { + match get_inner_type(&path) { + Ok(inner_path) => get_inner_type_recursive(inner_path), + Err(_) => Ok(path), + } + } + + match ty { + SynType::Path(path) => { + let inner_path = get_inner_type_recursive(path)?; + inner_path + .path + .segments + .last() + .map(|last_segment| last_segment.ident.to_owned()) + .ok_or_else(|| { + syn::Error::new( + proc_macro2::Span::call_site(), + "At least one ident must be specified", + ) + }) + } + _ => Err(syn::Error::new( + proc_macro2::Span::call_site(), + "Only path fields are supported", + )), + } +} + +/// This returns the field which implement #[encrypt] attribute +fn get_encryptable_fields(fields: Punctuated) -> Vec { + fields + .into_iter() + .filter(|field| { + field + .attrs + .iter() + .any(|attr| attr.path().is_ident("encrypt")) + }) + .collect() +} + +/// This function returns the inner most type of a field +fn get_field_and_inner_types(fields: &[Field]) -> Vec<(Field, Ident)> { + fields + .iter() + .flat_map(|field| { + get_inner_most_type(field.ty.clone()).map(|field_name| (field.to_owned(), field_name)) + }) + .collect() +} + +/// The type of the struct for which the batch encryption/decryption needs to be implemented +#[derive(PartialEq, Copy, Clone)] +enum StructType { + Encrypted, + Decrypted, + DecryptedUpdate, + FromRequest, + Updated, +} + +impl StructType { + /// Generates the fields for temporary structs which consists of the fields that should be + /// encrypted/decrypted + fn generate_struct_fields(&self, fields: &[(Field, Ident)]) -> Vec { + fields + .iter() + .map(|(field, inner_ty)| { + let provided_ty = get_encryption_ty_meta(field); + let is_option = get_field_type(field.ty.clone()) + .map(|f| f.eq("Option")) + .unwrap_or_default(); + let ident = &field.ident; + let inner_ty = if let Some(ref ty) = provided_ty { + &ty.value + } else { + inner_ty + }; + match (self, is_option) { + (Self::Encrypted, true) => quote! { pub #ident: Option }, + (Self::Encrypted, false) => quote! { pub #ident: Encryption }, + (Self::Decrypted, true) => { + quote! { pub #ident: Option>> } + } + (Self::Decrypted, false) => { + quote! { pub #ident: Encryptable> } + } + (Self::DecryptedUpdate, _) => { + quote! { pub #ident: Option>> } + } + (Self::FromRequest, true) => { + quote! { pub #ident: Option> } + } + (Self::FromRequest, false) => quote! { pub #ident: Secret<#inner_ty> }, + (Self::Updated, _) => quote! { pub #ident: Option> }, + } + }) + .collect() + } + + /// Generates the ToEncryptable trait implementation + fn generate_impls( + &self, + gen1: proc_macro2::TokenStream, + gen2: proc_macro2::TokenStream, + gen3: proc_macro2::TokenStream, + impl_st: proc_macro2::TokenStream, + inner: &[Field], + ) -> proc_macro2::TokenStream { + let map_length = inner.len(); + + let to_encryptable_impl = inner.iter().flat_map(|field| { + get_field_type(field.ty.clone()).map(|field_ty| { + let is_option = field_ty.eq("Option"); + let field_ident = &field.ident; + let field_ident_string = field_ident.as_ref().map(|s| s.to_string()); + + if is_option || *self == Self::Updated { + quote! { self.#field_ident.map(|s| map.insert(#field_ident_string.to_string(), s)) } + } else { + quote! { map.insert(#field_ident_string.to_string(), self.#field_ident) } + } + }) + }); + + let from_encryptable_impl = inner.iter().flat_map(|field| { + get_field_type(field.ty.clone()).map(|field_ty| { + let is_option = field_ty.eq("Option"); + let field_ident = &field.ident; + let field_ident_string = field_ident.as_ref().map(|s| s.to_string()); + + if is_option || *self == Self::Updated { + quote! { #field_ident: map.remove(#field_ident_string) } + } else { + quote! { + #field_ident: map.remove(#field_ident_string).ok_or( + error_stack::report!(common_utils::errors::ParsingError::EncodeError( + "Unable to convert from HashMap", + )) + )? + } + } + }) + }); + + quote! { + impl ToEncryptable<#gen1, #gen2, #gen3> for #impl_st { + fn to_encryptable(self) -> FxHashMap { + let mut map = FxHashMap::with_capacity_and_hasher(#map_length, Default::default()); + #(#to_encryptable_impl;)* + map + } + + fn from_encryptable( + mut map: FxHashMap>, + ) -> CustomResult<#gen1, common_utils::errors::ParsingError> { + Ok(#gen1 { + #(#from_encryptable_impl,)* + }) + } + } + } + } +} + +/// This function generates the temporary struct and ToEncryptable impls for the temporary structs +fn generate_to_encryptable( + struct_name: Ident, + fields: Vec, +) -> syn::Result { + let struct_types = [ + // The first two are to be used as return types we do not need to implement ToEncryptable + // on it + ("Decrypted", StructType::Decrypted), + ("DecryptedUpdate", StructType::DecryptedUpdate), + ("FromRequestEncryptable", StructType::FromRequest), + ("Encrypted", StructType::Encrypted), + ("UpdateEncryptable", StructType::Updated), + ]; + + let inner_types = get_field_and_inner_types(&fields); + + let inner_type = inner_types.first().map(|(_, ty)| ty).ok_or_else(|| { + syn::Error::new( + proc_macro2::Span::call_site(), + "Please use the macro with attribute #[encrypt] on the fields you want to encrypt", + ) + })?; + + let structs = struct_types.iter().map(|(prefix, struct_type)| { + let name = format_ident!("{}{}", prefix, struct_name); + let temp_fields = struct_type.generate_struct_fields(&inner_types); + quote! { + pub struct #name { + #(#temp_fields,)* + } + } + }); + + // These implementations shouldn't be implemented Decrypted and DecryptedUpdate temp structs + // So skip the first two entries in the list + let impls = struct_types + .iter() + .skip(2) + .map(|(prefix, struct_type)| { + let name = format_ident!("{}{}", prefix, struct_name); + + let impl_block = if *struct_type != StructType::DecryptedUpdate + || *struct_type != StructType::Decrypted + { + let (gen1, gen2, gen3) = match struct_type { + StructType::FromRequest => { + let decrypted_name = format_ident!("Decrypted{}", struct_name); + ( + quote! { #decrypted_name }, + quote! { Secret<#inner_type> }, + quote! { Secret<#inner_type> }, + ) + } + StructType::Encrypted => { + let decrypted_name = format_ident!("Decrypted{}", struct_name); + ( + quote! { #decrypted_name }, + quote! { Secret<#inner_type> }, + quote! { Encryption }, + ) + } + StructType::Updated => { + let decrypted_update_name = format_ident!("DecryptedUpdate{}", struct_name); + ( + quote! { #decrypted_update_name }, + quote! { Secret<#inner_type> }, + quote! { Secret<#inner_type> }, + ) + } + //Unreachable statement + _ => (quote! {}, quote! {}, quote! {}), + }; + + struct_type.generate_impls(gen1, gen2, gen3, quote! { #name }, &fields) + } else { + quote! {} + }; + + Ok(quote! { + #impl_block + }) + }) + .collect::>>()?; + + Ok(quote! { + #(#structs)* + #(#impls)* + }) +} + +pub fn derive_to_encryption( + input: syn::DeriveInput, +) -> Result { + let struct_name = input.ident; + let fields = get_encryptable_fields(get_struct_fields(input.data)?); + + generate_to_encryptable(struct_name, fields) +} diff --git a/crates/router_env/src/logger/types.rs b/crates/router_env/src/logger/types.rs index 8000aa37ec92..2410be9750cb 100644 --- a/crates/router_env/src/logger/types.rs +++ b/crates/router_env/src/logger/types.rs @@ -171,6 +171,8 @@ pub enum Flow { PaymentsAggregate, /// Payments Create Intent flow PaymentsCreateIntent, + /// Payments Get Intent flow + PaymentsGetIntent, #[cfg(feature = "payouts")] /// Payouts create flow PayoutsCreate, @@ -374,6 +376,8 @@ pub enum Flow { GetAuthorizationInfo, /// Get Roles info GetRolesInfo, + /// Get Parent Group Info + GetParentGroupInfo, /// List roles v2 ListRolesV2, /// List invitable roles at entity level @@ -382,8 +386,12 @@ pub enum Flow { ListUpdatableRolesAtEntityLevel, /// Get role GetRole, + /// Get parent info for role + GetRoleV2, /// Get role from token GetRoleFromToken, + /// Get resources and groups for role from token + GetRoleFromTokenV2, /// Update user role UpdateUserRole, /// Create merchant account for user in a org @@ -500,6 +508,8 @@ pub enum Flow { PaymentsManualUpdate, /// Dynamic Tax Calcultion SessionUpdateTaxCalculation, + /// Payments confirm intent + PaymentsConfirmIntent, /// Payments post session tokens flow PaymentsPostSessionTokens, } diff --git a/crates/scheduler/Cargo.toml b/crates/scheduler/Cargo.toml index 0ffd97c2f0eb..24e8c63f9557 100644 --- a/crates/scheduler/Cargo.toml +++ b/crates/scheduler/Cargo.toml @@ -10,7 +10,7 @@ default = ["kv_store", "olap"] olap = ["storage_impl/olap", "hyperswitch_domain_models/olap"] kv_store = [] email = ["external_services/email"] -v1 = ["diesel_models/v1", "hyperswitch_domain_models/v1", "storage_impl/v1"] +v1 = ["diesel_models/v1", "hyperswitch_domain_models/v1", "storage_impl/v1", "common_utils/v1"] [dependencies] # Third party crates diff --git a/crates/storage_impl/Cargo.toml b/crates/storage_impl/Cargo.toml index 0a84d5b25fe0..ac3598cea58a 100644 --- a/crates/storage_impl/Cargo.toml +++ b/crates/storage_impl/Cargo.toml @@ -13,8 +13,8 @@ dynamic_routing = [] oltp = [] olap = ["hyperswitch_domain_models/olap"] payouts = ["hyperswitch_domain_models/payouts"] -v1 = ["api_models/v1", "diesel_models/v1", "hyperswitch_domain_models/v1"] -v2 = ["api_models/v2", "diesel_models/v2", "hyperswitch_domain_models/v2"] +v1 = ["api_models/v1", "diesel_models/v1", "hyperswitch_domain_models/v1", "common_utils/v1"] +v2 = ["api_models/v2", "diesel_models/v2", "hyperswitch_domain_models/v2", "common_utils/v2"] customer_v2 = ["api_models/customer_v2", "diesel_models/customer_v2", "hyperswitch_domain_models/customer_v2"] payment_methods_v2 = ["diesel_models/payment_methods_v2", "api_models/payment_methods_v2", "hyperswitch_domain_models/payment_methods_v2"] diff --git a/crates/storage_impl/src/lookup.rs b/crates/storage_impl/src/lookup.rs index 54377e452673..eec85e267b99 100644 --- a/crates/storage_impl/src/lookup.rs +++ b/crates/storage_impl/src/lookup.rs @@ -93,7 +93,7 @@ impl ReverseLookupInterface for KVRouterStore { }; let redis_entry = kv::TypedSql { op: kv::DBOperation::Insert { - insertable: kv::Insertable::ReverseLookUp(new), + insertable: Box::new(kv::Insertable::ReverseLookUp(new)), }, }; diff --git a/crates/storage_impl/src/mock_db/payment_attempt.rs b/crates/storage_impl/src/mock_db/payment_attempt.rs index 121397cdfb9f..8adeb7006425 100644 --- a/crates/storage_impl/src/mock_db/payment_attempt.rs +++ b/crates/storage_impl/src/mock_db/payment_attempt.rs @@ -52,6 +52,7 @@ impl PaymentAttemptInterface for MockDb { _payment_method_type: Option>, _authentication_type: Option>, _merchanat_connector_id: Option>, + _card_network: Option>, _storage_scheme: storage_enums::MerchantStorageScheme, ) -> CustomResult { Err(StorageError::MockDbError)? @@ -225,7 +226,7 @@ impl PaymentAttemptInterface for MockDb { } #[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, diff --git a/crates/storage_impl/src/payments/payment_attempt.rs b/crates/storage_impl/src/payments/payment_attempt.rs index 5087e28b8542..899ba08244b3 100644 --- a/crates/storage_impl/src/payments/payment_attempt.rs +++ b/crates/storage_impl/src/payments/payment_attempt.rs @@ -17,6 +17,8 @@ use diesel_models::{ reverse_lookup::{ReverseLookup, ReverseLookupNew}, }; use error_stack::ResultExt; +#[cfg(feature = "v1")] +use hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptNew; #[cfg(feature = "v2")] use hyperswitch_domain_models::{ behaviour::{Conversion, ReverseConversion}, @@ -25,9 +27,7 @@ use hyperswitch_domain_models::{ use hyperswitch_domain_models::{ errors, mandates::{MandateAmountData, MandateDataType, MandateDetails}, - payments::payment_attempt::{ - PaymentAttempt, PaymentAttemptInterface, PaymentAttemptNew, PaymentAttemptUpdate, - }, + payments::payment_attempt::{PaymentAttempt, PaymentAttemptInterface, PaymentAttemptUpdate}, }; #[cfg(feature = "olap")] use hyperswitch_domain_models::{ @@ -116,7 +116,7 @@ impl PaymentAttemptInterface for RouterStore { #[cfg(feature = "v2")] #[instrument(skip_all)] - async fn update_payment_attempt_with_attempt_id( + async fn update_payment_attempt( &self, key_manager_state: &KeyManagerState, merchant_key_store: &MerchantKeyStore, @@ -406,6 +406,7 @@ impl PaymentAttemptInterface for RouterStore { payment_method_type: Option>, authentication_type: Option>, merchant_connector_id: Option>, + card_network: Option>, _storage_scheme: MerchantStorageScheme, ) -> CustomResult { let conn = self @@ -429,6 +430,7 @@ impl PaymentAttemptInterface for RouterStore { payment_method_type, authentication_type, merchant_connector_id, + card_network, ) .await .map_err(|er| { @@ -538,9 +540,9 @@ impl PaymentAttemptInterface for KVRouterStore { let redis_entry = kv::TypedSql { op: kv::DBOperation::Insert { - insertable: kv::Insertable::PaymentAttempt( + insertable: Box::new(kv::Insertable::PaymentAttempt(Box::new( payment_attempt.to_storage_model(), - ), + ))), }, }; @@ -645,12 +647,12 @@ impl PaymentAttemptInterface for KVRouterStore { let redis_entry = kv::TypedSql { op: kv::DBOperation::Update { - updatable: kv::Updateable::PaymentAttemptUpdate( + updatable: Box::new(kv::Updateable::PaymentAttemptUpdate(Box::new( kv::PaymentAttemptUpdateMems { orig: this.clone().to_storage_model(), update_data: payment_attempt.to_storage_model(), }, - ), + ))), }, }; @@ -730,7 +732,7 @@ impl PaymentAttemptInterface for KVRouterStore { #[cfg(feature = "v2")] #[instrument(skip_all)] - async fn update_payment_attempt_with_attempt_id( + async fn update_payment_attempt( &self, key_manager_state: &KeyManagerState, merchant_key_store: &MerchantKeyStore, @@ -740,7 +742,7 @@ impl PaymentAttemptInterface for KVRouterStore { ) -> error_stack::Result { // Ignoring storage scheme for v2 implementation self.router_store - .update_payment_attempt_with_attempt_id( + .update_payment_attempt( key_manager_state, merchant_key_store, this, @@ -1291,6 +1293,7 @@ impl PaymentAttemptInterface for KVRouterStore { payment_method_type: Option>, authentication_type: Option>, merchant_connector_id: Option>, + card_network: Option>, storage_scheme: MerchantStorageScheme, ) -> CustomResult { self.router_store @@ -1302,6 +1305,7 @@ impl PaymentAttemptInterface for KVRouterStore { payment_method_type, authentication_type, merchant_connector_id, + card_network, storage_scheme, ) .await diff --git a/crates/storage_impl/src/payments/payment_intent.rs b/crates/storage_impl/src/payments/payment_intent.rs index 8ca63e790371..3fcd30f1e890 100644 --- a/crates/storage_impl/src/payments/payment_intent.rs +++ b/crates/storage_impl/src/payments/payment_intent.rs @@ -103,7 +103,9 @@ impl PaymentIntentInterface for KVRouterStore { let redis_entry = kv::TypedSql { op: kv::DBOperation::Insert { - insertable: kv::Insertable::PaymentIntent(new_payment_intent), + insertable: Box::new(kv::Insertable::PaymentIntent(Box::new( + new_payment_intent, + ))), }, }; @@ -219,12 +221,12 @@ impl PaymentIntentInterface for KVRouterStore { let redis_entry = kv::TypedSql { op: kv::DBOperation::Update { - updatable: kv::Updateable::PaymentIntentUpdate( + updatable: Box::new(kv::Updateable::PaymentIntentUpdate(Box::new( kv::PaymentIntentUpdateMems { orig: origin_diesel_intent, update_data: diesel_intent_update, }, - ), + ))), }, }; diff --git a/crates/storage_impl/src/payouts/payout_attempt.rs b/crates/storage_impl/src/payouts/payout_attempt.rs index 81d06a1cbd5f..3ac66a2c3012 100644 --- a/crates/storage_impl/src/payouts/payout_attempt.rs +++ b/crates/storage_impl/src/payouts/payout_attempt.rs @@ -93,9 +93,9 @@ impl PayoutAttemptInterface for KVRouterStore { let redis_entry = kv::TypedSql { op: kv::DBOperation::Insert { - insertable: kv::Insertable::PayoutAttempt( + insertable: Box::new(kv::Insertable::PayoutAttempt( new_payout_attempt.to_storage_model(), - ), + )), }, }; @@ -182,12 +182,12 @@ impl PayoutAttemptInterface for KVRouterStore { let redis_entry = kv::TypedSql { op: kv::DBOperation::Update { - updatable: kv::Updateable::PayoutAttemptUpdate( + updatable: Box::new(kv::Updateable::PayoutAttemptUpdate( kv::PayoutAttemptUpdateMems { orig: origin_diesel_payout, update_data: diesel_payout_update, }, - ), + )), }, }; diff --git a/crates/storage_impl/src/payouts/payouts.rs b/crates/storage_impl/src/payouts/payouts.rs index 9a94743da3f1..2f6540732fd6 100644 --- a/crates/storage_impl/src/payouts/payouts.rs +++ b/crates/storage_impl/src/payouts/payouts.rs @@ -130,7 +130,7 @@ impl PayoutsInterface for KVRouterStore { let redis_entry = kv::TypedSql { op: kv::DBOperation::Insert { - insertable: kv::Insertable::Payouts(new.to_storage_model()), + insertable: Box::new(kv::Insertable::Payouts(new.to_storage_model())), }, }; @@ -201,10 +201,10 @@ impl PayoutsInterface for KVRouterStore { let redis_entry = kv::TypedSql { op: kv::DBOperation::Update { - updatable: kv::Updateable::PayoutsUpdate(kv::PayoutsUpdateMems { + updatable: Box::new(kv::Updateable::PayoutsUpdate(kv::PayoutsUpdateMems { orig: origin_diesel_payout, update_data: diesel_payout_update, - }), + })), }, }; diff --git a/crates/test_utils/src/connector_auth.rs b/crates/test_utils/src/connector_auth.rs index c71db4472c14..7508c76048c8 100644 --- a/crates/test_utils/src/connector_auth.rs +++ b/crates/test_utils/src/connector_auth.rs @@ -37,6 +37,7 @@ pub struct ConnectorAuthentication { #[cfg(feature = "dummy_connector")] pub dummyconnector: Option, pub ebanx: Option, + pub elavon: Option, pub fiserv: Option, pub fiservemea: Option, pub fiuu: Option, @@ -48,6 +49,7 @@ pub struct ConnectorAuthentication { pub helcim: Option, pub iatapay: Option, pub itaubank: Option, + pub jpmorgan: Option, pub mifinity: Option, pub mollie: Option, pub multisafepay: Option, diff --git a/cypress-tests-v2/cypress/fixtures/merchant_account.json b/cypress-tests-v2/cypress/fixtures/merchant_account.json index ac24e9565138..dbe88ae10d47 100644 --- a/cypress-tests-v2/cypress/fixtures/merchant_account.json +++ b/cypress-tests-v2/cypress/fixtures/merchant_account.json @@ -1,7 +1,6 @@ { "ma_create": { - "merchant_name": "Hyperswitch Seller", - "organization_id": "" + "merchant_name": "Hyperswitch Seller" }, "ma_update": { "merchant_name": "Hyperswitch" diff --git a/cypress-tests-v2/cypress/support/commands.js b/cypress-tests-v2/cypress/support/commands.js index c9d1ef3f24f5..abdf95194bb6 100644 --- a/cypress-tests-v2/cypress/support/commands.js +++ b/cypress-tests-v2/cypress/support/commands.js @@ -173,15 +173,13 @@ Cypress.Commands.add( .replaceAll(" ", "") .toLowerCase(); - // Update request body - merchantAccountCreateBody.organization_id = organization_id; - cy.request({ method: "POST", url: url, headers: { "Content-Type": "application/json", "api-key": api_key, + "X-Organization-Id": organization_id, }, body: merchantAccountCreateBody, failOnStatusCode: false, diff --git a/cypress-tests/README.md b/cypress-tests/README.md new file mode 100644 index 000000000000..0a071aa34a01 --- /dev/null +++ b/cypress-tests/README.md @@ -0,0 +1,334 @@ +# Cypress Tests + +## Overview + +This Tool is a solution designed to automate testing for the [Hyperswitch](https://github.com/juspay/hyperswitch/) using Cypress, an open-source tool capable of conducting API call tests and UI tests. This README provides guidance on installing Cypress and its dependencies. + +## Installation + +### Prerequisites + +Before installing Cypress, ensure that `Node` and `npm` is installed on your machine. To check if it is installed, run the following command: + +```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 + +To run test cases, follow these steps: + +1. Clone the repository and switch to the project directory: + + ```shell + git clone https://github.com/juspay/hyperswitch + cd cypress-tests + ``` + +2. Install Cypress and its dependencies to `cypress-tests` directory by running the following command: + + ```shell + npm ci + ``` + +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" + export CYPRESS_BASEURL="base_url" + export DEBUG=cypress:cli + export CYPRESS_ADMINAPIKEY="admin_api_key" + export CYPRESS_CONNECTOR_AUTH_FILE_PATH="path/to/creds.json" + ``` + +5. Run Cypress test cases + + To run the tests in interactive mode run the following command + + ```shell + npm run cypress + ``` + + To run all the tests in headless mode run the following command + + ```shell + npm run cypress:ci + ``` + + To run payment tests in headless mode run the following command + + ```shell + npm run cypress:payments + ``` + + To run payout tests in headless mode run the following command + + ```shell + npm run cypress:payouts + ``` + + To run routing tests in headless mode run the following command + + ```shell + npm run cypress:routing + ``` + +In order to run cypress tests against multiple connectors at a time or in parallel: + +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. + +## Folder Structure + +The folder structure of this directory is as follows: + +```text +. # The root directory for the Cypress tests. +├── .gitignore +├── cypress # Contains Cypress-related files and folders. +│ ├── e2e # End-to-end test directory. +│ │ ├── ConnectorTest # Directory for test scenarios related to connectors. +│ │ │ ├── your_testcase1_files_here.cy.js +│ │ │ ├── your_testcase2_files_here.cy.js +│ │ │ └── ... +│ │ └── ConnectorUtils # Directory for utility functions related to connectors. +│ │ ├── connector_detail_files_here.js +│ │ └── utils.js +│ ├── fixtures # Directory for storing test data API request. +│ │ └── your_fixture_files_here.json +│ ├── support # Directory for Cypress support files. +│ │ ├── commands.js # File containing custom Cypress commands and utilities. +│ │ └── e2e.js +│ └── utils +│ └── utility_files_go_here.js +├── cypress.config.js # Cypress configuration file. +├── cypress.env.json # File is used to store environment-specific configuration values,such as base URLs, which can be accessed within your Cypress tests. +├── package.json # Node.js package file. +├── readme.md # This file +└── yarn.lock +``` + +## Writing Tests + +### Adding Connectors + +To add a new connector for testing with Hyperswitch, follow these steps: + +1. Include the connector details in the `creds.json` file: + + example: + + ```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). + + Refer to Stripe.js file for guidance: + + ```javascript + /cypress-tests/cypress/e2e/ConnectorUtils/Stripe.js + ``` + + **File Naming:** Create a new file named .js for your specific connector. + + **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 `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: url, + headers: { + "Content-Type": "application/json", + "api-key": api_key, + }, + // set failOnStatusCode to false to prevent Cypress from failing the test + failOnStatusCode: false, + }).then((response) => { + // mandatorliy log the `x-request-id` to the console + logRequestId(response.headers["x-request-id"]); + + expect(response.headers["content-type"]).to.include("application/json"); + + 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); + } + }); +}); +``` + +### Adding Scenarios + +To add new test scenarios: + +1. Navigate to the ConnectorTest directory. +2. Create a new test file or modify existing ones to add your scenarios. +3. Write your test scenarios using Cypress commands. + +For example, to add a scenario for listing mandates in the `Mandateflows`: + +```javascript +// cypress/ConnectorTest/CreateSingleuseMandate.js +describe("Payment Scenarios", () => { + it("should complete a successful payment", () => { + // Your test logic here + }); +}); +``` + +In this scenario, you can call functions defined in `command.js`. For instance, to test the `listMandateCallTest` function: + +```javascript +describe("Payment Scenarios", () => { + it("list-mandate-call-test", () => { + cy.listMandateCallTest(globalState); + }); +}); +``` + +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 + +For more information on using Cypress and writing effective tests, refer to the official Cypress documentation: [Cypress Documentation](https://docs.cypress.io/) + +## Example creds.json + +```json +{ + "adyen": { + "connector_account_details": { + "auth_type": "SignatureKey", + "api_key": "api_key", + "key1": "key1", + "api_secret": "api_secret" + } + }, + "bankofamerica": { + "connector_account_details": { + "auth_type": "SignatureKey", + "api_key": "api_key", + "key1": "key1", + "api_secret": "api_secret" + } + }, + "bluesnap": { + "connector_account_details": { + "auth_type": "BodyKey", + "api_key": "api_key", + "key1": "key1" + } + }, + "cybersource": { + "connector_account_details": { + "auth_type": "SignatureKey", + "api_key": "api_key", + "key1": "key1", + "api_secret": "api_secret" + } + }, + "nmi": { + "connector_account_details": { + "auth_type": "BodyKey", + "api_key": "api_key", + "key1": "key1" + } + }, + "paypal": { + "connector_account_details": { + "auth_type": "BodyKey", + "api_key": "api_key", + "key1": "key1" + } + }, + "stripe": { + "connector_account_details": { + "auth_type": "HeaderKey", + "api_key": "api_key" + } + }, + "trustpay": { + "connector_account_details": { + "auth_type": "SignatureKey", + "api_key": "api_key", + "key1": "key1", + "api_secret": "api_secret" + } + } +} +``` diff --git a/cypress-tests/cypress.config.js b/cypress-tests/cypress.config.js index 8e7eb77fe2a9..ab71597f7fa7 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/cypress/e2e/PaymentTest/00006-VoidPayment.cy.js b/cypress-tests/cypress/e2e/PaymentTest/00006-VoidPayment.cy.js index 9735a74adfd1..c783f5e3d721 100644 --- a/cypress-tests/cypress/e2e/PaymentTest/00006-VoidPayment.cy.js +++ b/cypress-tests/cypress/e2e/PaymentTest/00006-VoidPayment.cy.js @@ -67,7 +67,7 @@ describe("Card - NoThreeDS Manual payment flow test", () => { it("void-call-test", () => { let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ - "Void" + "VoidAfterConfirm" ]; let req_data = data["Request"]; let res_data = data["Response"]; @@ -178,7 +178,7 @@ describe("Card - NoThreeDS Manual payment flow test", () => { it("void-call-test", () => { let data = getConnectorDetails(globalState.get("connectorId"))[ "card_pm" - ]["Void"]; + ]["VoidAfterConfirm"]; let req_data = data["Request"]; let res_data = data["Response"]; cy.voidCallTest(fixtures.voidBody, req_data, res_data, globalState); diff --git a/cypress-tests/cypress/e2e/PaymentTest/00013-SaveCardFlow.cy.js b/cypress-tests/cypress/e2e/PaymentTest/00013-SaveCardFlow.cy.js index 6e9289d4d0b0..e74c8fc9dd47 100644 --- a/cypress-tests/cypress/e2e/PaymentTest/00013-SaveCardFlow.cy.js +++ b/cypress-tests/cypress/e2e/PaymentTest/00013-SaveCardFlow.cy.js @@ -46,8 +46,13 @@ describe("Card - SaveCard payment flow test", () => { "automatic", globalState ); - if (should_continue) - should_continue = utils.should_continue_further(res_data); + if (should_continue) { + // Don't continue if payment status is processing during auto capture + // Payment data is tokenized only after payment is successful + let notProcessing = res_data?.body?.status != "processing"; + should_continue = + notProcessing && utils.should_continue_further(res_data); + } }); it("retrieve-payment-call-test", () => { diff --git a/cypress-tests/cypress/e2e/PaymentTest/00020-Variations.cy.js b/cypress-tests/cypress/e2e/PaymentTest/00020-Variations.cy.js index a00a2e39f959..b24b9f10f791 100644 --- a/cypress-tests/cypress/e2e/PaymentTest/00020-Variations.cy.js +++ b/cypress-tests/cypress/e2e/PaymentTest/00020-Variations.cy.js @@ -331,7 +331,7 @@ describe("Corner cases", () => { }); it("Capture call", () => { - let data = getConnectorDetails(globalState.get("commons"))["card_pm"][ + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ "CaptureCapturedAmount" ]; @@ -396,7 +396,7 @@ describe("Corner cases", () => { }); it("Confirm call", () => { - let data = getConnectorDetails(globalState.get("commons"))["card_pm"][ + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ "ConfirmSuccessfulPayment" ]; let req_data = data["Request"]; @@ -460,12 +460,12 @@ describe("Corner cases", () => { }); it("Void call", () => { - // `commons` here is intentionally used as we need to pass `ResponseCustom` - let data = getConnectorDetails(globalState.get("commons"))["card_pm"][ + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ "Void" ]; + let commonData = getConnectorDetails(globalState.get("commons"))["card_pm"]["Void"]; let req_data = data["Request"]; - let res_data = data["ResponseCustom"]; + let res_data = utils.getConnectorFlowDetails(data, commonData, "ResponseCustom"); cy.voidCallTest(fixtures.voidBody, req_data, res_data, globalState); if (should_continue) @@ -592,12 +592,12 @@ describe("Corner cases", () => { }); it("Refund call", () => { - // `commons` here is intentionally used as we need to pass `ResponseCustom` - let data = getConnectorDetails(globalState.get("commons"))["card_pm"][ + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ "Refund" ]; + let commonData = getConnectorDetails(globalState.get("commons"))["card_pm"]["Refund"]; let req_data = data["Request"]; - let res_data = data["ResponseCustom"]; + let res_data = utils.getConnectorFlowDetails(data, commonData, "ResponseCustom"); cy.refundCallTest( fixtures.refundBody, req_data, @@ -655,12 +655,12 @@ describe("Corner cases", () => { }); it("Refund call", () => { - // `commons` here is intentionally used as we need to pass `ResponseCustom` - let data = getConnectorDetails(globalState.get("commons"))["card_pm"][ + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ "Refund" ]; + let commonData = getConnectorDetails(globalState.get("commons"))["card_pm"]["Refund"]; let req_data = data["Request"]; - let res_data = data["ResponseCustom"]; + let res_data = utils.getConnectorFlowDetails(data, commonData, "ResponseCustom"); cy.refundCallTest( fixtures.refundBody, req_data, diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Commons.js b/cypress-tests/cypress/e2e/PaymentUtils/Commons.js index 73e54fee916f..01905ee05320 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Commons.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Commons.js @@ -666,6 +666,27 @@ export const connectorDetails = { }, }, }), + VoidAfterConfirm: getCustomExchange({ + Request: {}, + Response: { + status: 200, + body: { + status: "cancelled", + capture_method: "manual", + }, + }, + ResponseCustom: { + status: 400, + body: { + error: { + type: "invalid_request", + message: + "You cannot cancel this payment because it has status succeeded", + code: "IR_16", + }, + }, + }, + }), Refund: getCustomExchange({ Request: { payment_method: "card", diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Fiuu.js b/cypress-tests/cypress/e2e/PaymentUtils/Fiuu.js index 86e2314c9279..24a445dd3c25 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Fiuu.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Fiuu.js @@ -13,6 +13,40 @@ const successfulThreeDSTestCardDetails = { card_holder_name: "joseph Doe", card_cvc: "123", }; + +const singleUseMandateData = { + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "125.0.0.1", + user_agent: "amet irure esse", + }, + }, + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, +}; + +const multiUseMandateData = { + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "125.0.0.1", + user_agent: "amet irure esse", + }, + }, + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, +}; export const connectorDetails = { card_pm: { PaymentIntent: { @@ -184,5 +218,346 @@ export const connectorDetails = { }, }, }, + MandateSingleUse3DSAutoCapture: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulThreeDSTestCardDetails, + }, + currency: "USD", + mandate_data: singleUseMandateData, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + MandateSingleUse3DSManualCapture: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulThreeDSTestCardDetails, + }, + currency: "USD", + mandate_data: singleUseMandateData, + }, + Response: { + status: 200, + body: { + status: "requires_customer_action", + }, + }, + }, + MandateSingleUseNo3DSAutoCapture: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + currency: "USD", + mandate_data: singleUseMandateData, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + MandateSingleUseNo3DSManualCapture: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + currency: "USD", + mandate_data: singleUseMandateData, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + MandateMultiUseNo3DSAutoCapture: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + currency: "USD", + mandate_data: multiUseMandateData, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + MandateMultiUseNo3DSManualCapture: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + currency: "USD", + mandate_data: multiUseMandateData, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + MandateMultiUse3DSAutoCapture: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulThreeDSTestCardDetails, + }, + currency: "USD", + mandate_data: multiUseMandateData, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + MandateMultiUse3DSManualCapture: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulThreeDSTestCardDetails, + }, + currency: "USD", + mandate_data: multiUseMandateData, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + PaymentMethodIdMandateNo3DSAutoCapture: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + currency: "USD", + mandate_data: null, + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "125.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + SaveCardUseNo3DSAutoCapture: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + currency: "USD", + setup_future_usage: "on_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + SaveCardUseNo3DSManualCapture: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + currency: "USD", + setup_future_usage: "on_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + SaveCardUseNo3DSAutoCaptureOffSession: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + setup_future_usage: "off_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + SaveCardUseNo3DSManualCaptureOffSession: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + setup_future_usage: "off_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + SaveCardConfirmAutoCaptureOffSession: { + Request: { + setup_future_usage: "off_session", + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + SaveCardConfirmManualCaptureOffSession: { + Request: { + setup_future_usage: "off_session", + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + PaymentMethodIdMandateNo3DSManualCapture: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + currency: "USD", + mandate_data: null, + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "125.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + PaymentMethodIdMandate3DSAutoCapture: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulThreeDSTestCardDetails, + }, + currency: "USD", + mandate_data: null, + authentication_type: "three_ds", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "125.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_customer_action", + }, + }, + }, + PaymentMethodIdMandate3DSManualCapture: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulThreeDSTestCardDetails, + }, + mandate_data: null, + authentication_type: "three_ds", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "125.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_customer_action", + }, + }, + }, }, }; diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Paybox.js b/cypress-tests/cypress/e2e/PaymentUtils/Paybox.js index 8fbb8c0b07b7..b0550854ef87 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Paybox.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Paybox.js @@ -401,29 +401,6 @@ export const connectorDetails = { }, }, }, - CaptureCapturedAmount: { - Request: { - Request: { - payment_method: "card", - payment_method_data: { - card: successfulNo3DSCardDetails, - }, - currency: "EUR", - customer_acceptance: null, - }, - }, - Response: { - status: 400, - body: { - error: { - type: "invalid_request", - message: - "This Payment could not be captured because it has a payment.status of succeeded. The expected state is requires_capture, partially_captured_and_capturable, processing", - code: "IR_14", - }, - }, - }, - }, ConfirmSuccessfulPayment: { Request: { payment_method: "card", diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Utils.js b/cypress-tests/cypress/e2e/PaymentUtils/Utils.js index 18f4df3eb577..8848450bc61e 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Utils.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Utils.js @@ -19,6 +19,7 @@ import { connectorDetails as stripeConnectorDetails } from "./Stripe.js"; import { connectorDetails as trustpayConnectorDetails } from "./Trustpay.js"; import { connectorDetails as wellsfargoConnectorDetails } from "./WellsFargo.js"; import { connectorDetails as fiuuConnectorDetails } from "./Fiuu.js"; +import { connectorDetails as worldpayConnectorDetails } from "./WorldPay.js"; const connectorDetails = { adyen: adyenConnectorDetails, @@ -39,6 +40,7 @@ const connectorDetails = { datatrans: datatransConnectorDetails, wellsfargo: wellsfargoConnectorDetails, fiuu: fiuuConnectorDetails, + worldpay: worldpayConnectorDetails, }; export default function getConnectorDetails(connectorId) { @@ -46,6 +48,11 @@ export default function getConnectorDetails(connectorId) { return x; } +export function getConnectorFlowDetails(connectorData, commonData, key) { + let data = connectorData[key] === undefined ? commonData[key] : connectorData[key]; + return data; +} + function mergeDetails(connectorId) { const connectorData = getValueByKey(connectorDetails, connectorId); const fallbackData = getValueByKey(connectorDetails, "commons"); diff --git a/cypress-tests/cypress/e2e/PaymentUtils/WorldPay.js b/cypress-tests/cypress/e2e/PaymentUtils/WorldPay.js new file mode 100644 index 000000000000..70ed4fefa6c2 --- /dev/null +++ b/cypress-tests/cypress/e2e/PaymentUtils/WorldPay.js @@ -0,0 +1,436 @@ + +const billing = { + address: { + line1: "1467", + line2: "Harrison Street", + line3: "Harrison Street", + city: "San Fransico", + state: "CA", + zip: "94122", + country: "US", + first_name: "John", + last_name: "Doe" + } +}; + +const browser_info = { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36", + "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", + "language": "nl-NL", + "color_depth": 24, + "screen_height": 723, + "screen_width": 1536, + "time_zone": 0, + "java_enabled": true, + "java_script_enabled": true, + "ip_address": "127.0.0.1" +}; + +const successfulNo3DSCardDetails = { + card_number: "4242424242424242", + card_exp_month: "10", + card_exp_year: "2030", + card_holder_name: "morino", + card_cvc: "737", +}; + +const successfulThreeDSTestCardDetails = { + card_number: "4000000000001091", + card_exp_month: "10", + card_exp_year: "2030", + card_holder_name: "morino", + card_cvc: "737", +}; + +const payment_method_data_no3ds = { + card: { + last4: "4242", + card_type: "CREDIT", + card_network: "Visa", + card_issuer: "STRIPE PAYMENTS UK LIMITED", + card_issuing_country: "UNITEDKINGDOM", + card_isin: "424242", + card_extended_bin: null, + card_exp_month: "10", + card_exp_year: "2030", + card_holder_name: null, + payment_checks: null, + authentication_data: null + }, + billing: null +}; + +const payment_method_data_3ds = { + card: { + last4: "1091", + card_type: "CREDIT", + card_network: "Visa", + card_issuer: "INTL HDQTRS-CENTER OWNED", + card_issuing_country: "UNITEDSTATES", + card_isin: "400000", + card_extended_bin: null, + card_exp_month: "10", + card_exp_year: "2030", + card_holder_name: null, + payment_checks: null, + authentication_data: null + }, + billing: null +}; + +const singleUseMandateData = { + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "125.0.0.1", + user_agent: "amet irure esse", + }, + }, + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, +}; + +export const connectorDetails = { + card_pm: { + PaymentIntent: { + Request: { + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, Response: { + status: 200, + body: { + status: "requires_payment_method", + setup_future_usage: "on_session", + }, + }, + }, + No3DSManualCapture: { + Request: { + payment_method: "card", + payment_method_type: "debit", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + billing: billing, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + payment_method: "card", + payment_method_type: "debit", + attempt_count: 1, + payment_method_data: payment_method_data_no3ds, + }, + }, + }, + No3DSAutoCapture: { + Request: { + payment_method: "card", + payment_method_type: "debit", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "processing", + payment_method: "card", + payment_method_type: "debit", + attempt_count: 1, + payment_method_data: payment_method_data_no3ds, + }, + }, + }, + Capture: { + Request: { + payment_method: "card", + payment_method_type: "debit", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "processing", + amount: 6500, + amount_capturable: 6500, + }, + }, + }, + PartialCapture: { + Request: { + payment_method: "card", + payment_method_type: "debit", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "processing", + amount: 6500, + amount_capturable: 6500, + }, + }, + }, + Void: { + Request: {}, + Response: { + status: 200, + body: { + status: "cancelled", + }, + }, + ResponseCustom: { + body: { + type: "invalid_request", + message: "You cannot cancel this payment because it has status processing", + code: "IR_16", + } + } + }, + VoidAfterConfirm: { + Request: {}, + Response: { + status: 200, + body: { + status: "processing", + }, + }, + }, + SaveCardUseNo3DSManualCapture: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + currency: "USD", + setup_future_usage: "on_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Missing required param: payment_method_data", + code: "IR_04" + } + }, + }, + }, + SaveCardUseNo3DSAutoCapture: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + currency: "USD", + setup_future_usage: "on_session", + browser_info, + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "processing" + }, + } + }, + "3DSManualCapture": { + Request: { + payment_method: "card", + payment_method_type: "debit", + payment_method_data: { + card: successfulThreeDSTestCardDetails, + }, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + browser_info, + }, + Response: { + status: 200, + body: { + status: "requires_customer_action", + setup_future_usage: "on_session", + payment_method_data: payment_method_data_3ds, + }, + }, + }, + "3DSAutoCapture": { + Request: { + payment_method: "card", + payment_method_type: "debit", + payment_method_data: { + card: successfulThreeDSTestCardDetails, + }, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + browser_info, + }, + Response: { + status: 200, + body: { + status: "requires_customer_action", + setup_future_usage: "on_session", + payment_method_data: payment_method_data_3ds, + }, + }, + }, + + /** + * Variation cases + */ + CaptureCapturedAmount: { + Request: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + currency: "EUR", + customer_acceptance: null, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: + "This Payment could not be captured because it has a capture_method of automatic. The expected state is manual_multiple", + code: "IR_14", + }, + }, + }, + }, + ConfirmSuccessfulPayment: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: + "You cannot confirm this payment because it has status processing", + code: "IR_16", + }, + }, + }, + }, + + /** + * Not implemented or not ready for running test cases + * - Refunds + * - Mandates + */ + Refund: { + Request: {}, + Response: { + body: { + error: { + type: "invalid_request", + message: "This Payment could not be refund because it has a status of processing. The expected state is succeeded, partially_captured", + code: "IR_14" + } + } + }, + ResponseCustom: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "This Payment could not be refund because it has a status of processing. The expected state is succeeded, partially_captured", + code: "IR_14", + }, + }, + }, + }, + PartialRefund: { + Request: {}, + Response: { + body: { + error: { + type: "invalid_request", + message: "This Payment could not be refund because it has a status of processing. The expected state is succeeded, partially_captured", + code: "IR_14" + } + } + } + }, + SyncRefund: { + Request: {}, + Response: { + body: { + error: { + type: "invalid_request", + message: "Refund does not exist in our records.", + code: "HE_02" + } + } + } + }, + ZeroAuthMandate: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + currency: "USD", + mandate_data: singleUseMandateData, + }, + Response: { + body: { + error: { + type: "invalid_request", + message: "Setup Mandate flow for Worldpay is not implemented", + code: "IR_00" + } + }, + }, + }, + }, +} \ No newline at end of file diff --git a/cypress-tests/cypress/fixtures/create-connector-body.json b/cypress-tests/cypress/fixtures/create-connector-body.json index 5e0ce73aedc8..54a96d8f6ee2 100644 --- a/cypress-tests/cypress/fixtures/create-connector-body.json +++ b/cypress-tests/cypress/fixtures/create-connector-body.json @@ -13,6 +13,7 @@ "metadata": { "city": "NY", "unit": "245", - "endpoint_prefix": "AD" + "endpoint_prefix": "AD", + "merchant_name": "Cypress Test" } } diff --git a/cypress-tests/cypress/support/commands.js b/cypress-tests/cypress/support/commands.js index a6436e7f67c2..9b938e673d77 100644 --- a/cypress-tests/cypress/support/commands.js +++ b/cypress-tests/cypress/support/commands.js @@ -1843,7 +1843,11 @@ Cypress.Commands.add( const nextActionUrl = response.body.next_action.redirect_to_url; cy.log(nextActionUrl); } else if (response.body.authentication_type === "no_three_ds") { - expect(response.body.status).to.equal("succeeded"); + if (response.body.connector === "fiuu") { + expect(response.body.status).to.equal("failed"); + } else { + expect(response.body.status).to.equal("succeeded"); + } } else { throw new Error( `Invalid authentication type ${response.body.authentication_type}` @@ -2446,51 +2450,55 @@ Cypress.Commands.add( } ); -Cypress.Commands.add("updateConfig", (configType, configData, globalState, value) => { - const base_url = globalState.get("baseUrl"); - const merchant_id = globalState.get("merchantId"); - const api_key = globalState.get("adminApiKey"); - - let key; - let url; - let body; - - switch (configType) { - case 'autoRetry': - key = `should_call_gsm_${merchant_id}`; - url = `${base_url}/configs/${key}`; - body = { key: key, value: value }; - break; - case 'maxRetries': - key = `max_auto_retries_enabled_${merchant_id}`; - url = `${base_url}/configs/${key}`; - body = { key: key, value: value }; - break; - case 'stepUp': - key = `step_up_enabled_${merchant_id}`; - url = `${base_url}/configs/${key}`; - body = { key: key, value: value }; - break; - default: - throw new Error(`Invalid config type passed into the configs: "${api_key}: ${value}"`); - } - - cy.request({ - method: 'POST', - url: url, - headers: { - "Content-Type": "application/json", - "api-key": api_key, - }, - body: body, - failOnStatusCode: false, - }).then((response) => { - logRequestId(response.headers["x-request-id"]); - - if (response.status === 200) { - expect(response.body).to.have.property("key").to.equal(key); - expect(response.body).to.have.property("value").to.equal(value); +Cypress.Commands.add( + "updateConfig", + (configType, configData, globalState, value) => { + const base_url = globalState.get("baseUrl"); + const merchant_id = globalState.get("merchantId"); + const api_key = globalState.get("adminApiKey"); + + let key; + let url; + let body; + + switch (configType) { + case "autoRetry": + key = `should_call_gsm_${merchant_id}`; + url = `${base_url}/configs/${key}`; + body = { key: key, value: value }; + break; + case "maxRetries": + key = `max_auto_retries_enabled_${merchant_id}`; + url = `${base_url}/configs/${key}`; + body = { key: key, value: value }; + break; + case "stepUp": + key = `step_up_enabled_${merchant_id}`; + url = `${base_url}/configs/${key}`; + body = { key: key, value: value }; + break; + default: + throw new Error( + `Invalid config type passed into the configs: "${api_key}: ${value}"` + ); } - }); -}); + cy.request({ + method: "POST", + url: url, + headers: { + "Content-Type": "application/json", + "api-key": api_key, + }, + body: body, + failOnStatusCode: false, + }).then((response) => { + logRequestId(response.headers["x-request-id"]); + + if (response.status === 200) { + expect(response.body).to.have.property("key").to.equal(key); + expect(response.body).to.have.property("value").to.equal(value); + } + }); + } +); diff --git a/cypress-tests/cypress/support/redirectionHandler.js b/cypress-tests/cypress/support/redirectionHandler.js index b493d11fee83..aa6db7d50747 100644 --- a/cypress-tests/cypress/support/redirectionHandler.js +++ b/cypress-tests/cypress/support/redirectionHandler.js @@ -343,7 +343,19 @@ function threeDsRedirection(redirection_url, expected_url, connectorId) { cy.get("#outcomeSelect").select("Approve").should("have.value", "Y"); cy.get('button[type="submit"]').click(); }); - } else { + } else if (connectorId === "worldpay") { + cy.get("iframe", { timeout: WAIT_TIME }) + .its("0.contentDocument.body") + .within(() => { + cy.get('form[name="cardholderInput"]', { timeout: WAIT_TIME }) + .should("exist") + .then(() => { + cy.get('input[name="challengeDataEntry"]').click().type("1234"); + cy.get('input[value="SUBMIT"]').click(); + }) + }); + } + else { // If connectorId is neither of adyen, trustpay, nmi, stripe, bankofamerica or cybersource, wait for 10 seconds cy.wait(WAIT_TIME); } diff --git a/cypress-tests/readme.md b/cypress-tests/readme.md deleted file mode 100644 index dccb66ed0e53..000000000000 --- a/cypress-tests/readme.md +++ /dev/null @@ -1,260 +0,0 @@ -# Cypress Tests - -## Overview - -This Tool is a solution designed to automate testing for the [Hyperswitch](https://github.com/juspay/hyperswitch/) using Cypress, an open-source tool capable of conducting API call tests and UI tests. This README provides guidance on installing Cypress and its dependencies. - -## Installation - -### Prerequisites - -Before installing Cypress, ensure you have the following prerequisites installed: - -- npm (Node Package Manager) -- Node.js (18.x and above) - -### Run Test Cases on your local - -To run test cases, follow these steps: - -1. Clone the repository and switch to the project directory: - - ```shell - git clone https://github.com/juspay/hyperswitch - cd cypress-tests - ``` - -2. Install Cypress and its dependencies to `cypress-tests` directory by running the following command: - - ```shell - npm install - ``` - -3. Set environment variables for cypress - - ```shell - export CYPRESS_CONNECTOR="connector_id" - export CYPRESS_BASEURL="base_url" - export DEBUG=cypress:cli - export CYPRESS_ADMINAPIKEY="admin_api_key" - export CYPRESS_CONNECTOR_AUTH_FILE_PATH="path/to/creds.json" - ``` - -4. Run Cypress test cases - - To run the tests in interactive mode run the following command - - ```shell - npm run cypress - ``` - - To run all the tests in headless mode run the following command - - ```shell - npm run cypress:ci - ``` - - To run payment tests in headless mode run the following command - - ```shell - npm run cypress:payments - ``` - - To run payout tests in headless mode run the following command - - ```shell - npm run cypress:payouts - ``` - - To run routing tests in headless mode run the following command - - ```shell - npm run cypress:routing - ``` - -> [!NOTE] -> To learn about how creds file should be structured, refer to the [example.creds.json](#example-credsjson) section below. - -## Folder Structure - -The folder structure of this directory is as follows: - -```text -. # The root directory for the Cypress tests. -├── .gitignore -├── cypress # Contains Cypress-related files and folders. -│ ├── e2e # End-to-end test directory. -│ │ ├── ConnectorTest # Directory for test scenarios related to connectors. -│ │ │ ├── your_testcase1_files_here.cy.js -│ │ │ ├── your_testcase2_files_here.cy.js -│ │ │ └── ... -│ │ └── ConnectorUtils # Directory for utility functions related to connectors. -│ │ ├── connector_detail_files_here.js -│ │ └── utils.js -│ ├── fixtures # Directory for storing test data API request. -│ │ └── your_fixture_files_here.json -│ ├── support # Directory for Cypress support files. -│ │ ├── commands.js # File containing custom Cypress commands and utilities. -│ │ └── e2e.js -│ └── utils -│ └── utility_files_go_here.js -├── cypress.config.js # Cypress configuration file. -├── cypress.env.json # File is used to store environment-specific configuration values,such as base URLs, which can be accessed within your Cypress tests. -├── package.json # Node.js package file. -├── readme.md # This file -└── yarn.lock -``` - -## Writing Tests - -### Adding Connectors - -To add a new connector for testing with Hyperswitch, follow these steps: - -1.Include the connector details in the `creds.json` file: - -example: - -```json -{ - "stripe": { - "auth_type": "HeaderKey", - "api_key": "SK_134" - } -} -``` - -2.Add the new connector details to the ConnectorUtils folder (including CardNo and connector-specific information). - -Refer to Stripe.js file for guidance: - -```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. - -3.In util.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. - -Example: Adding List Mandate function to support `ListMandate` scenario - -```javascript -Cypress.Commands.add("listMandateCallTest", (globalState) => { - const customerId = globalState.get("customerId"); - cy.request({ - method: "GET", - url: `${globalState.get("baseUrl")}/customers/${customerId}/mandates`, - headers: { - "Content-Type": "application/json", - "api-key": globalState.get("apiKey"), - }, - }).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" - ); - } - 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"); - } - } - }); -}); -``` - -### Adding Scenarios - -To add new test scenarios: - -1. Navigate to the ConnectorTest directory. -2. Create a new test file or modify existing ones to add your scenarios. -3. Write your test scenarios using Cypress commands. - -For example, to add a scenario for listing mandates in the `Mandateflows`: - -```javascript -// cypress/ConnectorTest/CreateSingleuseMandate.js -describe("Payment Scenarios", () => { - it("should complete a successful payment", () => { - // Your test logic here - }); -}); -``` - -In this scenario, you can call functions defined in `command.js`. For instance, to test the `listMandateCallTest` function: - -```javascript -describe("Payment Scenarios", () => { - it("list-mandate-call-test", () => { - cy.listMandateCallTest(globalState); - }); -}); -``` - -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. - -## Additional Resources - -For more information on using Cypress and writing effective tests, refer to the official Cypress documentation: [Cypress Documentation](https://docs.cypress.io/) - -## Example creds.json - -```json -{ - "adyen": { - "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" - }, - "bluesnap": { - "auth_type": "BodyKey", - "api_key": "api_key", - "key1": "key1" - }, - "cybersource": { - "auth_type": "SignatureKey", - "api_key": "api_key", - "key1": "key1", - "api_secret": "api_secret" - }, - "nmi": { - "auth_type": "BodyKey", - "api_key": "api_key", - "key1": "key1" - }, - "paypal": { - "auth_type": "BodyKey", - "api_key": "api_key", - "key1": "key1" - }, - "stripe": { - "auth_type": "HeaderKey", - "api_key": "api_key" - }, - "trustpay": { - "auth_type": "SignatureKey", - "api_key": "api_key", - "key1": "key1", - "api_secret": "api_secret" - } -} -``` diff --git a/docker-compose-development.yml b/docker-compose-development.yml index 3878f880b065..07a2131c6d4a 100644 --- a/docker-compose-development.yml +++ b/docker-compose-development.yml @@ -64,6 +64,7 @@ services: FROM rust:latest RUN apt-get update && \ apt-get install -y protobuf-compiler + RUN rustup component add rustfmt clippy command: cargo run --bin router -- -f ./config/docker_compose.toml working_dir: /app ports: diff --git a/docs/try_local_system.md b/docs/try_local_system.md index a9c5e81138c3..07756463e740 100644 --- a/docs/try_local_system.md +++ b/docs/try_local_system.md @@ -15,6 +15,10 @@ Check the Table Of Contents to jump to the relevant section. - [Run hyperswitch using Docker Compose](#run-hyperswitch-using-docker-compose) - [Running additional services](#running-additional-services) - [Set up a development environment using Docker Compose](#set-up-a-development-environment-using-docker-compose) +- [Set up a Nix development environment](#set-up-a-nix-development-environment) + - [Install Nix](#install-nix) + - [Using external services through Nix](#using-external-services-through-nix) + - [Develop in a Nix environment (coming soon)](#develop-in-a-nix-environment-coming-soon) - [Set up a Rust environment and other dependencies](#set-up-a-rust-environment-and-other-dependencies) - [Set up dependencies on Ubuntu-based systems](#set-up-dependencies-on-ubuntu-based-systems) - [Set up dependencies on Windows (Ubuntu on WSL2)](#set-up-dependencies-on-windows-ubuntu-on-wsl2) @@ -166,6 +170,43 @@ Once the services have been confirmed to be up and running, you can proceed with If the command returned a `200 OK` status code, proceed with [trying out our APIs](#try-out-our-apis). +## Set up a Nix development environment + +A Nix development environment simplifies the setup of required project dependencies. This is available for MacOS, Linux and WSL2 users. + +### Install nix + +We recommend that you install Nix using [the DetSys nix-installer][detsys-nixos-installer], which automatically enables flakes. + +As an **optional** next step, if you are interested in using Nix to manage your dotfiles and local packages, you can setup [nixos-unified-template][nixos-unified-template-repo]. + +### Using external services through Nix + +Once Nix is installed, you can use it to manage external services via `flakes`. More services will be added soon. + +- Run below command in hyperswitch directory + + ```shell + nix run .#ext-services + ``` + +This will start the following services using `process-compose` +- PostgreSQL + - Creates database and an user to be used by the application +- Redis + +### Develop in a Nix environment (coming soon) + +Nix development environment ensures all the required project dependencies, including both the tools and services are readily available, eliminating the need for manual setup. + +Run below command in hyperswitch directory + + ```shell + nix develop + ``` + +**NOTE:** This is a work in progress, and only a selected commands are available at the moment. Look in `flake.nix` (hyperswitch-shell) for a full list of packages. + ## Set up a Rust environment and other dependencies If you are using `nix`, please skip the setup dependencies step and jump to @@ -681,3 +722,5 @@ To explore more of our APIs, please check the remaining folders in the [refunds-create]: https://www.postman.com/hyperswitch/workspace/hyperswitch-development/request/25176162-4d1315c6-ac61-4411-8f7d-15d4e4e736a1 [refunds-retrieve]: https://www.postman.com/hyperswitch/workspace/hyperswitch-development/request/25176162-137d6260-24f7-4752-9e69-26b61b83df0d [connector-specific-details]: https://docs.google.com/spreadsheets/d/e/2PACX-1vQWHLza9m5iO4Ol-tEBx22_Nnq8Mb3ISCWI53nrinIGLK8eHYmHGnvXFXUXEut8AFyGyI9DipsYaBLG/pubhtml?gid=748960791&single=true +[detsys-nixos-installer]: https://nixos.asia/en/install +[nixos-unified-template-repo]: https://github.com/juspay/nixos-unified-template#on-non-nixos diff --git a/flake.lock b/flake.lock index 6f9551084751..6bdae435765b 100644 --- a/flake.lock +++ b/flake.lock @@ -107,11 +107,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1676569297, - "narHash": "sha256-2n4C4H3/U+3YbDrQB6xIw7AaLdFISCCFwOkcETAigqU=", + "lastModified": 1728888510, + "narHash": "sha256-nsNdSldaAyu6PE3YUA+YQLqUDJh+gRbBooMMekZJwvI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "ac1f5b72a9e95873d1de0233fddcb56f99884b37", + "rev": "a3c0b3b21515f74fd2665903d4ce6bc4dc81c77c", "type": "github" }, "original": { @@ -137,12 +137,29 @@ "type": "github" } }, + "process-compose-flake": { + "locked": { + "lastModified": 1728868941, + "narHash": "sha256-yEMzxZfy+EE9gSqn++SyZeAVHXYupFT8Wyf99Z/CXXU=", + "owner": "Platonic-Systems", + "repo": "process-compose-flake", + "rev": "29301aec92d73c9b075fcfd06a6fb18665bfe6b5", + "type": "github" + }, + "original": { + "owner": "Platonic-Systems", + "repo": "process-compose-flake", + "type": "github" + } + }, "root": { "inputs": { "cargo2nix": "cargo2nix", "flake-parts": "flake-parts", "nixpkgs": "nixpkgs_2", - "rust-overlay": "rust-overlay_2" + "process-compose-flake": "process-compose-flake", + "rust-overlay": "rust-overlay_2", + "services-flake": "services-flake" } }, "rust-overlay": { @@ -187,6 +204,21 @@ "repo": "rust-overlay", "type": "github" } + }, + "services-flake": { + "locked": { + "lastModified": 1728811751, + "narHash": "sha256-IrwycNtt6jxJGCi+QJ8Bbzt9flg0vNeGLAR0KBbj4a8=", + "owner": "juspay", + "repo": "services-flake", + "rev": "e9f663036f3b1b1a12b0f136628ef93a8be92443", + "type": "github" + }, + "original": { + "owner": "juspay", + "repo": "services-flake", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index ad3de7e660b1..9516d0c81a7a 100644 --- a/flake.nix +++ b/flake.nix @@ -8,10 +8,14 @@ # TODO: Move away from these to https://github.com/juspay/rust-flake cargo2nix.url = "github:cargo2nix/cargo2nix/release-0.11.0"; rust-overlay.url = "github:oxalica/rust-overlay"; + + process-compose-flake.url = "github:Platonic-Systems/process-compose-flake"; + services-flake.url = "github:juspay/services-flake"; }; outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } { + imports = [ inputs.process-compose-flake.flakeModule ]; systems = inputs.nixpkgs.lib.systems.flakeExposed; perSystem = { self', pkgs, lib, system, ... }: let @@ -27,10 +31,10 @@ devShells.default = pkgs.mkShell { name = "hyperswitch-shell"; packages = with pkgs; [ + just + nixd openssl pkg-config - exa - fd rust-bin.stable.${rustVersion}.default ] ++ lib.optionals stdenv.isDarwin [ # arch might have issue finding these libs. @@ -38,6 +42,36 @@ frameworks.Foundation ]; }; + + /* For running external services + - Redis + - Postgres + */ + process-compose."ext-services" = + let + developmentToml = lib.importTOML ./config/development.toml; + databaseName = developmentToml.master_database.dbname; + databaseUser = developmentToml.master_database.username; + databasePass = developmentToml.master_database.password; + in + { + imports = [ inputs.services-flake.processComposeModules.default ]; + services.redis."r1".enable = true; + /* Postgres + - Create an user and grant all privileges + - Create a database + */ + services.postgres."p1" = { + enable = true; + initialScript = { + before = "CREATE USER ${databaseUser} WITH PASSWORD '${databasePass}' SUPERUSER CREATEDB CREATEROLE INHERIT LOGIN;"; + after = "GRANT ALL PRIVILEGES ON DATABASE ${databaseName} to ${databaseUser};"; + }; + initialDatabases = [ + { name = databaseName; } + ]; + }; + }; }; }; } diff --git a/justfile b/justfile index 84df776c1b0d..43fca4afc893 100644 --- a/justfile +++ b/justfile @@ -9,6 +9,7 @@ fmt *FLAGS: cargo +nightly fmt {{ fmt_flags }} {{ FLAGS }} check_flags := '--all-targets' +v2_lints:= '-D warnings -Aunused -Aclippy::todo -Aclippy::diverging_sub_expression' alias c := check @@ -44,7 +45,7 @@ clippy_v2 *FLAGS: ')" set -x - cargo clippy {{ check_flags }} --no-default-features --features "${FEATURES}" {{ FLAGS }} + cargo clippy {{ check_flags }} --no-default-features --features "${FEATURES}" -- {{ v2_lints }} {{ FLAGS }} set +x check_v2 *FLAGS: @@ -60,7 +61,7 @@ check_v2 *FLAGS: ')" set -x - cargo check {{ check_flags }} --no-default-features --features "${FEATURES}" {{ FLAGS }} + cargo check {{ check_flags }} --no-default-features --features "${FEATURES}" -- {{ FLAGS }} set +x run_v2: diff --git a/loadtest/config/development.toml b/loadtest/config/development.toml index c8a5ccf9228d..723498f7e7a1 100644 --- a/loadtest/config/development.toml +++ b/loadtest/config/development.toml @@ -35,6 +35,7 @@ jwt_secret = "secret" password_validity_in_days = 90 two_factor_auth_expiry_in_secs = 300 totp_issuer_name = "Hyperswitch" +force_two_factor_auth = false [locker] host = "" @@ -101,6 +102,7 @@ digitalvirgo.base_url = "https://dcb-integration-service-sandbox-external.stagin dlocal.base_url = "https://sandbox.dlocal.com/" dummyconnector.base_url = "http://localhost:8080/dummy-connector" ebanx.base_url = "https://sandbox.ebanxpay.com/" +elavon.base_url = "https://api.demo.convergepay.com" fiserv.base_url = "https://cert.api.fiservapps.com/" fiservemea.base_url = "https://prod.emea.api.fiservapps.com/sandbox" fiuu.base_url = "https://sandbox.merchant.razer.com/" @@ -114,6 +116,7 @@ gpayments.base_url = "https://{{merchant_endpoint_prefix}}-test.api.as1.gpayment helcim.base_url = "https://api.helcim.com/" iatapay.base_url = "https://sandbox.iata-pay.iata.org/api/v1" itaubank.base_url = "https://sandbox.devportal.itau.com.br/" +jpmorgan.base_url = "https://api-mock.payments.jpmorgan.com/api/v2" klarna.base_url = "https://api{{klarna_region}}.playground.klarna.com/" mifinity.base_url = "https://demo.mifinity.com/" mollie.base_url = "https://api.mollie.com/v2/" @@ -197,6 +200,7 @@ cards = [ "dlocal", "dummyconnector", "ebanx", + "elavon", "fiserv", "fiservemea", "fiuu", @@ -208,6 +212,7 @@ cards = [ "helcim", "iatapay", "itaubank", + "jpmorgan", "mollie", "multisafepay", "netcetera", @@ -369,7 +374,7 @@ enabled = false global_tenant = { schema = "public", redis_key_prefix = "" } [multitenancy.tenants] -public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default"} +public = { base_url = "http://localhost:8080", schema = "public", redis_key_prefix = "", clickhouse_database = "default"} [email] sender_email = "example@example.com" diff --git a/migrations/2024-10-24-123318_update-entity-type-column-in-roles/down.sql b/migrations/2024-10-24-123318_update-entity-type-column-in-roles/down.sql new file mode 100644 index 000000000000..60dfa892e602 --- /dev/null +++ b/migrations/2024-10-24-123318_update-entity-type-column-in-roles/down.sql @@ -0,0 +1,4 @@ +-- This file should undo anything in `up.sql` +ALTER TABLE roles ALTER COLUMN entity_type DROP DEFAULT; + +ALTER TABLE roles ALTER COLUMN entity_type DROP NOT NULL; \ No newline at end of file diff --git a/migrations/2024-10-24-123318_update-entity-type-column-in-roles/up.sql b/migrations/2024-10-24-123318_update-entity-type-column-in-roles/up.sql new file mode 100644 index 000000000000..564a026184ef --- /dev/null +++ b/migrations/2024-10-24-123318_update-entity-type-column-in-roles/up.sql @@ -0,0 +1,6 @@ +-- Your SQL goes here +UPDATE roles SET entity_type = 'merchant' WHERE entity_type IS NULL; + +ALTER TABLE roles ALTER COLUMN entity_type SET DEFAULT 'merchant'; + +ALTER TABLE roles ALTER COLUMN entity_type SET NOT NULL; \ No newline at end of file diff --git a/scripts/add_connector.sh b/scripts/add_connector.sh index 2e12d8290508..7e19844ad4d2 100755 --- a/scripts/add_connector.sh +++ b/scripts/add_connector.sh @@ -6,9 +6,9 @@ function find_prev_connector() { git checkout $self cp $self $self.tmp # Add new connector to existing list and sort it - connectors=(aci adyen adyenplatform airwallex applepay authorizedotnet bambora bamboraapac bankofamerica billwerk bitpay bluesnap boku braintree cashtocode checkout coinbase cryptopay cybersource datatrans deutschebank digitalvirgo dlocal dummyconnector ebanx fiserv fiservemea fiuu forte globalpay globepay gocardless gpayments helcim iatapay itaubank klarna mifinity mollie multisafepay netcetera nexinets nexixpay noon novalnet nuvei opayo opennode paybox payeezy payme payone paypal payu placetopay plaid powertranz prophetpay rapyd razorpay shift4 square stax stripe taxjar threedsecureio thunes trustpay tsys volt wellsfargo wellsfargopayout wise worldline worldpay zsl "$1") + connectors=(aci adyen adyenplatform airwallex applepay authorizedotnet bambora bamboraapac bankofamerica billwerk bitpay bluesnap boku braintree cashtocode checkout coinbase cryptopay cybersource datatrans deutschebank digitalvirgo dlocal dummyconnector ebanx elavon fiserv fiservemea fiuu forte globalpay globepay gocardless gpayments helcim iatapay itaubank jpmorgan klarna mifinity mollie multisafepay netcetera nexinets nexixpay noon novalnet nuvei opayo opennode paybox payeezy payme payone paypal payu placetopay plaid powertranz prophetpay rapyd razorpay shift4 square stax stripe taxjar threedsecureio thunes trustpay tsys volt wellsfargo wellsfargopayout wise worldline worldpay zsl "$1") IFS=$'\n' sorted=($(sort <<<"${connectors[*]}")); unset IFS - res=`echo ${sorted[@]}` + res="$(echo ${sorted[@]})" sed -i'' -e "s/^ connectors=.*/ connectors=($res \"\$1\")/" $self.tmp for i in "${!sorted[@]}"; do if [ "${sorted[$i]}" = "$1" ] && [ $i != "0" ]; then @@ -45,7 +45,7 @@ cd $SCRIPT/.. # Remove template files if already created for this connector rm -rf $conn/$payment_gateway $conn/$payment_gateway.rs -git checkout $conn.rs $src/types/api.rs $src/configs/settings.rs config/development.toml config/docker_compose.toml config/config.example.toml loadtest/config/development.toml crates/api_models/src/enums.rs crates/euclid/src/enums.rs crates/api_models/src/routing.rs $src/core/payments/flows.rs crates/common_enums/src/enums.rs $src/types/transformers.rs $src/core/admin.rs +git checkout $conn.rs $src/types/api.rs $src/configs/settings.rs config/development.toml config/docker_compose.toml config/config.example.toml loadtest/config/development.toml crates/api_models/src/connector_enums.rs crates/euclid/src/enums.rs crates/api_models/src/routing.rs $src/core/payments/flows.rs crates/common_enums/src/connector_enums.rs crates/common_enums/src/connector_enums.rs-e $src/types/transformers.rs $src/core/admin.rs # Add enum for this connector in required places previous_connector='' @@ -59,17 +59,17 @@ sed -i'' -e "s|$previous_connector_camelcase \(.*\)|$previous_connector_camelcas sed -i'' -e "s/pub $previous_connector: \(.*\)/pub $previous_connector: \1\n\tpub ${payment_gateway}: ConnectorParams,/" crates/hyperswitch_interfaces/src/configs.rs sed -i'' -e "s|$previous_connector.base_url \(.*\)|$previous_connector.base_url \1\n${payment_gateway}.base_url = \"$base_url\"|" config/development.toml config/docker_compose.toml config/config.example.toml loadtest/config/development.toml sed -r -i'' -e "s/\"$previous_connector\",/\"$previous_connector\",\n \"${payment_gateway}\",/" config/development.toml config/docker_compose.toml config/config.example.toml loadtest/config/development.toml -sed -i '' -e "s/\(pub enum Connector {\)/\1\n\t${payment_gateway_camelcase},/" crates/api_models/src/enums.rs -sed -i '' -e "/\/\/ Add Separate authentication support for connectors/{N;s/\(.*\)\n/\1\n\t\t\t| Self::${payment_gateway_camelcase}\n/;}" crates/api_models/src/enums.rs +sed -i '' -e "s/\(pub enum Connector {\)/\1\n\t${payment_gateway_camelcase},/" crates/api_models/src/connector_enums.rs +sed -i '' -e "/\/\/ Add Separate authentication support for connectors/{N;s/\(.*\)\n/\1\n\t\t\t| Self::${payment_gateway_camelcase}\n/;}" crates/api_models/src/connector_enums.rs sed -i '' -e "s/\(match connector_name {\)/\1\n\t\tapi_enums::Connector::${payment_gateway_camelcase} => {${payment_gateway}::transformers::${payment_gateway_camelcase}AuthType::try_from(val)?;Ok(())}/" $src/core/admin.rs -sed -i'' -e "s/\(pub enum RoutableConnectors {\)/\1\n\t${payment_gateway_camelcase},/" crates/common_enums/src/enums.rs +sed -i'' -e "s/\(pub enum RoutableConnectors {\)/\1\n\t${payment_gateway_camelcase},/" crates/common_enums/src/connector_enums.rs sed -i '' -e "s/\(pub enum Connector {\)/\1\n\t${payment_gateway_camelcase},/" crates/euclid/src/enums.rs sed -i'' -e "s|$previous_connector_camelcase \(.*\)|$previous_connector_camelcase \1\n\t\t\tapi_enums::Connector::${payment_gateway_camelcase} => Self::${payment_gateway_camelcase},|" $src/types/transformers.rs sed -i'' -e "s/^default_imp_for_\(.*\)/default_imp_for_\1\n\tconnectors::${payment_gateway_camelcase},/" crates/hyperswitch_connectors/src/default_implementations.rs sed -i'' -e "s/^default_imp_for_\(.*\)/default_imp_for_\1\n\tconnectors::${payment_gateway_camelcase},/" crates/hyperswitch_connectors/src/default_implementations_v2.rs # Remove temporary files created in above step -rm $conn.rs-e $src/types/api.rs-e $src/configs/settings.rs-e config/development.toml-e config/docker_compose.toml-e config/config.example.toml-e loadtest/config/development.toml-e crates/api_models/src/enums.rs-e crates/euclid/src/enums.rs-e crates/api_models/src/routing.rs-e $src/core/payments/flows.rs-e crates/common_enums/src/enums.rs-e $src/types/transformers.rs-e $src/core/admin.rs-e +rm $conn.rs-e $src/types/api.rs-e $src/configs/settings.rs-e config/development.toml-e config/docker_compose.toml-e config/config.example.toml-e loadtest/config/development.toml-e crates/api_models/src/connector_enums.rs-e crates/euclid/src/enums.rs-e crates/api_models/src/routing.rs-e $src/core/payments/flows.rs-e crates/common_enums/src/connector_enums.rs-e $src/types/transformers.rs-e $src/core/admin.rs-e crates/hyperswitch_connectors/src/default_implementations.rs-e crates/hyperswitch_connectors/src/default_implementations_v2.rs-e crates/hyperswitch_interfaces/src/configs.rs-e $src/connector.rs-e cd $conn/ # Generate template files for the connector diff --git a/scripts/execute_cypress.sh b/scripts/execute_cypress.sh new file mode 100755 index 000000000000..1f1219ee717c --- /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 "$@" diff --git a/v2_migrations/2024-08-28-081721_add_v2_columns/down.sql b/v2_migrations/2024-08-28-081721_add_v2_columns/down.sql index 519bef65cbba..4687c57fae31 100644 --- a/v2_migrations/2024-08-28-081721_add_v2_columns/down.sql +++ b/v2_migrations/2024-08-28-081721_add_v2_columns/down.sql @@ -39,4 +39,5 @@ ALTER TABLE payment_attempt DROP COLUMN payment_method_type_v2, DROP COLUMN authentication_applied, DROP COLUMN external_reference_id, DROP COLUMN tax_on_surcharge, + DROP COLUMN payment_method_billing_address, DROP COLUMN connector_payment_data; diff --git a/v2_migrations/2024-08-28-081721_add_v2_columns/up.sql b/v2_migrations/2024-08-28-081721_add_v2_columns/up.sql index 136bc550811a..3852c9c2ece3 100644 --- a/v2_migrations/2024-08-28-081721_add_v2_columns/up.sql +++ b/v2_migrations/2024-08-28-081721_add_v2_columns/up.sql @@ -42,4 +42,5 @@ ADD COLUMN payment_method_type_v2 VARCHAR, ADD COLUMN authentication_applied "AuthenticationType", ADD COLUMN external_reference_id VARCHAR(128), ADD COLUMN tax_on_surcharge BIGINT, + ADD COLUMN payment_method_billing_address BYTEA, ADD COLUMN connector_payment_data VARCHAR(512); diff --git a/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/down.sql b/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/down.sql index 318e57d5951f..359d5ce6359c 100644 --- a/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/down.sql +++ b/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/down.sql @@ -96,5 +96,8 @@ UPDATE payment_attempt SET attempt_id = id WHERE attempt_id IS NULL; +ALTER TABLE payment_attempt +ALTER COLUMN net_amount DROP NOT NULL; + ALTER TABLE payment_attempt ADD PRIMARY KEY (attempt_id, merchant_id); diff --git a/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/up.sql b/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/up.sql index eca7603e2b93..d4a1e7879b6b 100644 --- a/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/up.sql +++ b/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/up.sql @@ -104,6 +104,26 @@ SET NOT NULL, ALTER COLUMN currency SET NOT NULL, ALTER COLUMN client_secret +SET NOT NULL, + ALTER COLUMN session_expiry +SET NOT NULL, + ALTER COLUMN active_attempt_id DROP NOT NULL; + +------------------------ Payment Attempt ----------------------- +ALTER TABLE payment_attempt DROP CONSTRAINT payment_attempt_pkey; + +ALTER TABLE payment_attempt +ADD PRIMARY KEY (id); + +-- This migration is to make fields mandatory in payment_attempt table +ALTER TABLE payment_attempt +ALTER COLUMN net_amount +SET NOT NULL, + ALTER COLUMN authentication_type +SET NOT NULL, + ALTER COLUMN payment_method_type_v2 +SET NOT NULL, + ALTER COLUMN payment_method_subtype SET NOT NULL; ALTER TABLE payment_intent ALTER COLUMN session_expiry SET NOT NULL; diff --git a/v2_migrations/2024-10-08-081847_drop_v1_columns/down.sql b/v2_migrations/2024-10-08-081847_drop_v1_columns/down.sql index 2cdb02960339..55c5b3f749d4 100644 --- a/v2_migrations/2024-10-08-081847_drop_v1_columns/down.sql +++ b/v2_migrations/2024-10-08-081847_drop_v1_columns/down.sql @@ -85,7 +85,9 @@ ADD COLUMN IF NOT EXISTS attempt_id VARCHAR(64) NOT NULL, ADD COLUMN mandate_details JSONB, ADD COLUMN mandate_data JSONB, ADD COLUMN tax_amount bigint, - ADD COLUMN straight_through_algorithm JSONB; + ADD COLUMN straight_through_algorithm JSONB, + ADD COLUMN confirm BOOLEAN, + ADD COLUMN payment_method_billing_address_id VARCHAR(64); -- Create the index which was dropped because of dropping the column CREATE INDEX payment_attempt_connector_transaction_id_merchant_id_index ON payment_attempt (connector_transaction_id, merchant_id); diff --git a/v2_migrations/2024-10-08-081847_drop_v1_columns/up.sql b/v2_migrations/2024-10-08-081847_drop_v1_columns/up.sql index 48ae811bf343..0d22741b9420 100644 --- a/v2_migrations/2024-10-08-081847_drop_v1_columns/up.sql +++ b/v2_migrations/2024-10-08-081847_drop_v1_columns/up.sql @@ -83,4 +83,6 @@ ALTER TABLE payment_attempt DROP COLUMN attempt_id, DROP COLUMN mandate_details, DROP COLUMN mandate_data, DROP COLUMN tax_amount, - DROP COLUMN straight_through_algorithm; + DROP COLUMN straight_through_algorithm, + DROP COLUMN confirm, + DROP COLUMN payment_method_billing_address_id;