diff --git a/.github/workflows/pr-title-check.yml b/.github/workflows/conventional-commit-check.yml
similarity index 88%
rename from .github/workflows/pr-title-check.yml
rename to .github/workflows/conventional-commit-check.yml
index 8c15246f0e6c..5fd25e9332d1 100644
--- a/.github/workflows/pr-title-check.yml
+++ b/.github/workflows/conventional-commit-check.yml
@@ -1,4 +1,4 @@
-name: PR Title Checks
+name: Conventional Commit Message Check
on:
# This is a dangerous event trigger as it causes the workflow to run in the
@@ -35,19 +35,6 @@ env:
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
jobs:
- typos:
- name: Spell check PR title
- runs-on: ubuntu-latest
- steps:
- - name: Store PR title in a file
- shell: bash
- run: echo '${{ github.event.pull_request.title }}' > pr_title.txt
-
- - name: Spell check
- uses: crate-ci/typos@master
- with:
- files: ./pr_title.txt
-
pr_title_check:
name: Verify PR title follows conventional commit standards
runs-on: ubuntu-latest
@@ -66,8 +53,10 @@ jobs:
id: pr_title_check
if: ${{ github.event_name == 'pull_request_target' }}
shell: bash
+ env:
+ TITLE: ${{ github.event.pull_request.title }}
continue-on-error: true
- run: cog verify '${{ github.event.pull_request.title }}'
+ run: cog verify "$TITLE"
- name: Verify commit message follows conventional commit standards
id: commit_message_check
diff --git a/.github/workflows/postman-collection-runner.yml b/.github/workflows/postman-collection-runner.yml
index 6b0911d1b456..3291755b56cf 100644
--- a/.github/workflows/postman-collection-runner.yml
+++ b/.github/workflows/postman-collection-runner.yml
@@ -143,7 +143,7 @@ jobs:
for i in $(echo "$CONNECTORS" | tr "," "\n"); do
echo $i
- if ! cargo run --bin test_utils -- --connector_name="$i" --base_url="$BASE_URL" --admin_api_key="$ADMIN_API_KEY"; then
+ if ! cargo run --bin test_utils -- --connector-name="$i" --base-url="$BASE_URL" --admin-api-key="$ADMIN_API_KEY"; then
failed_connectors+=("$i")
fi
done
diff --git a/.github/workflows/pr-title-spell-check.yml b/.github/workflows/pr-title-spell-check.yml
new file mode 100644
index 000000000000..6ab6f184739d
--- /dev/null
+++ b/.github/workflows/pr-title-spell-check.yml
@@ -0,0 +1,27 @@
+name: PR Title Spell Check
+
+on:
+ pull_request:
+ types:
+ - opened
+ - edited
+ - synchronize
+
+jobs:
+ typos:
+ name: Spell check PR title
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ - name: Store PR title in a file
+ shell: bash
+ env:
+ TITLE: ${{ github.event.pull_request.title }}
+ run: echo $TITLE > pr_title.txt
+
+ - name: Spell check
+ uses: crate-ci/typos@master
+ with:
+ files: ./pr_title.txt
diff --git a/.github/workflows/release-new-version.yml b/.github/workflows/release-new-version.yml
index f489a3f8de2a..872c207e8aa3 100644
--- a/.github/workflows/release-new-version.yml
+++ b/.github/workflows/release-new-version.yml
@@ -74,7 +74,11 @@ jobs:
connector=$(basename ${connector_dir})
newman dir-import ${POSTMAN_DIR}/${connector} -o ${POSTMAN_JSON_DIR}/${connector}.postman_collection.json
done
- (git diff --quiet && git diff --staged --quiet) || (git commit -am 'test(postman): update postman collection files' && echo "Committed changes") || (echo "Unable to commit the following changes:" && git diff)
+
+ if git add postman && ! git diff --staged --quiet postman; then
+ git commit --message 'test(postman): update postman collection files'
+ echo "Changes detected and commited."
+ fi
- name: Obtain previous and new tag information
shell: bash
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aaf1cc629d8e..412b42afc2eb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,159 @@ All notable changes to HyperSwitch will be documented here.
- - -
+## 1.75.0 (2023-11-09)
+
+### Features
+
+- **events:** Add extracted fields based on req/res types ([#2795](https://github.com/juspay/hyperswitch/pull/2795)) ([`8985794`](https://github.com/juspay/hyperswitch/commit/89857941b09c5fbe0f3e7d5b4f908bb144ae162d))
+- **router:**
+ - Added merchant custom name support for payment link ([#2685](https://github.com/juspay/hyperswitch/pull/2685)) ([`8b15189`](https://github.com/juspay/hyperswitch/commit/8b151898dc0d8eefe5ed2bbdafe59e8f58b4698c))
+ - Add `gateway_status_map` CRUD APIs ([#2809](https://github.com/juspay/hyperswitch/pull/2809)) ([`5c9e235`](https://github.com/juspay/hyperswitch/commit/5c9e235bd30dd3e03d086a83613edfcc62b2ead2))
+
+### Bug Fixes
+
+- **analytics:** Added hs latency to api event for paymentconfirm call ([#2787](https://github.com/juspay/hyperswitch/pull/2787)) ([`aab8f60`](https://github.com/juspay/hyperswitch/commit/aab8f6035c16ca19009f8f1e0db688c17bc0b2b6))
+- [mollie] locale validation irrespective of auth type ([#2814](https://github.com/juspay/hyperswitch/pull/2814)) ([`25a73c2`](https://github.com/juspay/hyperswitch/commit/25a73c29a4c4715a54862dd6a28c875fd3752f63))
+
+**Full Changelog:** [`v1.74.0...v1.75.0`](https://github.com/juspay/hyperswitch/compare/v1.74.0...v1.75.0)
+
+- - -
+
+
+## 1.74.0 (2023-11-08)
+
+### Features
+
+- **core:** Use redis as temp locker instead of basilisk ([#2789](https://github.com/juspay/hyperswitch/pull/2789)) ([`6678689`](https://github.com/juspay/hyperswitch/commit/6678689265ae9a4fbb7a43c1938237d349c5a68e))
+- **events:** Add request details to api events ([#2769](https://github.com/juspay/hyperswitch/pull/2769)) ([`164d1c6`](https://github.com/juspay/hyperswitch/commit/164d1c66fbcb84104db07412496114db2f8c5c0c))
+- **router:** Add `gateway_status_map` interface ([#2804](https://github.com/juspay/hyperswitch/pull/2804)) ([`a429b23`](https://github.com/juspay/hyperswitch/commit/a429b23c7f21c9d08a79895c0b770b35aab725f7))
+- **test_utils:** Add custom-headers and custom delay support to rustman ([#2636](https://github.com/juspay/hyperswitch/pull/2636)) ([`1effddd`](https://github.com/juspay/hyperswitch/commit/1effddd0a0d3985d6df03c4ae9be28712befc05e))
+
+### Bug Fixes
+
+- **connector:** Add attempt_status in field in error_response ([#2794](https://github.com/juspay/hyperswitch/pull/2794)) ([`5642fef`](https://github.com/juspay/hyperswitch/commit/5642fef52a6d591d12c5745ed381f41a1593f183))
+
+### Refactors
+
+- **config:** Update payment method filter of Klarna in Stripe ([#2807](https://github.com/juspay/hyperswitch/pull/2807)) ([`21ce807`](https://github.com/juspay/hyperswitch/commit/21ce8079f4cb11d70c5eaae78f83773141c67d0c))
+- **router:** Add parameter connectors to get_request_body function ([#2708](https://github.com/juspay/hyperswitch/pull/2708)) ([`7623ea9`](https://github.com/juspay/hyperswitch/commit/7623ea93bee61b0bb22b68e86f44de17f04f876b))
+
+### Documentation
+
+- **README:** Update README ([#2800](https://github.com/juspay/hyperswitch/pull/2800)) ([`bef0a04`](https://github.com/juspay/hyperswitch/commit/bef0a04edc6323b3b7a2e0dd7eeb7954915ba7cf))
+
+**Full Changelog:** [`v1.73.0...v1.74.0`](https://github.com/juspay/hyperswitch/compare/v1.73.0...v1.74.0)
+
+- - -
+
+
+## 1.73.0 (2023-11-07)
+
+### Features
+
+- **connector:**
+ - [BANKOFAMERICA] Add Connector Template Code ([#2764](https://github.com/juspay/hyperswitch/pull/2764)) ([`4563935`](https://github.com/juspay/hyperswitch/commit/4563935372d2cdff3f746fa86a47f1166ffd32ac))
+ - [Bitpay] Add order id as the reference id ([#2591](https://github.com/juspay/hyperswitch/pull/2591)) ([`d47d4ac`](https://github.com/juspay/hyperswitch/commit/d47d4ac682705d6ac692f9381149bbf08ad71264))
+- **router:** Make webhook events config disabled only and by default enable all the events ([#2770](https://github.com/juspay/hyperswitch/pull/2770)) ([`d335879`](https://github.com/juspay/hyperswitch/commit/d335879f9289b57a90a76c6587a58a0b3e12c9ad))
+- Make drainer logs queryable with request_id and global_id ([#2771](https://github.com/juspay/hyperswitch/pull/2771)) ([`ff73aba`](https://github.com/juspay/hyperswitch/commit/ff73aba8e72d8e072027881760335c0c818df665))
+
+### Bug Fixes
+
+- **connector:** Fix amount conversion incase of minor unit ([#2793](https://github.com/juspay/hyperswitch/pull/2793)) ([`34f5226`](https://github.com/juspay/hyperswitch/commit/34f52260d3fa68b54e5b46207afaf2ad07a8d8ba))
+
+### Refactors
+
+- **payment_methods:** Added support for account subtype in pmd ([#2651](https://github.com/juspay/hyperswitch/pull/2651)) ([`e7375d0`](https://github.com/juspay/hyperswitch/commit/e7375d0e26099a7e0e6efd1b83b8eb9c7b1c5411))
+
+### Documentation
+
+- **README:** Add one-click deployment information using CDK ([#2798](https://github.com/juspay/hyperswitch/pull/2798)) ([`bb39cd4`](https://github.com/juspay/hyperswitch/commit/bb39cd4081fdcaf68b2b5de2234e93493dbd84b6))
+
+**Full Changelog:** [`v1.72.0...v1.73.0`](https://github.com/juspay/hyperswitch/compare/v1.72.0...v1.73.0)
+
+- - -
+
+
+## 1.72.0 (2023-11-05)
+
+### Features
+
+- **connector:**
+ - [ACI] Currency Unit Conversion ([#2750](https://github.com/juspay/hyperswitch/pull/2750)) ([`cdead78`](https://github.com/juspay/hyperswitch/commit/cdead78ea6a1f2dce92187f499f54498ba4bb173))
+ - [Fiserv] Currency Unit Conversion ([#2715](https://github.com/juspay/hyperswitch/pull/2715)) ([`b6b9e4f`](https://github.com/juspay/hyperswitch/commit/b6b9e4f912e1c61cd31ab91be587ffb08c9f3a5b))
+ - [Bitpay] Use `connector_request_reference_id` as reference to the connector ([#2697](https://github.com/juspay/hyperswitch/pull/2697)) ([`7141b89`](https://github.com/juspay/hyperswitch/commit/7141b89d231bae0c3b1c10095b88df16129b1665))
+ - [NMI] Currency Unit Conversion ([#2707](https://github.com/juspay/hyperswitch/pull/2707)) ([`1b45a30`](https://github.com/juspay/hyperswitch/commit/1b45a302630ed8affc5abff0de1325fb5c6f870e))
+ - [Payeezy] Currency Unit Conversion ([#2710](https://github.com/juspay/hyperswitch/pull/2710)) ([`25245b9`](https://github.com/juspay/hyperswitch/commit/25245b965371d93449f4584667adeb38ab7e0e59))
+
+### Refactors
+
+- **connector:** [Stax] Currency Unit Conversion ([#2711](https://github.com/juspay/hyperswitch/pull/2711)) ([`2782923`](https://github.com/juspay/hyperswitch/commit/278292322c7c06f4239dd73861469e436bd941fa))
+
+### Testing
+
+- **postman:** Update postman collection files ([`d11e7fd`](https://github.com/juspay/hyperswitch/commit/d11e7fd5642efe7da4b5021d87cf40f16d9eeded))
+
+**Full Changelog:** [`v1.71.0...v1.72.0`](https://github.com/juspay/hyperswitch/compare/v1.71.0...v1.72.0)
+
+- - -
+
+
+## 1.71.0 (2023-11-03)
+
+### Features
+
+- **merchant_connector_account:** Add cache for querying by `merchant_connector_id` ([#2738](https://github.com/juspay/hyperswitch/pull/2738)) ([`1ba6282`](https://github.com/juspay/hyperswitch/commit/1ba6282699b7dff5e6e95c9a14e51c0f8bf749cd))
+- **router:** Add Smart Routing to route payments efficiently ([#2665](https://github.com/juspay/hyperswitch/pull/2665)) ([`9b618d2`](https://github.com/juspay/hyperswitch/commit/9b618d24476967d364835d04010d9076a80aeb9c))
+
+### Bug Fixes
+
+- **connector:**
+ - [Cryptopay]Remove default case handling for Cryptopay ([#2699](https://github.com/juspay/hyperswitch/pull/2699)) ([`255a4f8`](https://github.com/juspay/hyperswitch/commit/255a4f89a8e0124310d42bb63ad459bd8cde2cba))
+ - [Bluesnap] fix psync status to failure when it is '403' ([#2772](https://github.com/juspay/hyperswitch/pull/2772)) ([`9314d14`](https://github.com/juspay/hyperswitch/commit/9314d1446326fd8a69f1f69657a976bbe7c27901))
+- Response spelling ([#2779](https://github.com/juspay/hyperswitch/pull/2779)) ([`5859372`](https://github.com/juspay/hyperswitch/commit/585937204d9071baa37d402f73159f8f650d0a07))
+
+### Testing
+
+- **postman:** Update postman collection files ([`21e8a10`](https://github.com/juspay/hyperswitch/commit/21e8a105f9b47ded232b457a0420ad71ec2414ed))
+
+**Full Changelog:** [`v1.70.1...v1.71.0`](https://github.com/juspay/hyperswitch/compare/v1.70.1...v1.71.0)
+
+- - -
+
+
+## 1.70.1 (2023-11-03)
+
+### Revert
+
+- Fix(analytics): feat(analytics): analytics APIs ([#2777](https://github.com/juspay/hyperswitch/pull/2777)) ([`169d33b`](https://github.com/juspay/hyperswitch/commit/169d33bf8157b1a9910c841c8c55eddc4d2ad168))
+
+**Full Changelog:** [`v1.70.0...v1.70.1`](https://github.com/juspay/hyperswitch/compare/v1.70.0...v1.70.1)
+
+- - -
+
+
+## 1.70.0 (2023-11-03)
+
+### Features
+
+- **analytics:** Analytics APIs ([#2676](https://github.com/juspay/hyperswitch/pull/2676)) ([`c0a5e7b`](https://github.com/juspay/hyperswitch/commit/c0a5e7b7d945095053606e35c9bb23a06090c4e3))
+- **connector:** [Multisafepay] add error handling ([#2595](https://github.com/juspay/hyperswitch/pull/2595)) ([`b3c846d`](https://github.com/juspay/hyperswitch/commit/b3c846d637dd32a2d6d7044c118abbb2616642f0))
+- **events:** Add api auth type details to events ([#2760](https://github.com/juspay/hyperswitch/pull/2760)) ([`1094493`](https://github.com/juspay/hyperswitch/commit/10944937a02502e0727f16368d8d055e575dd518))
+
+### Bug Fixes
+
+- **router:** Make customer_id optional when billing and shipping address is passed in payments create, update ([#2762](https://github.com/juspay/hyperswitch/pull/2762)) ([`e40a293`](https://github.com/juspay/hyperswitch/commit/e40a29351c7aa7b86a5684959a84f0236104cafd))
+- Null fields in payments response ([#2745](https://github.com/juspay/hyperswitch/pull/2745)) ([`42261a5`](https://github.com/juspay/hyperswitch/commit/42261a5306bb99d3e20eb3aa734a895e589b1d94))
+
+### Testing
+
+- **postman:** Update postman collection files ([`772f03e`](https://github.com/juspay/hyperswitch/commit/772f03ee3836ce86de3874f6a5e7f636718e6034))
+
+**Full Changelog:** [`v1.69.0...v1.70.0`](https://github.com/juspay/hyperswitch/compare/v1.69.0...v1.70.0)
+
+- - -
+
+
## 1.69.0 (2023-10-31)
### Features
diff --git a/Cargo.lock b/Cargo.lock
index 665703f3d505..ac7fde55d8e3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -376,6 +376,12 @@ dependencies = [
"libc",
]
+[[package]]
+name = "anes"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
+
[[package]]
name = "anstyle"
version = "1.0.0"
@@ -397,6 +403,7 @@ dependencies = [
"common_enums",
"common_utils",
"error-stack",
+ "euclid",
"masking",
"mime",
"reqwest",
@@ -1343,6 +1350,12 @@ dependencies = [
"thiserror",
]
+[[package]]
+name = "cast"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
+
[[package]]
name = "cc"
version = "1.0.83"
@@ -1413,6 +1426,33 @@ dependencies = [
"phf_codegen",
]
+[[package]]
+name = "ciborium"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926"
+dependencies = [
+ "ciborium-io",
+ "ciborium-ll",
+ "serde",
+]
+
+[[package]]
+name = "ciborium-io"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656"
+
+[[package]]
+name = "ciborium-ll"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b"
+dependencies = [
+ "ciborium-io",
+ "half",
+]
+
[[package]]
name = "clap"
version = "4.3.4"
@@ -1463,7 +1503,6 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
name = "common_enums"
version = "0.1.0"
dependencies = [
- "common_utils",
"diesel",
"router_derive",
"serde",
@@ -1479,6 +1518,7 @@ version = "0.1.0"
dependencies = [
"async-trait",
"bytes",
+ "common_enums",
"diesel",
"error-stack",
"fake",
@@ -1497,6 +1537,7 @@ dependencies = [
"reqwest",
"ring",
"router_env",
+ "rustc-hash",
"serde",
"serde_json",
"serde_urlencoded",
@@ -1615,6 +1656,42 @@ dependencies = [
"cfg-if",
]
+[[package]]
+name = "criterion"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
+dependencies = [
+ "anes",
+ "cast",
+ "ciborium",
+ "clap",
+ "criterion-plot",
+ "is-terminal",
+ "itertools 0.10.5",
+ "num-traits",
+ "once_cell",
+ "oorandom",
+ "plotters",
+ "rayon",
+ "regex",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "tinytemplate",
+ "walkdir",
+]
+
+[[package]]
+name = "criterion-plot"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
+dependencies = [
+ "cast",
+ "itertools 0.10.5",
+]
+
[[package]]
name = "crossbeam-channel"
version = "0.5.8"
@@ -2022,6 +2099,15 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+[[package]]
+name = "erased-serde"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c138974f9d5e7fe373eb04df7cae98833802ae4b11c24ac7039a21d5af4b26c"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "errno"
version = "0.3.4"
@@ -2063,6 +2149,52 @@ dependencies = [
"serde",
]
+[[package]]
+name = "euclid"
+version = "0.1.0"
+dependencies = [
+ "common_enums",
+ "criterion",
+ "erased-serde",
+ "euclid_macros",
+ "frunk",
+ "frunk_core",
+ "nom",
+ "once_cell",
+ "rustc-hash",
+ "serde",
+ "serde_json",
+ "strum 0.25.0",
+ "thiserror",
+]
+
+[[package]]
+name = "euclid_macros"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "rustc-hash",
+ "strum 0.24.1",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "euclid_wasm"
+version = "0.1.0"
+dependencies = [
+ "api_models",
+ "euclid",
+ "getrandom 0.2.10",
+ "kgraph_utils",
+ "once_cell",
+ "ron-parser",
+ "serde",
+ "serde-wasm-bindgen",
+ "strum 0.25.0",
+ "wasm-bindgen",
+]
+
[[package]]
name = "event-listener"
version = "2.5.3"
@@ -2415,8 +2547,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
dependencies = [
"cfg-if",
+ "js-sys",
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
+ "wasm-bindgen",
]
[[package]]
@@ -2497,6 +2631,12 @@ dependencies = [
"tracing",
]
+[[package]]
+name = "half"
+version = "1.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
+
[[package]]
name = "hashbrown"
version = "0.12.3"
@@ -2811,6 +2951,17 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
+[[package]]
+name = "is-terminal"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
+dependencies = [
+ "hermit-abi",
+ "rustix 0.38.17",
+ "windows-sys",
+]
+
[[package]]
name = "itertools"
version = "0.10.5"
@@ -2905,6 +3056,19 @@ dependencies = [
"simple_asn1",
]
+[[package]]
+name = "kgraph_utils"
+version = "0.1.0"
+dependencies = [
+ "api_models",
+ "criterion",
+ "euclid",
+ "masking",
+ "serde",
+ "serde_json",
+ "thiserror",
+]
+
[[package]]
name = "language-tags"
version = "0.3.2"
@@ -3365,6 +3529,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d11de466f4a3006fe8a5e7ec84e93b79c70cb992ae0aa0eb631ad2df8abfe2"
+[[package]]
+name = "oorandom"
+version = "11.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
+
[[package]]
name = "opaque-debug"
version = "0.3.0"
@@ -3729,6 +3899,34 @@ version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
+[[package]]
+name = "plotters"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45"
+dependencies = [
+ "num-traits",
+ "plotters-backend",
+ "plotters-svg",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "plotters-backend"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609"
+
+[[package]]
+name = "plotters-svg"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab"
+dependencies = [
+ "plotters-backend",
+]
+
[[package]]
name = "png"
version = "0.16.8"
@@ -4216,6 +4414,19 @@ dependencies = [
"serde",
]
+[[package]]
+name = "ron-parser"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c7280c46017fafbe4275179689e446a9b0db3bd91ea61aaee22841ef618405a"
+dependencies = [
+ "nom",
+ "serde",
+ "serde-wasm-bindgen",
+ "serde_json",
+ "wasm-bindgen",
+]
+
[[package]]
name = "router"
version = "0.2.0"
@@ -4248,6 +4459,7 @@ dependencies = [
"dyn-clone",
"encoding_rs",
"error-stack",
+ "euclid",
"external_services",
"futures",
"hex",
@@ -4257,6 +4469,7 @@ dependencies = [
"infer 0.13.0",
"josekit",
"jsonwebtoken",
+ "kgraph_utils",
"literally",
"masking",
"maud",
@@ -4268,6 +4481,7 @@ dependencies = [
"openssl",
"qrcode",
"rand 0.8.5",
+ "rand_chacha 0.3.1",
"redis_interface",
"regex",
"reqwest",
@@ -4275,6 +4489,7 @@ dependencies = [
"router_derive",
"router_env",
"roxmltree",
+ "rustc-hash",
"scheduler",
"serde",
"serde_json",
@@ -4651,6 +4866,17 @@ dependencies = [
"serde_derive",
]
+[[package]]
+name = "serde-wasm-bindgen"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e"
+dependencies = [
+ "js-sys",
+ "serde",
+ "wasm-bindgen",
+]
+
[[package]]
name = "serde_derive"
version = "1.0.188"
@@ -5349,6 +5575,16 @@ dependencies = [
"time-core",
]
+[[package]]
+name = "tinytemplate"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
+dependencies = [
+ "serde",
+ "serde_json",
+]
+
[[package]]
name = "tinyvec"
version = "1.6.0"
diff --git a/README.md b/README.md
index cc19670a8fc3..129a0512d4a0 100644
--- a/README.md
+++ b/README.md
@@ -35,19 +35,11 @@ The single API to access payment ecosystems across 130+ countries
-🎉 Hacktoberfest is here! 🎉
-
-New to Rust? Hyperswitch is the perfect place to start this hacktoberfest! 😁
-
-> ⭐️ If you're new to Hacktoberfest, you can learn more and register to participate [here](https://hacktoberfest.com/participation/). Registration is from **September 26th - October 31st**.
-
-Hyperswitch is an open source payments switch to make payments fast, reliable, and, affordable.
-It lets you connect with multiple payment processors and route traffic effortlessly, all with a single API integration.
-
+Hyperswitch is a community-led, open payments switch to enable access to the best payments infrastructure for every digital business.
Using Hyperswitch, you can:
@@ -58,8 +50,6 @@ Using Hyperswitch, you can:
- 🎨 **Customize payment flows** with full visibility and control
- 🌐 **Increase business reach** with local/alternate payment methods
-> Hyperswitch is **wire-compatible** with top processors like Stripe, making it easy to integrate.
-
@@ -67,24 +57,23 @@ Using Hyperswitch, you can:
⚡️ Quick Start Guide
+ One-click deployment on AWS cloud
-
+The fastest and easiest way to try hyperswitch is via our CDK scripts
-Ways to get started with Hyperswitch:
+1. Click on the following button for a quick standalone deployment on AWS, suitable for prototyping.
+ No code or setup is required in your system and the deployment is covered within the AWS free-tier setup.
-1. Try it in our Sandbox Environment: Fast and easy to
- start.
- No code or setup is required in your system, [learn more](/docs/try_sandbox.md)
+ Click here if you have not bootstrapped your region before deploying
+
-
-2. A simple demo of integrating Hyperswitch with your React App, Try our React [Demo App](https://github.com/aashu331998/hyperswitch-react-demo-app/archive/refs/heads/main.zip).
+2. Sign-in to your AWS console.
+3. Follow the instructions provided on the console to successfully deploy Hyperswitch
-3. Install in your local system: Configurations and
- setup required in your system.
- Suitable if you like to customise the core offering, [setup guide](/docs/try_local_system.md)
+For an early access to the production-ready setup fill this Early Access Form
🔌 Fast Integration for Stripe Users
diff --git a/config/config.example.toml b/config/config.example.toml
index 59083d6c71d3..ed9cf9698984 100644
--- a/config/config.example.toml
+++ b/config/config.example.toml
@@ -163,6 +163,7 @@ airwallex.base_url = "https://api-demo.airwallex.com/"
applepay.base_url = "https://apple-pay-gateway.apple.com/"
authorizedotnet.base_url = "https://apitest.authorize.net/xml/v1/request.api"
bambora.base_url = "https://api.na.bambora.com"
+bankofamerica.base_url = "https://apitest.merchant-services.bankofamerica.com/"
bitpay.base_url = "https://test.bitpay.com"
bluesnap.base_url = "https://sandbox.bluesnap.com/"
bluesnap.secondary_base_url = "https://sandpay.bluesnap.com/"
diff --git a/config/development.toml b/config/development.toml
index 5e74eafcb467..63c1f045d94f 100644
--- a/config/development.toml
+++ b/config/development.toml
@@ -71,6 +71,7 @@ cards = [
"airwallex",
"authorizedotnet",
"bambora",
+ "bankofamerica",
"bitpay",
"bluesnap",
"boku",
@@ -136,6 +137,7 @@ airwallex.base_url = "https://api-demo.airwallex.com/"
applepay.base_url = "https://apple-pay-gateway.apple.com/"
authorizedotnet.base_url = "https://apitest.authorize.net/xml/v1/request.api"
bambora.base_url = "https://api.na.bambora.com"
+bankofamerica.base_url = "https://apitest.merchant-services.bankofamerica.com/"
bitpay.base_url = "https://test.bitpay.com"
bluesnap.base_url = "https://sandbox.bluesnap.com/"
bluesnap.secondary_base_url = "https://sandpay.bluesnap.com/"
@@ -246,7 +248,7 @@ ideal = { country = "NL", currency = "EUR" }
[pm_filters.stripe]
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,KR,VN,MA,ZA,VA,CL,SV,GT,HN,PA" }
-klarna = { country = "US", currency = "USD" }
+klarna = { country = "AU,AT,BE,CA,CZ,DK,FI,FR,DE,GR,IE,IT,NL,NZ,NO,PL,PT,ES,SE,CH,GB,US", currency = "AUD,CAD,CHF,CZK,DKK,EUR,GBP,NOK,NZD,PLN,SEK,USD" }
affirm = { country = "US", currency = "USD" }
afterpay_clearpay = { country = "US,CA,GB,AU,NZ,FR,ES", currency = "USD,CAD,GBP,AUD,NZD" }
giropay = { country = "DE", currency = "EUR" }
diff --git a/config/docker_compose.toml b/config/docker_compose.toml
index 20ca175ceb84..282894b56d43 100644
--- a/config/docker_compose.toml
+++ b/config/docker_compose.toml
@@ -78,6 +78,7 @@ airwallex.base_url = "https://api-demo.airwallex.com/"
applepay.base_url = "https://apple-pay-gateway.apple.com/"
authorizedotnet.base_url = "https://apitest.authorize.net/xml/v1/request.api"
bambora.base_url = "https://api.na.bambora.com"
+bankofamerica.base_url = "https://apitest.merchant-services.bankofamerica.com/"
bitpay.base_url = "https://test.bitpay.com"
bluesnap.base_url = "https://sandbox.bluesnap.com/"
bluesnap.secondary_base_url = "https://sandpay.bluesnap.com/"
@@ -145,6 +146,7 @@ cards = [
"airwallex",
"authorizedotnet",
"bambora",
+ "bankofamerica",
"bitpay",
"bluesnap",
"boku",
diff --git a/connector-template/mod.rs b/connector-template/mod.rs
index 05f527d24662..7f21962109de 100644
--- a/connector-template/mod.rs
+++ b/connector-template/mod.rs
@@ -105,6 +105,7 @@ impl ConnectorCommon for {{project-name | downcase | pascal_case}} {
code: response.code,
message: response.message,
reason: response.reason,
+ attempt_status: None,
})
}
}
@@ -156,7 +157,7 @@ impl
Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
}
- fn get_request_body(&self, req: &types::PaymentsAuthorizeRouterData) -> CustomResult, errors::ConnectorError> {
+ fn get_request_body(&self, req: &types::PaymentsAuthorizeRouterData, _connectors: &settings::Connectors,) -> CustomResult , errors::ConnectorError> {
let connector_router_data =
{{project-name | downcase}}::{{project-name | downcase | pascal_case}}RouterData::try_from((
&self.get_currency_unit(),
@@ -185,7 +186,7 @@ impl
.headers(types::PaymentsAuthorizeType::get_headers(
self, req, connectors,
)?)
- .body(types::PaymentsAuthorizeType::get_request_body(self, req)?)
+ .body(types::PaymentsAuthorizeType::get_request_body(self, req, connectors)?)
.build(),
))
}
@@ -301,6 +302,7 @@ impl
fn get_request_body(
&self,
_req: &types::PaymentsCaptureRouterData,
+ _connectors: &settings::Connectors,
) -> CustomResult , errors::ConnectorError> {
Err(errors::ConnectorError::NotImplemented("get_request_body method".to_string()).into())
}
@@ -318,7 +320,7 @@ impl
.headers(types::PaymentsCaptureType::get_headers(
self, req, connectors,
)?)
- .body(types::PaymentsCaptureType::get_request_body(self, req)?)
+ .body(types::PaymentsCaptureType::get_request_body(self, req, connectors)?)
.build(),
))
}
@@ -373,7 +375,7 @@ impl
Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
}
- fn get_request_body(&self, req: &types::RefundsRouterData) -> CustomResult, errors::ConnectorError> {
+ fn get_request_body(&self, req: &types::RefundsRouterData, _connectors: &settings::Connectors,) -> CustomResult, errors::ConnectorError> {
let connector_router_data =
{{project-name | downcase}}::{{project-name | downcase | pascal_case}}RouterData::try_from((
&self.get_currency_unit(),
@@ -393,7 +395,7 @@ impl
.url(&types::RefundExecuteType::get_url(self, req, connectors)?)
.attach_default_headers()
.headers(types::RefundExecuteType::get_headers(self, req, connectors)?)
- .body(types::RefundExecuteType::get_request_body(self, req)?)
+ .body(types::RefundExecuteType::get_request_body(self, req, connectors)?)
.build();
Ok(Some(request))
}
@@ -441,7 +443,7 @@ impl
.url(&types::RefundSyncType::get_url(self, req, connectors)?)
.attach_default_headers()
.headers(types::RefundSyncType::get_headers(self, req, connectors)?)
- .body(types::RefundSyncType::get_request_body(self, req)?)
+ .body(types::RefundSyncType::get_request_body(self, req, connectors)?)
.build(),
))
}
diff --git a/crates/api_models/Cargo.toml b/crates/api_models/Cargo.toml
index ce61d30d36f5..d15fdeabf387 100644
--- a/crates/api_models/Cargo.toml
+++ b/crates/api_models/Cargo.toml
@@ -9,8 +9,12 @@ license.workspace = true
[features]
default = ["payouts"]
+business_profile_routing = []
+connector_choice_bcompat = []
errors = ["dep:actix-web", "dep:reqwest"]
-dummy_connector = ["common_enums/dummy_connector"]
+backwards_compatibility = ["connector_choice_bcompat"]
+connector_choice_mca_id = ["euclid/connector_choice_mca_id"]
+dummy_connector = ["common_enums/dummy_connector", "euclid/dummy_connector"]
detailed_errors = []
payouts = []
@@ -32,5 +36,6 @@ thiserror = "1.0.40"
cards = { version = "0.1.0", path = "../cards" }
common_enums = { path = "../common_enums" }
common_utils = { version = "0.1.0", path = "../common_utils" }
+euclid = { version = "0.1.0", path = "../euclid" }
masking = { version = "0.1.0", path = "../masking" }
router_derive = { version = "0.1.0", path = "../router_derive" }
diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs
index b1a258e6b26c..979214a071a9 100644
--- a/crates/api_models/src/admin.rs
+++ b/crates/api_models/src/admin.rs
@@ -443,72 +443,6 @@ pub mod payout_routing_algorithm {
}
}
-#[derive(Clone, Debug, Deserialize, Serialize)]
-#[serde(tag = "type", content = "data", rename_all = "snake_case")]
-pub enum RoutingAlgorithm {
- Single(RoutableConnectorChoice),
-}
-
-#[derive(Clone, Debug, Deserialize, Serialize)]
-#[serde(untagged)]
-pub enum RoutableConnectorChoice {
- ConnectorName(api_enums::RoutableConnectors),
- ConnectorId {
- merchant_connector_id: String,
- connector: api_enums::RoutableConnectors,
- },
-}
-
-#[derive(Clone, Debug, Deserialize, Serialize)]
-#[serde(
- tag = "type",
- content = "data",
- rename_all = "snake_case",
- from = "StraightThroughAlgorithmSerde",
- into = "StraightThroughAlgorithmSerde"
-)]
-pub enum StraightThroughAlgorithm {
- Single(RoutableConnectorChoice),
-}
-
-#[derive(Clone, Debug, Deserialize, Serialize)]
-#[serde(tag = "type", content = "data", rename_all = "snake_case")]
-pub enum StraightThroughAlgorithmInner {
- Single(RoutableConnectorChoice),
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-#[serde(untagged)]
-pub enum StraightThroughAlgorithmSerde {
- Direct(StraightThroughAlgorithmInner),
- Nested {
- algorithm: StraightThroughAlgorithmInner,
- },
-}
-
-impl From for StraightThroughAlgorithm {
- fn from(value: StraightThroughAlgorithmSerde) -> Self {
- let inner = match value {
- StraightThroughAlgorithmSerde::Direct(algorithm) => algorithm,
- StraightThroughAlgorithmSerde::Nested { algorithm } => algorithm,
- };
-
- match inner {
- StraightThroughAlgorithmInner::Single(conn) => Self::Single(conn),
- }
- }
-}
-
-impl From for StraightThroughAlgorithmSerde {
- fn from(value: StraightThroughAlgorithm) -> Self {
- let inner = match value {
- StraightThroughAlgorithm::Single(conn) => StraightThroughAlgorithmInner::Single(conn),
- };
-
- Self::Nested { algorithm: inner }
- }
-}
-
#[derive(Clone, Debug, Deserialize, ToSchema, Serialize, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct PrimaryBusinessDetails {
@@ -529,9 +463,8 @@ pub struct PaymentLinkConfig {
#[serde(deny_unknown_fields)]
pub struct PaymentLinkColorSchema {
- pub primary_color: Option,
- pub primary_accent_color: Option,
- pub secondary_color: Option,
+ pub background_primary_color: Option,
+ pub sdk_theme: Option,
}
#[derive(Clone, Debug, Deserialize, ToSchema, Serialize)]
@@ -959,6 +892,8 @@ pub struct ToggleKVResponse {
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct ToggleKVRequest {
+ #[serde(skip_deserializing)]
+ pub merchant_id: String,
/// Status of KV for the specific merchant
#[schema(example = true)]
pub kv_enabled: bool,
diff --git a/crates/api_models/src/api_keys.rs b/crates/api_models/src/api_keys.rs
index f0ab403d9c65..805c5616c2a0 100644
--- a/crates/api_models/src/api_keys.rs
+++ b/crates/api_models/src/api_keys.rs
@@ -129,6 +129,12 @@ pub struct UpdateApiKeyRequest {
/// rotating your keys once every 6 months.
#[schema(example = "2022-09-10T10:11:12Z")]
pub expiration: Option,
+
+ #[serde(skip_deserializing)]
+ pub key_id: String,
+
+ #[serde(skip_deserializing)]
+ pub merchant_id: String,
}
/// The response body for revoking an API Key.
diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs
index ee67c1187e6b..b27e71b9e8f5 100644
--- a/crates/api_models/src/enums.rs
+++ b/crates/api_models/src/enums.rs
@@ -75,8 +75,9 @@ pub enum Connector {
Adyen,
Airwallex,
Authorizedotnet,
- Bitpay,
Bambora,
+ // Bankofamerica, Added as template code for future usage
+ Bitpay,
Bluesnap,
Boku,
Braintree,
@@ -195,6 +196,7 @@ pub enum RoutableConnectors {
Adyen,
Airwallex,
Authorizedotnet,
+ // Bankofamerica, Added as template code for future usage
Bitpay,
Bambora,
Bluesnap,
diff --git a/crates/api_models/src/events.rs b/crates/api_models/src/events.rs
new file mode 100644
index 000000000000..23e7c9dc706a
--- /dev/null
+++ b/crates/api_models/src/events.rs
@@ -0,0 +1,75 @@
+pub mod customer;
+pub mod gsm;
+pub mod payment;
+#[cfg(feature = "payouts")]
+pub mod payouts;
+pub mod refund;
+pub mod routing;
+
+use common_utils::{
+ events::{ApiEventMetric, ApiEventsType},
+ impl_misc_api_event_type,
+};
+
+use crate::{
+ admin::*, api_keys::*, cards_info::*, disputes::*, files::*, mandates::*, payment_methods::*,
+ payments::*, verifications::*,
+};
+
+impl ApiEventMetric for TimeRange {}
+
+impl_misc_api_event_type!(
+ PaymentMethodId,
+ PaymentsSessionResponse,
+ PaymentMethodListResponse,
+ PaymentMethodCreate,
+ PaymentLinkInitiateRequest,
+ RetrievePaymentLinkResponse,
+ MandateListConstraints,
+ CreateFileResponse,
+ DisputeResponse,
+ SubmitEvidenceRequest,
+ MerchantConnectorResponse,
+ MerchantConnectorId,
+ MandateResponse,
+ MandateRevokedResponse,
+ RetrievePaymentLinkRequest,
+ MandateId,
+ DisputeListConstraints,
+ RetrieveApiKeyResponse,
+ BusinessProfileResponse,
+ BusinessProfileUpdate,
+ BusinessProfileCreate,
+ RevokeApiKeyResponse,
+ ToggleKVResponse,
+ ToggleKVRequest,
+ MerchantAccountDeleteResponse,
+ MerchantAccountUpdate,
+ CardInfoResponse,
+ CreateApiKeyResponse,
+ CreateApiKeyRequest,
+ MerchantConnectorDeleteResponse,
+ MerchantConnectorUpdate,
+ MerchantConnectorCreate,
+ MerchantId,
+ CardsInfoRequest,
+ MerchantAccountResponse,
+ MerchantAccountListRequest,
+ MerchantAccountCreate,
+ PaymentsSessionRequest,
+ ApplepayMerchantVerificationRequest,
+ ApplepayMerchantResponse,
+ ApplepayVerifiedDomainsResponse,
+ UpdateApiKeyRequest
+);
+
+#[cfg(feature = "stripe")]
+impl_misc_api_event_type!(
+ StripeSetupIntentResponse,
+ StripeRefundResponse,
+ StripePaymentIntentListResponse,
+ StripePaymentIntentResponse,
+ CustomerDeleteResponse,
+ CustomerPaymentMethodListResponse,
+ CreateCustomerResponse
+);
diff --git a/crates/api_models/src/events/customer.rs b/crates/api_models/src/events/customer.rs
new file mode 100644
index 000000000000..29f565042181
--- /dev/null
+++ b/crates/api_models/src/events/customer.rs
@@ -0,0 +1,35 @@
+use common_utils::events::{ApiEventMetric, ApiEventsType};
+
+use crate::customers::{CustomerDeleteResponse, CustomerId, CustomerRequest, CustomerResponse};
+
+impl ApiEventMetric for CustomerDeleteResponse {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Customer {
+ customer_id: self.customer_id.clone(),
+ })
+ }
+}
+
+impl ApiEventMetric for CustomerRequest {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Customer {
+ customer_id: self.customer_id.clone(),
+ })
+ }
+}
+
+impl ApiEventMetric for CustomerResponse {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Customer {
+ customer_id: self.customer_id.clone(),
+ })
+ }
+}
+
+impl ApiEventMetric for CustomerId {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Customer {
+ customer_id: self.customer_id.clone(),
+ })
+ }
+}
diff --git a/crates/api_models/src/events/gsm.rs b/crates/api_models/src/events/gsm.rs
new file mode 100644
index 000000000000..d984ae1ff698
--- /dev/null
+++ b/crates/api_models/src/events/gsm.rs
@@ -0,0 +1,33 @@
+use common_utils::events::{ApiEventMetric, ApiEventsType};
+
+use crate::gsm;
+
+impl ApiEventMetric for gsm::GsmCreateRequest {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Gsm)
+ }
+}
+
+impl ApiEventMetric for gsm::GsmUpdateRequest {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Gsm)
+ }
+}
+
+impl ApiEventMetric for gsm::GsmRetrieveRequest {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Gsm)
+ }
+}
+
+impl ApiEventMetric for gsm::GsmDeleteRequest {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Gsm)
+ }
+}
+
+impl ApiEventMetric for gsm::GsmDeleteResponse {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Gsm)
+ }
+}
diff --git a/crates/api_models/src/events/payment.rs b/crates/api_models/src/events/payment.rs
new file mode 100644
index 000000000000..2f3336fc2777
--- /dev/null
+++ b/crates/api_models/src/events/payment.rs
@@ -0,0 +1,151 @@
+use common_utils::events::{ApiEventMetric, ApiEventsType};
+
+use crate::{
+ payment_methods::{
+ CustomerPaymentMethodsListResponse, PaymentMethodDeleteResponse, PaymentMethodListRequest,
+ PaymentMethodResponse, PaymentMethodUpdate,
+ },
+ payments::{
+ PaymentIdType, PaymentListConstraints, PaymentListFilterConstraints, PaymentListFilters,
+ PaymentListResponse, PaymentListResponseV2, PaymentsApproveRequest, PaymentsCancelRequest,
+ PaymentsCaptureRequest, PaymentsRejectRequest, PaymentsRequest, PaymentsResponse,
+ PaymentsRetrieveRequest, PaymentsStartRequest, RedirectionResponse,
+ },
+};
+impl ApiEventMetric for PaymentsRetrieveRequest {
+ fn get_api_event_type(&self) -> Option {
+ match self.resource_id {
+ PaymentIdType::PaymentIntentId(ref id) => Some(ApiEventsType::Payment {
+ payment_id: id.clone(),
+ }),
+ _ => None,
+ }
+ }
+}
+
+impl ApiEventMetric for PaymentsStartRequest {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Payment {
+ payment_id: self.payment_id.clone(),
+ })
+ }
+}
+
+impl ApiEventMetric for PaymentsCaptureRequest {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Payment {
+ payment_id: self.payment_id.to_owned(),
+ })
+ }
+}
+
+impl ApiEventMetric for PaymentsCancelRequest {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Payment {
+ payment_id: self.payment_id.clone(),
+ })
+ }
+}
+
+impl ApiEventMetric for PaymentsApproveRequest {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Payment {
+ payment_id: self.payment_id.clone(),
+ })
+ }
+}
+
+impl ApiEventMetric for PaymentsRejectRequest {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Payment {
+ payment_id: self.payment_id.clone(),
+ })
+ }
+}
+
+impl ApiEventMetric for PaymentsRequest {
+ fn get_api_event_type(&self) -> Option {
+ match self.payment_id {
+ Some(PaymentIdType::PaymentIntentId(ref id)) => Some(ApiEventsType::Payment {
+ payment_id: id.clone(),
+ }),
+ _ => None,
+ }
+ }
+}
+
+impl ApiEventMetric for PaymentsResponse {
+ fn get_api_event_type(&self) -> Option {
+ self.payment_id
+ .clone()
+ .map(|payment_id| ApiEventsType::Payment { payment_id })
+ }
+}
+
+impl ApiEventMetric for PaymentMethodResponse {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::PaymentMethod {
+ payment_method_id: self.payment_method_id.clone(),
+ payment_method: Some(self.payment_method),
+ payment_method_type: self.payment_method_type,
+ })
+ }
+}
+
+impl ApiEventMetric for PaymentMethodUpdate {}
+
+impl ApiEventMetric for PaymentMethodDeleteResponse {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::PaymentMethod {
+ payment_method_id: self.payment_method_id.clone(),
+ payment_method: None,
+ payment_method_type: None,
+ })
+ }
+}
+
+impl ApiEventMetric for CustomerPaymentMethodsListResponse {}
+
+impl ApiEventMetric for PaymentMethodListRequest {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::PaymentMethodList {
+ payment_id: self
+ .client_secret
+ .as_ref()
+ .and_then(|cs| cs.rsplit_once("_secret_"))
+ .map(|(pid, _)| pid.to_string()),
+ })
+ }
+}
+
+impl ApiEventMetric for PaymentListFilterConstraints {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::ResourceListAPI)
+ }
+}
+
+impl ApiEventMetric for PaymentListFilters {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::ResourceListAPI)
+ }
+}
+
+impl ApiEventMetric for PaymentListConstraints {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::ResourceListAPI)
+ }
+}
+
+impl ApiEventMetric for PaymentListResponse {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::ResourceListAPI)
+ }
+}
+
+impl ApiEventMetric for PaymentListResponseV2 {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::ResourceListAPI)
+ }
+}
+
+impl ApiEventMetric for RedirectionResponse {}
diff --git a/crates/api_models/src/events/payouts.rs b/crates/api_models/src/events/payouts.rs
new file mode 100644
index 000000000000..303709acc476
--- /dev/null
+++ b/crates/api_models/src/events/payouts.rs
@@ -0,0 +1,29 @@
+use common_utils::events::{ApiEventMetric, ApiEventsType};
+
+use crate::payouts::{
+ PayoutActionRequest, PayoutCreateRequest, PayoutCreateResponse, PayoutRetrieveRequest,
+};
+
+impl ApiEventMetric for PayoutRetrieveRequest {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Payout)
+ }
+}
+
+impl ApiEventMetric for PayoutCreateRequest {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Payout)
+ }
+}
+
+impl ApiEventMetric for PayoutCreateResponse {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Payout)
+ }
+}
+
+impl ApiEventMetric for PayoutActionRequest {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Payout)
+ }
+}
diff --git a/crates/api_models/src/events/refund.rs b/crates/api_models/src/events/refund.rs
new file mode 100644
index 000000000000..424a3191db66
--- /dev/null
+++ b/crates/api_models/src/events/refund.rs
@@ -0,0 +1,63 @@
+use common_utils::events::{ApiEventMetric, ApiEventsType};
+
+use crate::refunds::{
+ RefundListMetaData, RefundListRequest, RefundListResponse, RefundRequest, RefundResponse,
+ RefundUpdateRequest, RefundsRetrieveRequest,
+};
+
+impl ApiEventMetric for RefundRequest {
+ fn get_api_event_type(&self) -> Option {
+ let payment_id = self.payment_id.clone();
+ self.refund_id
+ .clone()
+ .map(|refund_id| ApiEventsType::Refund {
+ payment_id: Some(payment_id),
+ refund_id,
+ })
+ }
+}
+
+impl ApiEventMetric for RefundResponse {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Refund {
+ payment_id: Some(self.payment_id.clone()),
+ refund_id: self.refund_id.clone(),
+ })
+ }
+}
+
+impl ApiEventMetric for RefundsRetrieveRequest {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Refund {
+ payment_id: None,
+ refund_id: self.refund_id.clone(),
+ })
+ }
+}
+
+impl ApiEventMetric for RefundUpdateRequest {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Refund {
+ payment_id: None,
+ refund_id: self.refund_id.clone(),
+ })
+ }
+}
+
+impl ApiEventMetric for RefundListRequest {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::ResourceListAPI)
+ }
+}
+
+impl ApiEventMetric for RefundListResponse {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::ResourceListAPI)
+ }
+}
+
+impl ApiEventMetric for RefundListMetaData {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::ResourceListAPI)
+ }
+}
diff --git a/crates/api_models/src/events/routing.rs b/crates/api_models/src/events/routing.rs
new file mode 100644
index 000000000000..5eca01acc6fb
--- /dev/null
+++ b/crates/api_models/src/events/routing.rs
@@ -0,0 +1,58 @@
+use common_utils::events::{ApiEventMetric, ApiEventsType};
+
+use crate::routing::{
+ LinkedRoutingConfigRetrieveResponse, MerchantRoutingAlgorithm, RoutingAlgorithmId,
+ RoutingConfigRequest, RoutingDictionaryRecord, RoutingKind,
+};
+#[cfg(feature = "business_profile_routing")]
+use crate::routing::{RoutingRetrieveLinkQuery, RoutingRetrieveQuery};
+
+impl ApiEventMetric for RoutingKind {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Routing)
+ }
+}
+
+impl ApiEventMetric for MerchantRoutingAlgorithm {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Routing)
+ }
+}
+
+impl ApiEventMetric for RoutingAlgorithmId {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Routing)
+ }
+}
+
+impl ApiEventMetric for RoutingDictionaryRecord {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Routing)
+ }
+}
+
+impl ApiEventMetric for LinkedRoutingConfigRetrieveResponse {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Routing)
+ }
+}
+
+#[cfg(feature = "business_profile_routing")]
+impl ApiEventMetric for RoutingRetrieveQuery {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Routing)
+ }
+}
+
+impl ApiEventMetric for RoutingConfigRequest {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Routing)
+ }
+}
+
+#[cfg(feature = "business_profile_routing")]
+impl ApiEventMetric for RoutingRetrieveLinkQuery {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Routing)
+ }
+}
diff --git a/crates/api_models/src/gsm.rs b/crates/api_models/src/gsm.rs
new file mode 100644
index 000000000000..6bd8fd99dd93
--- /dev/null
+++ b/crates/api_models/src/gsm.rs
@@ -0,0 +1,75 @@
+use crate::enums;
+
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct GsmCreateRequest {
+ pub connector: enums::Connector,
+ pub flow: String,
+ pub sub_flow: String,
+ pub code: String,
+ pub message: String,
+ pub status: String,
+ pub router_error: Option,
+ pub decision: GsmDecision,
+ pub step_up_possible: bool,
+}
+
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct GsmRetrieveRequest {
+ pub connector: enums::Connector,
+ pub flow: String,
+ pub sub_flow: String,
+ pub code: String,
+ pub message: String,
+}
+
+#[derive(
+ Default,
+ Clone,
+ Copy,
+ Debug,
+ strum::Display,
+ PartialEq,
+ Eq,
+ serde::Serialize,
+ serde::Deserialize,
+ strum::EnumString,
+)]
+#[serde(rename_all = "snake_case")]
+#[strum(serialize_all = "snake_case")]
+pub enum GsmDecision {
+ Retry,
+ Requeue,
+ #[default]
+ DoDefault,
+}
+
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct GsmUpdateRequest {
+ pub connector: String,
+ pub flow: String,
+ pub sub_flow: String,
+ pub code: String,
+ pub message: String,
+ pub status: Option,
+ pub router_error: Option,
+ pub decision: Option,
+ pub step_up_possible: Option,
+}
+
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct GsmDeleteRequest {
+ pub connector: String,
+ pub flow: String,
+ pub sub_flow: String,
+ pub code: String,
+ pub message: String,
+}
+
+#[derive(Debug, serde::Serialize)]
+pub struct GsmDeleteResponse {
+ pub gsm_rule_delete: bool,
+ pub connector: String,
+ pub flow: String,
+ pub sub_flow: String,
+ pub code: String,
+}
diff --git a/crates/api_models/src/lib.rs b/crates/api_models/src/lib.rs
index dab1b46adbad..5da916b14817 100644
--- a/crates/api_models/src/lib.rs
+++ b/crates/api_models/src/lib.rs
@@ -9,7 +9,9 @@ pub mod enums;
pub mod ephemeral_key;
#[cfg(feature = "errors")]
pub mod errors;
+pub mod events;
pub mod files;
+pub mod gsm;
pub mod mandates;
pub mod organization;
pub mod payment_methods;
@@ -17,5 +19,6 @@ pub mod payments;
#[cfg(feature = "payouts")]
pub mod payouts;
pub mod refunds;
+pub mod routing;
pub mod verifications;
pub mod webhooks;
diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs
index b30590bfd6f2..289f652981eb 100644
--- a/crates/api_models/src/payment_methods.rs
+++ b/crates/api_models/src/payment_methods.rs
@@ -12,7 +12,9 @@ use utoipa::ToSchema;
#[cfg(feature = "payouts")]
use crate::payouts;
use crate::{
- admin, enums as api_enums,
+ admin,
+ customers::CustomerId,
+ enums as api_enums,
payments::{self, BankCodeResponse},
};
@@ -167,6 +169,8 @@ pub struct CardDetailsPaymentMethod {
pub struct PaymentMethodDataBankCreds {
pub mask: String,
pub hash: String,
+ pub account_type: Option,
+ pub account_name: Option,
pub payment_method_type: api_enums::PaymentMethodType,
pub connector_details: Vec,
}
@@ -474,6 +478,8 @@ pub struct RequestPaymentMethodTypes {
#[derive(Debug, Clone, serde::Serialize, Default, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct PaymentMethodListRequest {
+ #[serde(skip_deserializing)]
+ pub customer_id: Option,
/// This is a 15 minute expiry token which shall be used from the client to authenticate and perform sessions from the SDK
#[schema(max_length = 30, min_length = 30, example = "secret_k2uj3he2893ein2d")]
pub client_secret: Option,
diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs
index f9cb21dae5f2..22579ed6d6ea 100644
--- a/crates/api_models/src/payments.rs
+++ b/crates/api_models/src/payments.rs
@@ -2232,7 +2232,9 @@ pub struct PaymentListFilters {
pub authentication_type: Vec,
}
-#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, PartialEq, Eq, Hash)]
+#[derive(
+ Debug, Clone, Copy, serde::Serialize, serde::Deserialize, PartialEq, Eq, Hash, ToSchema,
+)]
pub struct TimeRange {
/// The start time to filter payments list or to get list of filters. To get list of filters start time is needed to be passed
#[serde(with = "common_utils::custom_serde::iso8601")]
@@ -3098,6 +3100,8 @@ pub struct PaymentLinkObject {
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
pub link_expiry: Option,
pub merchant_custom_domain_name: Option,
+ /// Custom merchant name for payment link
+ pub custom_merchant_name: Option,
}
#[derive(Default, Debug, serde::Deserialize, Clone, ToSchema, serde::Serialize)]
@@ -3141,11 +3145,12 @@ pub struct PaymentLinkDetails {
pub pub_key: String,
pub client_secret: String,
pub payment_id: String,
- #[serde(with = "common_utils::custom_serde::iso8601")]
- pub expiry: PrimitiveDateTime,
+ #[serde(with = "common_utils::custom_serde::iso8601::option")]
+ pub expiry: Option,
pub merchant_logo: String,
pub return_url: String,
- pub merchant_name: crypto::OptionalEncryptableName,
- pub order_details: Vec,
+ pub merchant_name: String,
+ pub order_details: Option>,
pub max_items_visible_after_collapse: i8,
+ pub sdk_theme: Option,
}
diff --git a/crates/api_models/src/refunds.rs b/crates/api_models/src/refunds.rs
index 7b4eae4238ac..6fe8be8b5291 100644
--- a/crates/api_models/src/refunds.rs
+++ b/crates/api_models/src/refunds.rs
@@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
use time::PrimitiveDateTime;
use utoipa::ToSchema;
+use super::payments::TimeRange;
use crate::{admin, enums};
#[derive(Default, Debug, ToSchema, Clone, Deserialize, Serialize)]
@@ -75,6 +76,8 @@ pub struct RefundsRetrieveRequest {
#[derive(Default, Debug, ToSchema, Clone, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct RefundUpdateRequest {
+ #[serde(skip)]
+ pub refund_id: String,
/// An arbitrary string attached to the object. Often useful for displaying to users and your customer support executive
#[schema(max_length = 255, example = "Customer returned the product")]
pub reason: Option,
@@ -152,16 +155,6 @@ pub struct RefundListRequest {
pub refund_status: Option>,
}
-#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash, ToSchema)]
-pub struct TimeRange {
- /// The start time to filter refunds list or to get list of filters. To get list of filters start time is needed to be passed
- #[serde(with = "common_utils::custom_serde::iso8601")]
- pub start_time: PrimitiveDateTime,
- /// The end time to filter refunds list or to get list of filters. If not passed the default time is now
- #[serde(default, with = "common_utils::custom_serde::iso8601::option")]
- pub end_time: Option,
-}
-
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, ToSchema)]
pub struct RefundListResponse {
/// The number of refunds included in the list
diff --git a/crates/api_models/src/routing.rs b/crates/api_models/src/routing.rs
new file mode 100644
index 000000000000..425ca364191d
--- /dev/null
+++ b/crates/api_models/src/routing.rs
@@ -0,0 +1,599 @@
+use std::fmt::Debug;
+
+use common_utils::errors::ParsingError;
+use error_stack::IntoReport;
+use euclid::{
+ dssa::types::EuclidAnalysable,
+ enums as euclid_enums,
+ frontend::{
+ ast,
+ dir::{DirKeyKind, EuclidDirFilter},
+ },
+};
+use serde::{Deserialize, Serialize};
+
+use crate::enums::{self, RoutableConnectors};
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[serde(tag = "type", content = "data", rename_all = "snake_case")]
+pub enum ConnectorSelection {
+ Priority(Vec),
+ VolumeSplit(Vec),
+}
+
+impl ConnectorSelection {
+ pub fn get_connector_list(&self) -> Vec {
+ match self {
+ Self::Priority(list) => list.clone(),
+ Self::VolumeSplit(splits) => {
+ splits.iter().map(|split| split.connector.clone()).collect()
+ }
+ }
+ }
+}
+
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+pub struct RoutingConfigRequest {
+ pub name: Option,
+ pub description: Option,
+ pub algorithm: Option,
+ pub profile_id: Option,
+}
+
+#[cfg(feature = "business_profile_routing")]
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct RoutingRetrieveQuery {
+ pub limit: Option,
+ pub offset: Option,
+
+ pub profile_id: Option,
+}
+
+#[cfg(feature = "business_profile_routing")]
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct RoutingRetrieveLinkQuery {
+ pub profile_id: Option,
+}
+
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+pub struct RoutingRetrieveResponse {
+ pub algorithm: Option,
+}
+
+#[derive(Debug, serde::Serialize)]
+#[serde(untagged)]
+pub enum LinkedRoutingConfigRetrieveResponse {
+ MerchantAccountBased(RoutingRetrieveResponse),
+ ProfileBased(Vec),
+}
+
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+pub struct MerchantRoutingAlgorithm {
+ pub id: String,
+ #[cfg(feature = "business_profile_routing")]
+ pub profile_id: String,
+ pub name: String,
+ pub description: String,
+ pub algorithm: RoutingAlgorithm,
+ pub created_at: i64,
+ pub modified_at: i64,
+}
+
+impl EuclidDirFilter for ConnectorSelection {
+ const ALLOWED: &'static [DirKeyKind] = &[
+ DirKeyKind::PaymentMethod,
+ DirKeyKind::CardBin,
+ DirKeyKind::CardType,
+ DirKeyKind::CardNetwork,
+ DirKeyKind::PayLaterType,
+ DirKeyKind::WalletType,
+ DirKeyKind::UpiType,
+ DirKeyKind::BankRedirectType,
+ DirKeyKind::BankDebitType,
+ DirKeyKind::CryptoType,
+ DirKeyKind::MetaData,
+ DirKeyKind::PaymentAmount,
+ DirKeyKind::PaymentCurrency,
+ DirKeyKind::AuthenticationType,
+ DirKeyKind::MandateAcceptanceType,
+ DirKeyKind::MandateType,
+ DirKeyKind::PaymentType,
+ DirKeyKind::SetupFutureUsage,
+ DirKeyKind::CaptureMethod,
+ DirKeyKind::BillingCountry,
+ DirKeyKind::BusinessCountry,
+ DirKeyKind::BusinessLabel,
+ DirKeyKind::MetaData,
+ DirKeyKind::RewardType,
+ DirKeyKind::VoucherType,
+ DirKeyKind::CardRedirectType,
+ DirKeyKind::BankTransferType,
+ ];
+}
+
+impl EuclidAnalysable for ConnectorSelection {
+ fn get_dir_value_for_analysis(
+ &self,
+ rule_name: String,
+ ) -> Vec<(euclid::frontend::dir::DirValue, euclid::types::Metadata)> {
+ self.get_connector_list()
+ .into_iter()
+ .map(|connector_choice| {
+ let connector_name = connector_choice.connector.to_string();
+ #[cfg(not(feature = "connector_choice_mca_id"))]
+ let sub_label = connector_choice.sub_label.clone();
+ #[cfg(feature = "connector_choice_mca_id")]
+ let mca_id = connector_choice.merchant_connector_id.clone();
+
+ (
+ euclid::frontend::dir::DirValue::Connector(Box::new(connector_choice.into())),
+ std::collections::HashMap::from_iter([(
+ "CONNECTOR_SELECTION".to_string(),
+ #[cfg(feature = "connector_choice_mca_id")]
+ serde_json::json!({
+ "rule_name": rule_name,
+ "connector_name": connector_name,
+ "mca_id": mca_id,
+ }),
+ #[cfg(not(feature = "connector_choice_mca_id"))]
+ serde_json ::json!({
+ "rule_name": rule_name,
+ "connector_name": connector_name,
+ "sub_label": sub_label,
+ }),
+ )]),
+ )
+ })
+ .collect()
+ }
+}
+
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+pub struct ConnectorVolumeSplit {
+ pub connector: RoutableConnectorChoice,
+ pub split: u8,
+}
+
+#[cfg(feature = "connector_choice_bcompat")]
+#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
+pub enum RoutableChoiceKind {
+ OnlyConnector,
+ FullStruct,
+}
+
+#[cfg(feature = "connector_choice_bcompat")]
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+#[serde(untagged)]
+pub enum RoutableChoiceSerde {
+ OnlyConnector(Box),
+ FullStruct {
+ connector: RoutableConnectors,
+ #[cfg(feature = "connector_choice_mca_id")]
+ merchant_connector_id: Option,
+ #[cfg(not(feature = "connector_choice_mca_id"))]
+ sub_label: Option,
+ },
+}
+
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+#[cfg_attr(
+ feature = "connector_choice_bcompat",
+ serde(from = "RoutableChoiceSerde"),
+ serde(into = "RoutableChoiceSerde")
+)]
+#[cfg_attr(not(feature = "connector_choice_bcompat"), derive(PartialEq, Eq))]
+pub struct RoutableConnectorChoice {
+ #[cfg(feature = "connector_choice_bcompat")]
+ pub choice_kind: RoutableChoiceKind,
+ pub connector: RoutableConnectors,
+ #[cfg(feature = "connector_choice_mca_id")]
+ pub merchant_connector_id: Option,
+ #[cfg(not(feature = "connector_choice_mca_id"))]
+ pub sub_label: Option,
+}
+
+impl ToString for RoutableConnectorChoice {
+ fn to_string(&self) -> String {
+ #[cfg(feature = "connector_choice_mca_id")]
+ let base = self.connector.to_string();
+
+ #[cfg(not(feature = "connector_choice_mca_id"))]
+ let base = {
+ let mut sub_base = self.connector.to_string();
+ if let Some(ref label) = self.sub_label {
+ sub_base.push('_');
+ sub_base.push_str(label);
+ }
+
+ sub_base
+ };
+
+ base
+ }
+}
+
+#[cfg(feature = "connector_choice_bcompat")]
+impl PartialEq for RoutableConnectorChoice {
+ fn eq(&self, other: &Self) -> bool {
+ #[cfg(not(feature = "connector_choice_mca_id"))]
+ {
+ self.connector.eq(&other.connector) && self.sub_label.eq(&other.sub_label)
+ }
+
+ #[cfg(feature = "connector_choice_mca_id")]
+ {
+ self.connector.eq(&other.connector)
+ && self.merchant_connector_id.eq(&other.merchant_connector_id)
+ }
+ }
+}
+
+#[cfg(feature = "connector_choice_bcompat")]
+impl Eq for RoutableConnectorChoice {}
+
+#[cfg(feature = "connector_choice_bcompat")]
+impl From for RoutableConnectorChoice {
+ fn from(value: RoutableChoiceSerde) -> Self {
+ match value {
+ RoutableChoiceSerde::OnlyConnector(connector) => Self {
+ choice_kind: RoutableChoiceKind::OnlyConnector,
+ connector: *connector,
+ #[cfg(feature = "connector_choice_mca_id")]
+ merchant_connector_id: None,
+ #[cfg(not(feature = "connector_choice_mca_id"))]
+ sub_label: None,
+ },
+
+ RoutableChoiceSerde::FullStruct {
+ connector,
+ #[cfg(feature = "connector_choice_mca_id")]
+ merchant_connector_id,
+ #[cfg(not(feature = "connector_choice_mca_id"))]
+ sub_label,
+ } => Self {
+ choice_kind: RoutableChoiceKind::FullStruct,
+ connector,
+ #[cfg(feature = "connector_choice_mca_id")]
+ merchant_connector_id,
+ #[cfg(not(feature = "connector_choice_mca_id"))]
+ sub_label,
+ },
+ }
+ }
+}
+
+#[cfg(feature = "connector_choice_bcompat")]
+impl From for RoutableChoiceSerde {
+ fn from(value: RoutableConnectorChoice) -> Self {
+ match value.choice_kind {
+ RoutableChoiceKind::OnlyConnector => Self::OnlyConnector(Box::new(value.connector)),
+ RoutableChoiceKind::FullStruct => Self::FullStruct {
+ connector: value.connector,
+ #[cfg(feature = "connector_choice_mca_id")]
+ merchant_connector_id: value.merchant_connector_id,
+ #[cfg(not(feature = "connector_choice_mca_id"))]
+ sub_label: value.sub_label,
+ },
+ }
+ }
+}
+
+impl From for ast::ConnectorChoice {
+ fn from(value: RoutableConnectorChoice) -> Self {
+ Self {
+ connector: match value.connector {
+ #[cfg(feature = "dummy_connector")]
+ RoutableConnectors::DummyConnector1 => euclid_enums::Connector::DummyConnector1,
+ #[cfg(feature = "dummy_connector")]
+ RoutableConnectors::DummyConnector2 => euclid_enums::Connector::DummyConnector2,
+ #[cfg(feature = "dummy_connector")]
+ RoutableConnectors::DummyConnector3 => euclid_enums::Connector::DummyConnector3,
+ #[cfg(feature = "dummy_connector")]
+ RoutableConnectors::DummyConnector4 => euclid_enums::Connector::DummyConnector4,
+ #[cfg(feature = "dummy_connector")]
+ RoutableConnectors::DummyConnector5 => euclid_enums::Connector::DummyConnector5,
+ #[cfg(feature = "dummy_connector")]
+ RoutableConnectors::DummyConnector6 => euclid_enums::Connector::DummyConnector6,
+ #[cfg(feature = "dummy_connector")]
+ RoutableConnectors::DummyConnector7 => euclid_enums::Connector::DummyConnector7,
+ RoutableConnectors::Aci => euclid_enums::Connector::Aci,
+ RoutableConnectors::Adyen => euclid_enums::Connector::Adyen,
+ RoutableConnectors::Airwallex => euclid_enums::Connector::Airwallex,
+ RoutableConnectors::Authorizedotnet => euclid_enums::Connector::Authorizedotnet,
+ RoutableConnectors::Bitpay => euclid_enums::Connector::Bitpay,
+ RoutableConnectors::Bambora => euclid_enums::Connector::Bambora,
+ RoutableConnectors::Bluesnap => euclid_enums::Connector::Bluesnap,
+ RoutableConnectors::Boku => euclid_enums::Connector::Boku,
+ RoutableConnectors::Braintree => euclid_enums::Connector::Braintree,
+ RoutableConnectors::Cashtocode => euclid_enums::Connector::Cashtocode,
+ RoutableConnectors::Checkout => euclid_enums::Connector::Checkout,
+ RoutableConnectors::Coinbase => euclid_enums::Connector::Coinbase,
+ RoutableConnectors::Cryptopay => euclid_enums::Connector::Cryptopay,
+ RoutableConnectors::Cybersource => euclid_enums::Connector::Cybersource,
+ RoutableConnectors::Dlocal => euclid_enums::Connector::Dlocal,
+ RoutableConnectors::Fiserv => euclid_enums::Connector::Fiserv,
+ RoutableConnectors::Forte => euclid_enums::Connector::Forte,
+ RoutableConnectors::Globalpay => euclid_enums::Connector::Globalpay,
+ RoutableConnectors::Globepay => euclid_enums::Connector::Globepay,
+ RoutableConnectors::Gocardless => euclid_enums::Connector::Gocardless,
+ RoutableConnectors::Helcim => euclid_enums::Connector::Helcim,
+ RoutableConnectors::Iatapay => euclid_enums::Connector::Iatapay,
+ RoutableConnectors::Klarna => euclid_enums::Connector::Klarna,
+ RoutableConnectors::Mollie => euclid_enums::Connector::Mollie,
+ RoutableConnectors::Multisafepay => euclid_enums::Connector::Multisafepay,
+ RoutableConnectors::Nexinets => euclid_enums::Connector::Nexinets,
+ RoutableConnectors::Nmi => euclid_enums::Connector::Nmi,
+ RoutableConnectors::Noon => euclid_enums::Connector::Noon,
+ RoutableConnectors::Nuvei => euclid_enums::Connector::Nuvei,
+ RoutableConnectors::Opennode => euclid_enums::Connector::Opennode,
+ RoutableConnectors::Payme => euclid_enums::Connector::Payme,
+ RoutableConnectors::Paypal => euclid_enums::Connector::Paypal,
+ RoutableConnectors::Payu => euclid_enums::Connector::Payu,
+ RoutableConnectors::Powertranz => euclid_enums::Connector::Powertranz,
+ RoutableConnectors::Rapyd => euclid_enums::Connector::Rapyd,
+ RoutableConnectors::Shift4 => euclid_enums::Connector::Shift4,
+ RoutableConnectors::Square => euclid_enums::Connector::Square,
+ RoutableConnectors::Stax => euclid_enums::Connector::Stax,
+ RoutableConnectors::Stripe => euclid_enums::Connector::Stripe,
+ RoutableConnectors::Trustpay => euclid_enums::Connector::Trustpay,
+ RoutableConnectors::Tsys => euclid_enums::Connector::Tsys,
+ RoutableConnectors::Volt => euclid_enums::Connector::Volt,
+ RoutableConnectors::Wise => euclid_enums::Connector::Wise,
+ RoutableConnectors::Worldline => euclid_enums::Connector::Worldline,
+ RoutableConnectors::Worldpay => euclid_enums::Connector::Worldpay,
+ RoutableConnectors::Zen => euclid_enums::Connector::Zen,
+ },
+
+ #[cfg(not(feature = "connector_choice_mca_id"))]
+ sub_label: value.sub_label,
+ }
+ }
+}
+
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+pub struct DetailedConnectorChoice {
+ pub connector: RoutableConnectors,
+ pub business_label: Option,
+ pub business_country: Option,
+ pub business_sub_label: Option,
+}
+
+impl DetailedConnectorChoice {
+ pub fn get_connector_label(&self) -> Option {
+ self.business_country
+ .as_ref()
+ .zip(self.business_label.as_ref())
+ .map(|(business_country, business_label)| {
+ let mut base_label = format!(
+ "{}_{:?}_{}",
+ self.connector, business_country, business_label
+ );
+
+ if let Some(ref sub_label) = self.business_sub_label {
+ base_label.push('_');
+ base_label.push_str(sub_label);
+ }
+
+ base_label
+ })
+ }
+}
+
+#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, strum::Display)]
+#[serde(rename_all = "snake_case")]
+#[strum(serialize_all = "snake_case")]
+pub enum RoutingAlgorithmKind {
+ Single,
+ Priority,
+ VolumeSplit,
+ Advanced,
+}
+
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+#[serde(
+ tag = "type",
+ content = "data",
+ rename_all = "snake_case",
+ try_from = "RoutingAlgorithmSerde"
+)]
+pub enum RoutingAlgorithm {
+ Single(Box),
+ Priority(Vec),
+ VolumeSplit(Vec),
+ Advanced(euclid::frontend::ast::Program),
+}
+
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+#[serde(tag = "type", content = "data", rename_all = "snake_case")]
+pub enum RoutingAlgorithmSerde {
+ Single(Box),
+ Priority(Vec),
+ VolumeSplit(Vec),
+ Advanced(euclid::frontend::ast::Program),
+}
+
+impl TryFrom for RoutingAlgorithm {
+ type Error = error_stack::Report;
+
+ fn try_from(value: RoutingAlgorithmSerde) -> Result {
+ match &value {
+ RoutingAlgorithmSerde::Priority(i) if i.is_empty() => {
+ Err(ParsingError::StructParseFailure(
+ "Connectors list can't be empty for Priority Algorithm",
+ ))
+ .into_report()?
+ }
+ RoutingAlgorithmSerde::VolumeSplit(i) if i.is_empty() => {
+ Err(ParsingError::StructParseFailure(
+ "Connectors list can't be empty for Volume split Algorithm",
+ ))
+ .into_report()?
+ }
+ _ => {}
+ };
+ Ok(match value {
+ RoutingAlgorithmSerde::Single(i) => Self::Single(i),
+ RoutingAlgorithmSerde::Priority(i) => Self::Priority(i),
+ RoutingAlgorithmSerde::VolumeSplit(i) => Self::VolumeSplit(i),
+ RoutingAlgorithmSerde::Advanced(i) => Self::Advanced(i),
+ })
+ }
+}
+
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+#[serde(
+ tag = "type",
+ content = "data",
+ rename_all = "snake_case",
+ try_from = "StraightThroughAlgorithmSerde",
+ into = "StraightThroughAlgorithmSerde"
+)]
+pub enum StraightThroughAlgorithm {
+ Single(Box),
+ Priority(Vec),
+ VolumeSplit(Vec),
+}
+
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+#[serde(tag = "type", content = "data", rename_all = "snake_case")]
+pub enum StraightThroughAlgorithmInner {
+ Single(Box),
+ Priority(Vec),
+ VolumeSplit(Vec),
+}
+
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+#[serde(untagged)]
+pub enum StraightThroughAlgorithmSerde {
+ Direct(StraightThroughAlgorithmInner),
+ Nested {
+ algorithm: StraightThroughAlgorithmInner,
+ },
+}
+
+impl TryFrom for StraightThroughAlgorithm {
+ type Error = error_stack::Report;
+
+ fn try_from(value: StraightThroughAlgorithmSerde) -> Result {
+ let inner = match value {
+ StraightThroughAlgorithmSerde::Direct(algorithm) => algorithm,
+ StraightThroughAlgorithmSerde::Nested { algorithm } => algorithm,
+ };
+
+ match &inner {
+ StraightThroughAlgorithmInner::Priority(i) if i.is_empty() => {
+ Err(ParsingError::StructParseFailure(
+ "Connectors list can't be empty for Priority Algorithm",
+ ))
+ .into_report()?
+ }
+ StraightThroughAlgorithmInner::VolumeSplit(i) if i.is_empty() => {
+ Err(ParsingError::StructParseFailure(
+ "Connectors list can't be empty for Volume split Algorithm",
+ ))
+ .into_report()?
+ }
+ _ => {}
+ };
+
+ Ok(match inner {
+ StraightThroughAlgorithmInner::Single(single) => Self::Single(single),
+ StraightThroughAlgorithmInner::Priority(plist) => Self::Priority(plist),
+ StraightThroughAlgorithmInner::VolumeSplit(vsplit) => Self::VolumeSplit(vsplit),
+ })
+ }
+}
+
+impl From for StraightThroughAlgorithmSerde {
+ fn from(value: StraightThroughAlgorithm) -> Self {
+ let inner = match value {
+ StraightThroughAlgorithm::Single(conn) => StraightThroughAlgorithmInner::Single(conn),
+ StraightThroughAlgorithm::Priority(plist) => {
+ StraightThroughAlgorithmInner::Priority(plist)
+ }
+ StraightThroughAlgorithm::VolumeSplit(vsplit) => {
+ StraightThroughAlgorithmInner::VolumeSplit(vsplit)
+ }
+ };
+
+ Self::Nested { algorithm: inner }
+ }
+}
+
+impl From for RoutingAlgorithm {
+ fn from(value: StraightThroughAlgorithm) -> Self {
+ match value {
+ StraightThroughAlgorithm::Single(conn) => Self::Single(conn),
+ StraightThroughAlgorithm::Priority(conns) => Self::Priority(conns),
+ StraightThroughAlgorithm::VolumeSplit(splits) => Self::VolumeSplit(splits),
+ }
+ }
+}
+
+impl RoutingAlgorithm {
+ pub fn get_kind(&self) -> RoutingAlgorithmKind {
+ match self {
+ Self::Single(_) => RoutingAlgorithmKind::Single,
+ Self::Priority(_) => RoutingAlgorithmKind::Priority,
+ Self::VolumeSplit(_) => RoutingAlgorithmKind::VolumeSplit,
+ Self::Advanced(_) => RoutingAlgorithmKind::Advanced,
+ }
+ }
+}
+
+#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
+pub struct RoutingAlgorithmRef {
+ pub algorithm_id: Option,
+ pub timestamp: i64,
+ pub config_algo_id: Option,
+ pub surcharge_config_algo_id: Option,
+}
+
+impl RoutingAlgorithmRef {
+ pub fn update_algorithm_id(&mut self, new_id: String) {
+ self.algorithm_id = Some(new_id);
+ self.timestamp = common_utils::date_time::now_unix_timestamp();
+ }
+
+ pub fn update_conditional_config_id(&mut self, ids: String) {
+ self.config_algo_id = Some(ids);
+ self.timestamp = common_utils::date_time::now_unix_timestamp();
+ }
+
+ pub fn update_surcharge_config_id(&mut self, ids: String) {
+ self.surcharge_config_algo_id = Some(ids);
+ self.timestamp = common_utils::date_time::now_unix_timestamp();
+ }
+}
+
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+
+pub struct RoutingDictionaryRecord {
+ pub id: String,
+ #[cfg(feature = "business_profile_routing")]
+ pub profile_id: String,
+ pub name: String,
+ pub kind: RoutingAlgorithmKind,
+ pub description: String,
+ pub created_at: i64,
+ pub modified_at: i64,
+}
+
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+pub struct RoutingDictionary {
+ pub merchant_id: String,
+ pub active_id: Option,
+ pub records: Vec,
+}
+
+#[derive(serde::Serialize, serde::Deserialize, Debug)]
+#[serde(untagged)]
+pub enum RoutingKind {
+ Config(RoutingDictionary),
+ RoutingAlgorithm(Vec),
+}
+
+#[repr(transparent)]
+#[derive(serde::Serialize, serde::Deserialize, Debug)]
+#[serde(transparent)]
+pub struct RoutingAlgorithmId(pub String);
diff --git a/crates/common_enums/Cargo.toml b/crates/common_enums/Cargo.toml
index 10b4fb509e88..db37d27ab0f1 100644
--- a/crates/common_enums/Cargo.toml
+++ b/crates/common_enums/Cargo.toml
@@ -12,14 +12,13 @@ dummy_connector = []
[dependencies]
diesel = { version = "2.1.0", features = ["postgres"] }
-serde = { version = "1.0.160", features = [ "derive" ] }
+serde = { version = "1.0.160", features = ["derive"] }
serde_json = "1.0.96"
-strum = { version = "0.25", features = [ "derive" ] }
+strum = { version = "0.25", features = ["derive"] }
time = { version = "0.3.21", features = ["serde", "serde-well-known", "std"] }
utoipa = { version = "3.3.0", features = ["preserve_order"] }
# First party crates
-common_utils = { version = "0.1.0", path = "../common_utils" }
router_derive = { version = "0.1.0", path = "../router_derive" }
[dev-dependencies]
diff --git a/crates/common_utils/Cargo.toml b/crates/common_utils/Cargo.toml
index e319cf86ccd0..62bd747da1b0 100644
--- a/crates/common_utils/Cargo.toml
+++ b/crates/common_utils/Cargo.toml
@@ -28,6 +28,7 @@ rand = "0.8.5"
regex = "1.8.4"
reqwest = { version = "0.11.18", features = ["json", "native-tls", "gzip", "multipart"] }
ring = { version = "0.16.20", features = ["std"] }
+rustc-hash = "1.1.0"
serde = { version = "1.0.163", features = ["derive"] }
serde_json = "1.0.96"
serde_urlencoded = "0.7.1"
@@ -41,6 +42,7 @@ phonenumber = "0.3.3"
# First party crates
masking = { version = "0.1.0", path = "../masking" }
router_env = { version = "0.1.0", path = "../router_env", features = ["log_extra_implicit_fields", "log_custom_entries_to_extra"], optional = true }
+common_enums = { version = "0.1.0", path = "../common_enums" }
[target.'cfg(not(target_os = "windows"))'.dependencies]
signal-hook-tokio = { version = "0.3.1", features = ["futures-v0_3"], optional = true }
diff --git a/crates/common_utils/src/consts.rs b/crates/common_utils/src/consts.rs
index 2f517295ae48..7bc248bf8d1b 100644
--- a/crates/common_utils/src/consts.rs
+++ b/crates/common_utils/src/consts.rs
@@ -29,3 +29,15 @@ pub const SURCHARGE_PERCENTAGE_PRECISION_LENGTH: u8 = 2;
/// Header Key for application overhead of a request
pub const X_HS_LATENCY: &str = "x-hs-latency";
+
+/// SDK Default Theme const
+pub const DEFAULT_SDK_THEME: &str = "#7EA8F6";
+
+/// Default Payment Link Background color
+pub const DEFAULT_BACKGROUND_COLOR: &str = "#E5E5E5";
+
+/// Default product Img Link
+pub const DEFAULT_PRODUCT_IMG: &str = "https://i.imgur.com/On3VtKF.png";
+
+/// Default Merchant Logo Link
+pub const DEFAULT_MERCHANT_LOGO: &str = "https://i.imgur.com/RfxPFQo.png";
diff --git a/crates/common_utils/src/events.rs b/crates/common_utils/src/events.rs
new file mode 100644
index 000000000000..8c52f6c36d63
--- /dev/null
+++ b/crates/common_utils/src/events.rs
@@ -0,0 +1,92 @@
+use common_enums::{PaymentMethod, PaymentMethodType};
+use serde::Serialize;
+
+pub trait ApiEventMetric {
+ fn get_api_event_type(&self) -> Option {
+ None
+ }
+}
+
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
+#[serde(tag = "flow_type")]
+pub enum ApiEventsType {
+ Payout,
+ Payment {
+ payment_id: String,
+ },
+ Refund {
+ payment_id: Option,
+ refund_id: String,
+ },
+ PaymentMethod {
+ payment_method_id: String,
+ payment_method: Option,
+ payment_method_type: Option,
+ },
+ Customer {
+ customer_id: String,
+ },
+ User {
+ //specified merchant_id will overridden on global defined
+ merchant_id: String,
+ user_id: String,
+ },
+ PaymentMethodList {
+ payment_id: Option,
+ },
+ Webhooks {
+ connector: String,
+ payment_id: Option,
+ },
+ Routing,
+ ResourceListAPI,
+ PaymentRedirectionResponse,
+ Gsm,
+ // TODO: This has to be removed once the corresponding apiEventTypes are created
+ Miscellaneous,
+}
+
+impl ApiEventMetric for serde_json::Value {}
+impl ApiEventMetric for () {}
+
+impl ApiEventMetric for Result {
+ fn get_api_event_type(&self) -> Option {
+ match self {
+ Ok(q) => q.get_api_event_type(),
+ Err(_) => None,
+ }
+ }
+}
+
+// TODO: Ideally all these types should be replaced by newtype responses
+impl ApiEventMetric for Vec {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Miscellaneous)
+ }
+}
+
+#[macro_export]
+macro_rules! impl_misc_api_event_type {
+ ($($type:ty),+) => {
+ $(
+ impl ApiEventMetric for $type {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Miscellaneous)
+ }
+ }
+ )+
+ };
+}
+
+impl_misc_api_event_type!(
+ String,
+ (&String, &String),
+ (Option, Option, String),
+ bool
+);
+
+impl ApiEventMetric for &T {
+ fn get_api_event_type(&self) -> Option {
+ T::get_api_event_type(self)
+ }
+}
diff --git a/crates/common_utils/src/lib.rs b/crates/common_utils/src/lib.rs
index ca6bba480063..62428dccfb6a 100644
--- a/crates/common_utils/src/lib.rs
+++ b/crates/common_utils/src/lib.rs
@@ -6,6 +6,8 @@ pub mod consts;
pub mod crypto;
pub mod custom_serde;
pub mod errors;
+#[allow(missing_docs)] // Todo: add docs
+pub mod events;
pub mod ext_traits;
pub mod fp_utils;
pub mod pii;
@@ -13,6 +15,8 @@ pub mod pii;
pub mod request;
#[cfg(feature = "signals")]
pub mod signals;
+#[allow(missing_docs)] // Todo: add docs
+pub mod static_cache;
pub mod types;
pub mod validation;
diff --git a/crates/common_utils/src/static_cache.rs b/crates/common_utils/src/static_cache.rs
new file mode 100644
index 000000000000..ca608fa9a3b5
--- /dev/null
+++ b/crates/common_utils/src/static_cache.rs
@@ -0,0 +1,91 @@
+use std::sync::{Arc, RwLock};
+
+use once_cell::sync::Lazy;
+use rustc_hash::FxHashMap;
+
+#[derive(Debug)]
+pub struct CacheEntry {
+ data: Arc,
+ timestamp: i64,
+}
+
+#[derive(Debug, Clone, thiserror::Error)]
+pub enum CacheError {
+ #[error("Could not acquire the lock for cache entry")]
+ CouldNotAcquireLock,
+ #[error("Entry not found in cache")]
+ EntryNotFound,
+}
+
+#[derive(Debug)]
+pub struct StaticCache {
+ data: Lazy>>>,
+}
+
+impl StaticCache
+where
+ T: Send,
+{
+ pub const fn new() -> Self {
+ Self {
+ data: Lazy::new(|| RwLock::new(FxHashMap::default())),
+ }
+ }
+
+ pub fn present(&self, key: &String) -> Result {
+ let the_map = self
+ .data
+ .read()
+ .map_err(|_| CacheError::CouldNotAcquireLock)?;
+
+ Ok(the_map.get(key).is_some())
+ }
+
+ pub fn expired(&self, key: &String, timestamp: i64) -> Result {
+ let the_map = self
+ .data
+ .read()
+ .map_err(|_| CacheError::CouldNotAcquireLock)?;
+
+ Ok(match the_map.get(key) {
+ None => false,
+ Some(entry) => timestamp > entry.timestamp,
+ })
+ }
+
+ pub fn retrieve(&self, key: &String) -> Result, CacheError> {
+ let the_map = self
+ .data
+ .read()
+ .map_err(|_| CacheError::CouldNotAcquireLock)?;
+
+ let cache_entry = the_map.get(key).ok_or(CacheError::EntryNotFound)?;
+
+ Ok(Arc::clone(&cache_entry.data))
+ }
+
+ pub fn save(&self, key: String, data: T, timestamp: i64) -> Result<(), CacheError> {
+ let mut the_map = self
+ .data
+ .write()
+ .map_err(|_| CacheError::CouldNotAcquireLock)?;
+
+ let entry = CacheEntry {
+ data: Arc::new(data),
+ timestamp,
+ };
+
+ the_map.insert(key, entry);
+ Ok(())
+ }
+
+ pub fn clear(&self) -> Result<(), CacheError> {
+ let mut the_map = self
+ .data
+ .write()
+ .map_err(|_| CacheError::CouldNotAcquireLock)?;
+
+ the_map.clear();
+ Ok(())
+ }
+}
diff --git a/crates/data_models/src/payments/payment_attempt.rs b/crates/data_models/src/payments/payment_attempt.rs
index 734de8fe4a55..cdd41ea9db2d 100644
--- a/crates/data_models/src/payments/payment_attempt.rs
+++ b/crates/data_models/src/payments/payment_attempt.rs
@@ -286,6 +286,8 @@ pub enum PaymentAttemptUpdate {
connector_response_reference_id: Option,
amount_capturable: Option,
updated_by: String,
+ authentication_data: Option,
+ encoded_data: Option,
},
UnresolvedResponseUpdate {
status: storage_enums::AttemptStatus,
diff --git a/crates/diesel_models/src/address.rs b/crates/diesel_models/src/address.rs
index e67f37c90465..03dedfd60d8f 100644
--- a/crates/diesel_models/src/address.rs
+++ b/crates/diesel_models/src/address.rs
@@ -19,7 +19,7 @@ pub struct AddressNew {
pub last_name: Option,
pub phone_number: Option,
pub country_code: Option,
- pub customer_id: String,
+ pub customer_id: Option,
pub merchant_id: String,
pub payment_id: Option,
pub created_at: PrimitiveDateTime,
@@ -45,7 +45,7 @@ pub struct Address {
pub country_code: Option,
pub created_at: PrimitiveDateTime,
pub modified_at: PrimitiveDateTime,
- pub customer_id: String,
+ pub customer_id: Option,
pub merchant_id: String,
pub payment_id: Option,
pub updated_by: String,
diff --git a/crates/diesel_models/src/connector_response.rs b/crates/diesel_models/src/connector_response.rs
deleted file mode 100644
index 863ce28ee0ae..000000000000
--- a/crates/diesel_models/src/connector_response.rs
+++ /dev/null
@@ -1,122 +0,0 @@
-use diesel::{AsChangeset, Identifiable, Insertable, Queryable};
-use serde::{Deserialize, Serialize};
-use time::PrimitiveDateTime;
-
-use crate::schema::connector_response;
-
-#[derive(Clone, Debug, Deserialize, Serialize, Insertable, router_derive::DebugAsDisplay)]
-#[diesel(table_name = connector_response)]
-#[serde(deny_unknown_fields)]
-pub struct ConnectorResponseNew {
- pub payment_id: String,
- pub merchant_id: String,
- pub attempt_id: String,
- #[serde(with = "common_utils::custom_serde::iso8601")]
- pub created_at: PrimitiveDateTime,
- #[serde(with = "common_utils::custom_serde::iso8601")]
- pub modified_at: PrimitiveDateTime,
- pub connector_name: Option,
- pub connector_transaction_id: Option,
- pub authentication_data: Option,
- pub encoded_data: Option,
- pub updated_by: String,
-}
-
-#[derive(Clone, Debug, Deserialize, Serialize, Identifiable, Queryable)]
-#[diesel(table_name = connector_response)]
-pub struct ConnectorResponse {
- pub id: i32,
- pub payment_id: String,
- pub merchant_id: String,
- pub attempt_id: String,
- #[serde(with = "common_utils::custom_serde::iso8601")]
- pub created_at: PrimitiveDateTime,
- #[serde(with = "common_utils::custom_serde::iso8601")]
- pub modified_at: PrimitiveDateTime,
- pub connector_name: Option,
- pub connector_transaction_id: Option,
- pub authentication_data: Option,
- pub encoded_data: Option,
- pub updated_by: String,
-}
-
-#[derive(Clone, Default, Debug, Deserialize, AsChangeset, Serialize)]
-#[diesel(table_name = connector_response)]
-pub struct ConnectorResponseUpdateInternal {
- pub connector_transaction_id: Option,
- pub authentication_data: Option,
- pub modified_at: Option,
- pub encoded_data: Option,
- pub connector_name: Option,
- pub updated_by: String,
-}
-
-#[derive(Clone, Debug, Serialize, Deserialize)]
-pub enum ConnectorResponseUpdate {
- ResponseUpdate {
- connector_transaction_id: Option,
- authentication_data: Option,
- encoded_data: Option,
- connector_name: Option,
- updated_by: String,
- },
- ErrorUpdate {
- connector_name: Option,
- updated_by: String,
- },
-}
-
-impl ConnectorResponseUpdate {
- pub fn apply_changeset(self, source: ConnectorResponse) -> ConnectorResponse {
- let connector_response_update: ConnectorResponseUpdateInternal = self.into();
- ConnectorResponse {
- modified_at: connector_response_update
- .modified_at
- .unwrap_or_else(common_utils::date_time::now),
- connector_name: connector_response_update
- .connector_name
- .or(source.connector_name),
- connector_transaction_id: source
- .connector_transaction_id
- .or(connector_response_update.connector_transaction_id),
- authentication_data: connector_response_update
- .authentication_data
- .or(source.authentication_data),
- encoded_data: connector_response_update
- .encoded_data
- .or(source.encoded_data),
- updated_by: connector_response_update.updated_by,
- ..source
- }
- }
-}
-
-impl From for ConnectorResponseUpdateInternal {
- fn from(connector_response_update: ConnectorResponseUpdate) -> Self {
- match connector_response_update {
- ConnectorResponseUpdate::ResponseUpdate {
- connector_transaction_id,
- authentication_data,
- encoded_data,
- connector_name,
- updated_by,
- } => Self {
- connector_transaction_id,
- authentication_data,
- encoded_data,
- modified_at: Some(common_utils::date_time::now()),
- connector_name,
- updated_by,
- },
- ConnectorResponseUpdate::ErrorUpdate {
- connector_name,
- updated_by,
- } => Self {
- connector_name,
- modified_at: Some(common_utils::date_time::now()),
- updated_by,
- ..Self::default()
- },
- }
- }
-}
diff --git a/crates/diesel_models/src/enums.rs b/crates/diesel_models/src/enums.rs
index b73eeefbb10b..ec021f0f51a5 100644
--- a/crates/diesel_models/src/enums.rs
+++ b/crates/diesel_models/src/enums.rs
@@ -14,6 +14,7 @@ pub mod diesel_exports {
DbPaymentType as PaymentType, DbPayoutStatus as PayoutStatus, DbPayoutType as PayoutType,
DbProcessTrackerStatus as ProcessTrackerStatus, DbReconStatus as ReconStatus,
DbRefundStatus as RefundStatus, DbRefundType as RefundType,
+ DbRoutingAlgorithmKind as RoutingAlgorithmKind,
};
}
pub use common_enums::*;
@@ -21,6 +22,27 @@ use common_utils::pii;
use diesel::serialize::{Output, ToSql};
use time::PrimitiveDateTime;
+#[derive(
+ Clone,
+ Copy,
+ Debug,
+ Eq,
+ PartialEq,
+ serde::Deserialize,
+ serde::Serialize,
+ strum::Display,
+ strum::EnumString,
+)]
+#[router_derive::diesel_enum(storage_type = "pg_enum")]
+#[serde(rename_all = "snake_case")]
+#[strum(serialize_all = "snake_case")]
+pub enum RoutingAlgorithmKind {
+ Single,
+ Priority,
+ VolumeSplit,
+ Advanced,
+}
+
#[derive(
Clone,
Copy,
@@ -379,3 +401,25 @@ pub enum FraudCheckLastStep {
TransactionOrRecordRefund,
Fulfillment,
}
+
+#[derive(
+ Clone,
+ Copy,
+ Debug,
+ Default,
+ Eq,
+ PartialEq,
+ serde::Serialize,
+ serde::Deserialize,
+ strum::Display,
+ strum::EnumString,
+ frunk::LabelledGeneric,
+)]
+#[router_derive::diesel_enum(storage_type = "text")]
+#[serde(rename_all = "snake_case")]
+#[strum(serialize_all = "snake_case")]
+pub enum UserStatus {
+ Active,
+ #[default]
+ InvitationSent,
+}
diff --git a/crates/diesel_models/src/ephemeral_key.rs b/crates/diesel_models/src/ephemeral_key.rs
index 96bd6e497c33..77b9c647e43b 100644
--- a/crates/diesel_models/src/ephemeral_key.rs
+++ b/crates/diesel_models/src/ephemeral_key.rs
@@ -14,3 +14,9 @@ pub struct EphemeralKey {
pub expires: i64,
pub secret: String,
}
+
+impl common_utils::events::ApiEventMetric for EphemeralKey {
+ fn get_api_event_type(&self) -> Option {
+ Some(common_utils::events::ApiEventsType::Miscellaneous)
+ }
+}
diff --git a/crates/diesel_models/src/gsm.rs b/crates/diesel_models/src/gsm.rs
new file mode 100644
index 000000000000..2e824758aa5a
--- /dev/null
+++ b/crates/diesel_models/src/gsm.rs
@@ -0,0 +1,106 @@
+//! Gateway status mapping
+
+use common_utils::{
+ custom_serde,
+ events::{ApiEventMetric, ApiEventsType},
+};
+use diesel::{AsChangeset, Identifiable, Insertable, Queryable};
+use time::PrimitiveDateTime;
+
+use crate::schema::gateway_status_map;
+
+#[derive(
+ Clone,
+ Debug,
+ Eq,
+ PartialEq,
+ router_derive::DebugAsDisplay,
+ Identifiable,
+ Queryable,
+ serde::Serialize,
+)]
+#[diesel(table_name = gateway_status_map, primary_key(connector, flow, sub_flow, code, message))]
+pub struct GatewayStatusMap {
+ pub connector: String,
+ pub flow: String,
+ pub sub_flow: String,
+ pub code: String,
+ pub message: String,
+ pub status: String,
+ pub router_error: Option,
+ pub decision: String,
+ #[serde(with = "custom_serde::iso8601")]
+ pub created_at: PrimitiveDateTime,
+ #[serde(with = "custom_serde::iso8601")]
+ pub last_modified: PrimitiveDateTime,
+ pub step_up_possible: bool,
+}
+
+#[derive(Clone, Debug, Eq, PartialEq, Insertable)]
+#[diesel(table_name = gateway_status_map)]
+pub struct GatewayStatusMappingNew {
+ pub connector: String,
+ pub flow: String,
+ pub sub_flow: String,
+ pub code: String,
+ pub message: String,
+ pub status: String,
+ pub router_error: Option,
+ pub decision: String,
+ pub step_up_possible: bool,
+}
+
+#[derive(
+ Clone,
+ Debug,
+ PartialEq,
+ Eq,
+ AsChangeset,
+ router_derive::DebugAsDisplay,
+ Default,
+ serde::Deserialize,
+)]
+#[diesel(table_name = gateway_status_map)]
+pub struct GatewayStatusMapperUpdateInternal {
+ pub connector: Option,
+ pub flow: Option,
+ pub sub_flow: Option,
+ pub code: Option,
+ pub message: Option,
+ pub status: Option,
+ pub router_error: Option>,
+ pub decision: Option,
+ pub step_up_possible: Option,
+}
+
+#[derive(Debug)]
+pub struct GatewayStatusMappingUpdate {
+ pub status: Option,
+ pub router_error: Option>,
+ pub decision: Option,
+ pub step_up_possible: Option,
+}
+
+impl From for GatewayStatusMapperUpdateInternal {
+ fn from(value: GatewayStatusMappingUpdate) -> Self {
+ let GatewayStatusMappingUpdate {
+ decision,
+ status,
+ router_error,
+ step_up_possible,
+ } = value;
+ Self {
+ status,
+ router_error,
+ decision,
+ step_up_possible,
+ ..Default::default()
+ }
+ }
+}
+
+impl ApiEventMetric for GatewayStatusMap {
+ fn get_api_event_type(&self) -> Option {
+ Some(ApiEventsType::Gsm)
+ }
+}
diff --git a/crates/diesel_models/src/kv.rs b/crates/diesel_models/src/kv.rs
index f1145a4b6e1f..f56ef8304186 100644
--- a/crates/diesel_models/src/kv.rs
+++ b/crates/diesel_models/src/kv.rs
@@ -3,7 +3,6 @@ use serde::{Deserialize, Serialize};
use crate::{
address::{Address, AddressNew, AddressUpdateInternal},
- connector_response::{ConnectorResponse, ConnectorResponseNew, ConnectorResponseUpdate},
errors,
payment_attempt::{PaymentAttempt, PaymentAttemptNew, PaymentAttemptUpdate},
payment_intent::{PaymentIntentNew, PaymentIntentUpdate},
@@ -27,13 +26,21 @@ pub struct TypedSql {
}
impl TypedSql {
- pub fn to_field_value_pairs(&self) -> crate::StorageResult> {
- Ok(vec![(
- "typed_sql",
- serde_json::to_string(self)
- .into_report()
- .change_context(errors::DatabaseError::QueryGenerationFailed)?,
- )])
+ pub fn to_field_value_pairs(
+ &self,
+ request_id: String,
+ global_id: String,
+ ) -> crate::StorageResult> {
+ Ok(vec![
+ (
+ "typed_sql",
+ serde_json::to_string(self)
+ .into_report()
+ .change_context(errors::DatabaseError::QueryGenerationFailed)?,
+ ),
+ ("global_id", global_id),
+ ("request_id", request_id),
+ ])
}
}
@@ -43,7 +50,6 @@ pub enum Insertable {
PaymentIntent(PaymentIntentNew),
PaymentAttempt(PaymentAttemptNew),
Refund(RefundNew),
- ConnectorResponse(ConnectorResponseNew),
Address(Box),
ReverseLookUp(ReverseLookupNew),
}
@@ -54,16 +60,9 @@ pub enum Updateable {
PaymentIntentUpdate(PaymentIntentUpdateMems),
PaymentAttemptUpdate(PaymentAttemptUpdateMems),
RefundUpdate(RefundUpdateMems),
- ConnectorResponseUpdate(ConnectorResponseUpdateMems),
AddressUpdate(Box),
}
-#[derive(Debug, Serialize, Deserialize)]
-pub struct ConnectorResponseUpdateMems {
- pub orig: ConnectorResponse,
- pub update_data: ConnectorResponseUpdate,
-}
-
#[derive(Debug, Serialize, Deserialize)]
pub struct AddressUpdateMems {
pub orig: Address,
diff --git a/crates/diesel_models/src/lib.rs b/crates/diesel_models/src/lib.rs
index 528446678015..781099662a50 100644
--- a/crates/diesel_models/src/lib.rs
+++ b/crates/diesel_models/src/lib.rs
@@ -4,7 +4,7 @@ pub mod business_profile;
pub mod capture;
pub mod cards_info;
pub mod configs;
-pub mod connector_response;
+
pub mod customers;
pub mod dispute;
pub mod encryption;
@@ -15,6 +15,7 @@ pub mod events;
pub mod file;
#[allow(unused)]
pub mod fraud_check;
+pub mod gsm;
#[cfg(feature = "kv_store")]
pub mod kv;
pub mod locker_mock_up;
@@ -34,18 +35,21 @@ pub mod process_tracker;
pub mod query;
pub mod refund;
pub mod reverse_lookup;
+pub mod routing_algorithm;
#[allow(unused_qualifications)]
pub mod schema;
+pub mod user;
+pub mod user_role;
use diesel_impl::{DieselArray, OptionalDieselArray};
pub type StorageResult = error_stack::Result;
pub type PgPooledConn = async_bb8_diesel::Connection;
pub use self::{
- address::*, api_keys::*, cards_info::*, configs::*, connector_response::*, customers::*,
- dispute::*, ephemeral_key::*, events::*, file::*, locker_mock_up::*, mandate::*,
- merchant_account::*, merchant_connector_account::*, payment_attempt::*, payment_intent::*,
- payment_method::*, process_tracker::*, refund::*, reverse_lookup::*,
+ address::*, api_keys::*, cards_info::*, configs::*, customers::*, dispute::*, ephemeral_key::*,
+ events::*, file::*, locker_mock_up::*, mandate::*, merchant_account::*,
+ merchant_connector_account::*, payment_attempt::*, payment_intent::*, payment_method::*,
+ process_tracker::*, refund::*, reverse_lookup::*,
};
/// The types and implementations provided by this module are required for the schema generated by
diff --git a/crates/diesel_models/src/payment_attempt.rs b/crates/diesel_models/src/payment_attempt.rs
index 058086106111..ce388fea10eb 100644
--- a/crates/diesel_models/src/payment_attempt.rs
+++ b/crates/diesel_models/src/payment_attempt.rs
@@ -203,6 +203,8 @@ pub enum PaymentAttemptUpdate {
connector_response_reference_id: Option,
amount_capturable: Option,
updated_by: String,
+ authentication_data: Option,
+ encoded_data: Option,
},
UnresolvedResponseUpdate {
status: storage_enums::AttemptStatus,
@@ -478,6 +480,8 @@ impl From for PaymentAttemptUpdateInternal {
connector_response_reference_id,
amount_capturable,
updated_by,
+ authentication_data,
+ encoded_data,
} => Self {
status: Some(status),
connector,
@@ -494,6 +498,8 @@ impl From for PaymentAttemptUpdateInternal {
connector_response_reference_id,
amount_capturable,
updated_by,
+ authentication_data,
+ encoded_data,
..Default::default()
},
PaymentAttemptUpdate::ErrorUpdate {
diff --git a/crates/diesel_models/src/payment_link.rs b/crates/diesel_models/src/payment_link.rs
index 4b182a8155a5..50cc5e89cee9 100644
--- a/crates/diesel_models/src/payment_link.rs
+++ b/crates/diesel_models/src/payment_link.rs
@@ -20,8 +20,8 @@ pub struct PaymentLink {
pub last_modified_at: PrimitiveDateTime,
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
pub fulfilment_time: Option,
+ pub custom_merchant_name: Option,
}
-
#[derive(
Clone,
Debug,
@@ -47,4 +47,5 @@ pub struct PaymentLinkNew {
pub last_modified_at: Option,
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
pub fulfilment_time: Option,
+ pub custom_merchant_name: Option,
}
diff --git a/crates/diesel_models/src/query.rs b/crates/diesel_models/src/query.rs
index 6b705e29873e..cf5a993c2686 100644
--- a/crates/diesel_models/src/query.rs
+++ b/crates/diesel_models/src/query.rs
@@ -4,13 +4,14 @@ pub mod business_profile;
mod capture;
pub mod cards_info;
pub mod configs;
-pub mod connector_response;
+
pub mod customers;
pub mod dispute;
pub mod events;
pub mod file;
pub mod fraud_check;
pub mod generics;
+pub mod gsm;
pub mod locker_mock_up;
pub mod mandate;
pub mod merchant_account;
@@ -26,3 +27,6 @@ pub mod payouts;
pub mod process_tracker;
pub mod refund;
pub mod reverse_lookup;
+pub mod routing_algorithm;
+pub mod user;
+pub mod user_role;
diff --git a/crates/diesel_models/src/query/gsm.rs b/crates/diesel_models/src/query/gsm.rs
new file mode 100644
index 000000000000..bd44ce4dc378
--- /dev/null
+++ b/crates/diesel_models/src/query/gsm.rs
@@ -0,0 +1,100 @@
+use diesel::{associations::HasTable, BoolExpressionMethods, ExpressionMethods};
+use error_stack::report;
+
+use crate::{
+ errors, gsm::*, query::generics, schema::gateway_status_map::dsl, PgPooledConn, StorageResult,
+};
+
+impl GatewayStatusMappingNew {
+ pub async fn insert(self, conn: &PgPooledConn) -> StorageResult {
+ generics::generic_insert(conn, self).await
+ }
+}
+
+impl GatewayStatusMap {
+ pub async fn find(
+ conn: &PgPooledConn,
+ connector: String,
+ flow: String,
+ sub_flow: String,
+ code: String,
+ message: String,
+ ) -> StorageResult {
+ generics::generic_find_one::<::Table, _, _>(
+ conn,
+ dsl::connector
+ .eq(connector)
+ .and(dsl::flow.eq(flow))
+ .and(dsl::sub_flow.eq(sub_flow))
+ .and(dsl::code.eq(code))
+ .and(dsl::message.eq(message)),
+ )
+ .await
+ }
+
+ pub async fn retrieve_decision(
+ conn: &PgPooledConn,
+ connector: String,
+ flow: String,
+ sub_flow: String,
+ code: String,
+ message: String,
+ ) -> StorageResult {
+ Self::find(conn, connector, flow, sub_flow, code, message)
+ .await
+ .map(|item| item.decision)
+ }
+
+ pub async fn update(
+ conn: &PgPooledConn,
+ connector: String,
+ flow: String,
+ sub_flow: String,
+ code: String,
+ message: String,
+ gsm: GatewayStatusMappingUpdate,
+ ) -> StorageResult {
+ generics::generic_update_with_results::<
+ ::Table,
+ GatewayStatusMapperUpdateInternal,
+ _,
+ _,
+ >(
+ conn,
+ dsl::connector
+ .eq(connector)
+ .and(dsl::flow.eq(flow))
+ .and(dsl::sub_flow.eq(sub_flow))
+ .and(dsl::code.eq(code))
+ .and(dsl::message.eq(message)),
+ gsm.into(),
+ )
+ .await?
+ .first()
+ .cloned()
+ .ok_or_else(|| {
+ report!(errors::DatabaseError::NotFound)
+ .attach_printable("Error while updating gsm entry")
+ })
+ }
+
+ pub async fn delete(
+ conn: &PgPooledConn,
+ connector: String,
+ flow: String,
+ sub_flow: String,
+ code: String,
+ message: String,
+ ) -> StorageResult {
+ generics::generic_delete::<::Table, _>(
+ conn,
+ dsl::connector
+ .eq(connector)
+ .and(dsl::flow.eq(flow))
+ .and(dsl::sub_flow.eq(sub_flow))
+ .and(dsl::code.eq(code))
+ .and(dsl::message.eq(message)),
+ )
+ .await
+ }
+}
diff --git a/crates/diesel_models/src/query/routing_algorithm.rs b/crates/diesel_models/src/query/routing_algorithm.rs
new file mode 100644
index 000000000000..533ac7194c41
--- /dev/null
+++ b/crates/diesel_models/src/query/routing_algorithm.rs
@@ -0,0 +1,200 @@
+use async_bb8_diesel::AsyncRunQueryDsl;
+use diesel::{associations::HasTable, BoolExpressionMethods, ExpressionMethods, QueryDsl};
+use error_stack::{IntoReport, ResultExt};
+use router_env::tracing::{self, instrument};
+use time::PrimitiveDateTime;
+
+use crate::{
+ enums,
+ errors::DatabaseError,
+ query::generics,
+ routing_algorithm::{RoutingAlgorithm, RoutingAlgorithmMetadata, RoutingProfileMetadata},
+ schema::routing_algorithm::dsl,
+ PgPooledConn, StorageResult,
+};
+
+impl RoutingAlgorithm {
+ #[instrument(skip(conn))]
+ pub async fn insert(self, conn: &PgPooledConn) -> StorageResult {
+ generics::generic_insert(conn, self).await
+ }
+
+ #[instrument(skip(conn))]
+ pub async fn find_by_algorithm_id_merchant_id(
+ conn: &PgPooledConn,
+ algorithm_id: &str,
+ merchant_id: &str,
+ ) -> StorageResult {
+ generics::generic_find_one::<::Table, _, _>(
+ conn,
+ dsl::algorithm_id
+ .eq(algorithm_id.to_owned())
+ .and(dsl::merchant_id.eq(merchant_id.to_owned())),
+ )
+ .await
+ }
+
+ #[instrument(skip(conn))]
+ pub async fn find_by_algorithm_id_profile_id(
+ conn: &PgPooledConn,
+ algorithm_id: &str,
+ profile_id: &str,
+ ) -> StorageResult {
+ generics::generic_find_one::<::Table, _, _>(
+ conn,
+ dsl::algorithm_id
+ .eq(algorithm_id.to_owned())
+ .and(dsl::profile_id.eq(profile_id.to_owned())),
+ )
+ .await
+ }
+
+ #[instrument(skip(conn))]
+ pub async fn find_metadata_by_algorithm_id_profile_id(
+ conn: &PgPooledConn,
+ algorithm_id: &str,
+ profile_id: &str,
+ ) -> StorageResult {
+ Self::table()
+ .select((
+ dsl::profile_id,
+ dsl::algorithm_id,
+ dsl::name,
+ dsl::description,
+ dsl::kind,
+ dsl::created_at,
+ dsl::modified_at,
+ ))
+ .filter(
+ dsl::algorithm_id
+ .eq(algorithm_id.to_owned())
+ .and(dsl::profile_id.eq(profile_id.to_owned())),
+ )
+ .limit(1)
+ .load_async::<(
+ String,
+ String,
+ String,
+ Option,
+ enums::RoutingAlgorithmKind,
+ PrimitiveDateTime,
+ PrimitiveDateTime,
+ )>(conn)
+ .await
+ .into_report()
+ .change_context(DatabaseError::Others)?
+ .into_iter()
+ .next()
+ .ok_or(DatabaseError::NotFound)
+ .into_report()
+ .map(
+ |(profile_id, algorithm_id, name, description, kind, created_at, modified_at)| {
+ RoutingProfileMetadata {
+ profile_id,
+ algorithm_id,
+ name,
+ description,
+ kind,
+ created_at,
+ modified_at,
+ }
+ },
+ )
+ }
+
+ #[instrument(skip(conn))]
+ pub async fn list_metadata_by_profile_id(
+ conn: &PgPooledConn,
+ profile_id: &str,
+ limit: i64,
+ offset: i64,
+ ) -> StorageResult> {
+ Ok(Self::table()
+ .select((
+ dsl::algorithm_id,
+ dsl::name,
+ dsl::description,
+ dsl::kind,
+ dsl::created_at,
+ dsl::modified_at,
+ ))
+ .filter(dsl::profile_id.eq(profile_id.to_owned()))
+ .limit(limit)
+ .offset(offset)
+ .load_async::<(
+ String,
+ String,
+ Option,
+ enums::RoutingAlgorithmKind,
+ PrimitiveDateTime,
+ PrimitiveDateTime,
+ )>(conn)
+ .await
+ .into_report()
+ .change_context(DatabaseError::Others)?
+ .into_iter()
+ .map(
+ |(algorithm_id, name, description, kind, created_at, modified_at)| {
+ RoutingAlgorithmMetadata {
+ algorithm_id,
+ name,
+ description,
+ kind,
+ created_at,
+ modified_at,
+ }
+ },
+ )
+ .collect())
+ }
+
+ #[instrument(skip(conn))]
+ pub async fn list_metadata_by_merchant_id(
+ conn: &PgPooledConn,
+ merchant_id: &str,
+ limit: i64,
+ offset: i64,
+ ) -> StorageResult> {
+ Ok(Self::table()
+ .select((
+ dsl::profile_id,
+ dsl::algorithm_id,
+ dsl::name,
+ dsl::description,
+ dsl::kind,
+ dsl::created_at,
+ dsl::modified_at,
+ ))
+ .filter(dsl::merchant_id.eq(merchant_id.to_owned()))
+ .limit(limit)
+ .offset(offset)
+ .order(dsl::modified_at.desc())
+ .load_async::<(
+ String,
+ String,
+ String,
+ Option,
+ enums::RoutingAlgorithmKind,
+ PrimitiveDateTime,
+ PrimitiveDateTime,
+ )>(conn)
+ .await
+ .into_report()
+ .change_context(DatabaseError::Others)?
+ .into_iter()
+ .map(
+ |(profile_id, algorithm_id, name, description, kind, created_at, modified_at)| {
+ RoutingProfileMetadata {
+ profile_id,
+ algorithm_id,
+ name,
+ description,
+ kind,
+ created_at,
+ modified_at,
+ }
+ },
+ )
+ .collect())
+ }
+}
diff --git a/crates/diesel_models/src/query/user.rs b/crates/diesel_models/src/query/user.rs
new file mode 100644
index 000000000000..5761d8af814d
--- /dev/null
+++ b/crates/diesel_models/src/query/user.rs
@@ -0,0 +1,62 @@
+use diesel::{associations::HasTable, ExpressionMethods};
+use error_stack::report;
+use router_env::tracing::{self, instrument};
+
+use crate::{
+ errors::{self},
+ query::generics,
+ schema::users::dsl,
+ user::*,
+ PgPooledConn, StorageResult,
+};
+
+impl UserNew {
+ #[instrument(skip(conn))]
+ pub async fn insert(self, conn: &PgPooledConn) -> StorageResult {
+ generics::generic_insert(conn, self).await
+ }
+}
+
+impl User {
+ pub async fn find_by_user_email(conn: &PgPooledConn, user_email: &str) -> StorageResult {
+ generics::generic_find_one::<::Table, _, _>(
+ conn,
+ dsl::email.eq(user_email.to_owned()),
+ )
+ .await
+ }
+
+ pub async fn find_by_user_id(conn: &PgPooledConn, user_id: &str) -> StorageResult {
+ generics::generic_find_one::<::Table, _, _>(
+ conn,
+ dsl::user_id.eq(user_id.to_owned()),
+ )
+ .await
+ }
+
+ pub async fn update_by_user_id(
+ conn: &PgPooledConn,
+ user_id: &str,
+ user: UserUpdate,
+ ) -> StorageResult {
+ generics::generic_update_with_results::<::Table, _, _, _>(
+ conn,
+ dsl::user_id.eq(user_id.to_owned()),
+ UserUpdateInternal::from(user),
+ )
+ .await?
+ .first()
+ .cloned()
+ .ok_or_else(|| {
+ report!(errors::DatabaseError::NotFound).attach_printable("Error while updating user")
+ })
+ }
+
+ pub async fn delete_by_user_id(conn: &PgPooledConn, user_id: &str) -> StorageResult {
+ generics::generic_delete::<::Table, _>(
+ conn,
+ dsl::user_id.eq(user_id.to_owned()),
+ )
+ .await
+ }
+}
diff --git a/crates/diesel_models/src/query/user_role.rs b/crates/diesel_models/src/query/user_role.rs
new file mode 100644
index 000000000000..d2f9564a5309
--- /dev/null
+++ b/crates/diesel_models/src/query/user_role.rs
@@ -0,0 +1,58 @@
+use diesel::{associations::HasTable, BoolExpressionMethods, ExpressionMethods};
+use router_env::tracing::{self, instrument};
+
+use crate::{query::generics, schema::user_roles::dsl, user_role::*, PgPooledConn, StorageResult};
+
+impl UserRoleNew {
+ #[instrument(skip(conn))]
+ pub async fn insert(self, conn: &PgPooledConn) -> StorageResult