diff --git a/.github/workflows/CI-pr.yml b/.github/workflows/CI-pr.yml
index c79ffa63709a..ecb13f3c1a85 100644
--- a/.github/workflows/CI-pr.yml
+++ b/.github/workflows/CI-pr.yml
@@ -41,17 +41,25 @@ jobs:
name: Check formatting
runs-on: ubuntu-latest
steps:
+ - name: Generate a token
+ if: ${{ github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name }}
+ id: generate_token
+ uses: actions/create-github-app-token@v1
+ with:
+ app-id: ${{ secrets.HYPERSWITCH_BOT_APP_ID }}
+ private-key: ${{ secrets.HYPERSWITCH_BOT_APP_PRIVATE_KEY }}
+
- name: Checkout repository with token
if: ${{ github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name }}
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.ref }}
- token: ${{ secrets.AUTO_FILE_UPDATE_PAT }}
+ token: ${{ steps.generate_token.outputs.token }}
- name: Checkout repository for fork
if: ${{ github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name }}
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@master
@@ -71,8 +79,8 @@ jobs:
cargo +nightly fmt --all
if ! git diff --exit-code --quiet -- crates; then
echo "::notice::Formatting check failed"
- git config --local user.name 'github-actions[bot]'
- git config --local user.email '41898282+github-actions[bot]@users.noreply.github.com'
+ git config --local user.name 'hyperswitch-bot[bot]'
+ git config --local user.email '148525504+hyperswitch-bot[bot]@users.noreply.github.com'
git add crates
git commit --message 'chore: run formatter'
git push
@@ -91,7 +99,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: "Fetch base branch"
shell: bash
@@ -108,12 +116,12 @@ jobs:
with:
toolchain: 1.65
- - uses: Swatinem/rust-cache@v2.4.0
+ - uses: Swatinem/rust-cache@v2.7.0
with:
save-if: ${{ github.event_name == 'push' }}
- name: Install cargo-hack
- uses: baptiste0928/cargo-install@v2.1.0
+ uses: baptiste0928/cargo-install@v2.2.0
with:
crate: cargo-hack
version: 0.6.5
@@ -280,7 +288,7 @@ jobs:
# steps:
# - name: Checkout repository
- # uses: actions/checkout@v3
+ # uses: actions/checkout@v4
# - name: Run cargo-deny
# uses: EmbarkStudios/cargo-deny-action@v1.3.2
@@ -299,17 +307,25 @@ jobs:
# - windows-latest
steps:
+ - name: Generate a token
+ if: ${{ github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name }}
+ id: generate_token
+ uses: actions/create-github-app-token@v1
+ with:
+ app-id: ${{ secrets.HYPERSWITCH_BOT_APP_ID }}
+ private-key: ${{ secrets.HYPERSWITCH_BOT_APP_PRIVATE_KEY }}
+
- name: Checkout repository for fork
if: ${{ (github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name) }}
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Checkout repository with token
if: ${{ (github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name) }}
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.ref }}
- token: ${{ secrets.AUTO_FILE_UPDATE_PAT }}
+ token: ${{ steps.generate_token.outputs.token }}
- name: "Fetch base branch"
shell: bash
@@ -328,16 +344,16 @@ jobs:
components: clippy
- name: Install cargo-hack
- uses: baptiste0928/cargo-install@v2.1.0
+ uses: baptiste0928/cargo-install@v2.2.0
with:
crate: cargo-hack
# - name: Install cargo-nextest
- # uses: baptiste0928/cargo-install@v2.1.0
+ # uses: baptiste0928/cargo-install@v2.2.0
# with:
# crate: cargo-nextest
- - uses: Swatinem/rust-cache@v2.4.0
+ - uses: Swatinem/rust-cache@v2.7.0
with:
save-if: ${{ github.event_name == 'push' }}
@@ -360,8 +376,8 @@ jobs:
shell: bash
run: |
if ! git diff --quiet --exit-code -- Cargo.lock ; then
- git config --local user.name 'github-actions[bot]'
- git config --local user.email '41898282+github-actions[bot]@users.noreply.github.com'
+ git config --local user.name 'hyperswitch-bot[bot]'
+ git config --local user.email '148525504+hyperswitch-bot[bot]@users.noreply.github.com'
git add Cargo.lock
git commit --message 'chore: update Cargo.lock'
git push
@@ -516,7 +532,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Spell check
uses: crate-ci/typos@master
diff --git a/.github/workflows/CI-push.yml b/.github/workflows/CI-push.yml
index edc9317e526d..a6a4bde5a5d4 100644
--- a/.github/workflows/CI-push.yml
+++ b/.github/workflows/CI-push.yml
@@ -25,7 +25,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@master
@@ -50,7 +50,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install mold linker
uses: rui314/setup-mold@v1
@@ -63,12 +63,12 @@ jobs:
with:
toolchain: 1.65
- - uses: Swatinem/rust-cache@v2.4.0
+ - uses: Swatinem/rust-cache@v2.7.0
with:
save-if: ${{ github.event_name == 'push' }}
- name: Install cargo-hack
- uses: baptiste0928/cargo-install@v2.1.0
+ uses: baptiste0928/cargo-install@v2.2.0
with:
crate: cargo-hack
version: 0.6.5
@@ -101,7 +101,7 @@ jobs:
# steps:
# - name: Checkout repository
- # uses: actions/checkout@v3
+ # uses: actions/checkout@v4
# - name: Run cargo-deny
# uses: EmbarkStudios/cargo-deny-action@v1.3.2
@@ -121,7 +121,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install mold linker
uses: rui314/setup-mold@v1
@@ -136,16 +136,16 @@ jobs:
components: clippy
- name: Install cargo-hack
- uses: baptiste0928/cargo-install@v2.1.0
+ uses: baptiste0928/cargo-install@v2.2.0
with:
crate: cargo-hack
# - name: Install cargo-nextest
- # uses: baptiste0928/cargo-install@v2.1.0
+ # uses: baptiste0928/cargo-install@v2.2.0
# with:
# crate: cargo-nextest
- - uses: Swatinem/rust-cache@v2.4.0
+ - uses: Swatinem/rust-cache@v2.7.0
with:
save-if: ${{ github.event_name == 'push' }}
@@ -178,7 +178,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Spell check
uses: crate-ci/typos@master
diff --git a/.github/workflows/auto-release-tag.yml b/.github/workflows/auto-release-tag.yml
index 5334c914cda5..4555b68764c1 100644
--- a/.github/workflows/auto-release-tag.yml
+++ b/.github/workflows/auto-release-tag.yml
@@ -10,18 +10,18 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Login to Docker Hub
- uses: docker/login-action@v2
+ uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USER }}
password: ${{ secrets.DOCKERHUB_PASSWD }}
- name: Build and push router Docker image
- uses: docker/build-push-action@v4
+ uses: docker/build-push-action@v5
with:
build-args: |
BINARY=router
@@ -30,7 +30,7 @@ jobs:
tags: juspaydotin/orca:${{ github.ref_name }}, juspaydotin/hyperswitch-router:${{ github.ref_name }}
- name: Build and push consumer Docker image
- uses: docker/build-push-action@v4
+ uses: docker/build-push-action@v5
with:
build-args: |
BINARY=scheduler
@@ -40,7 +40,7 @@ jobs:
tags: juspaydotin/orca-consumer:${{ github.ref_name }}, juspaydotin/hyperswitch-consumer:${{ github.ref_name }}
- name: Build and push producer Docker image
- uses: docker/build-push-action@v4
+ uses: docker/build-push-action@v5
with:
build-args: |
BINARY=scheduler
@@ -50,7 +50,7 @@ jobs:
tags: juspaydotin/orca-producer:${{ github.ref_name }}, juspaydotin/hyperswitch-producer:${{ github.ref_name }}
- name: Build and push drainer Docker image
- uses: docker/build-push-action@v4
+ uses: docker/build-push-action@v5
with:
build-args: |
BINARY=drainer
diff --git a/.github/workflows/connector-sanity-tests.yml b/.github/workflows/connector-sanity-tests.yml
index 40a3c3612503..48e6a946a450 100644
--- a/.github/workflows/connector-sanity-tests.yml
+++ b/.github/workflows/connector-sanity-tests.yml
@@ -79,14 +79,14 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: stable 2 weeks ago
- - uses: Swatinem/rust-cache@v2.4.0
+ - uses: Swatinem/rust-cache@v2.7.0
- name: Decrypt connector auth file
env:
diff --git a/.github/workflows/connector-ui-sanity-tests.yml b/.github/workflows/connector-ui-sanity-tests.yml
index 5db45f2962a5..d4317681a113 100644
--- a/.github/workflows/connector-ui-sanity-tests.yml
+++ b/.github/workflows/connector-ui-sanity-tests.yml
@@ -82,7 +82,7 @@ jobs:
- name: Checkout repository
if: ${{ (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name) }}
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Decrypt connector auth file
if: ${{ (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name) }}
@@ -113,10 +113,10 @@ jobs:
toolchain: stable
- name: Build and Cache Rust Dependencies
- uses: Swatinem/rust-cache@v2.4.0
+ uses: Swatinem/rust-cache@v2.7.0
- name: Install Diesel CLI with Postgres Support
- uses: baptiste0928/cargo-install@v2.1.0
+ uses: baptiste0928/cargo-install@v2.2.0
if: ${{ (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name) }}
with:
crate: diesel_cli
diff --git a/.github/workflows/conventional-commit-check.yml b/.github/workflows/conventional-commit-check.yml
index 5fd25e9332d1..ad01642068b5 100644
--- a/.github/workflows/conventional-commit-check.yml
+++ b/.github/workflows/conventional-commit-check.yml
@@ -45,7 +45,7 @@ jobs:
with:
toolchain: stable 2 weeks ago
- - uses: baptiste0928/cargo-install@v2.1.0
+ - uses: baptiste0928/cargo-install@v2.2.0
with:
crate: cocogitto
diff --git a/.github/workflows/create-hotfix-branch.yml b/.github/workflows/create-hotfix-branch.yml
index 77a8bad6bc66..6fd2d4947719 100644
--- a/.github/workflows/create-hotfix-branch.yml
+++ b/.github/workflows/create-hotfix-branch.yml
@@ -8,11 +8,19 @@ jobs:
runs-on: ubuntu-latest
steps:
+ - name: Generate a token
+ if: ${{ github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name }}
+ id: generate_token
+ uses: actions/create-github-app-token@v1
+ with:
+ app-id: ${{ secrets.HYPERSWITCH_BOT_APP_ID }}
+ private-key: ${{ secrets.HYPERSWITCH_BOT_APP_PRIVATE_KEY }}
+
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
- token: ${{ secrets.AUTO_RELEASE_PAT }}
+ token: ${{ steps.generate_token.outputs.token }}
- name: Check if the input is valid tag
shell: bash
diff --git a/.github/workflows/create-hotfix-tag.yml b/.github/workflows/create-hotfix-tag.yml
index 45699bda24dc..e9df004139e0 100644
--- a/.github/workflows/create-hotfix-tag.yml
+++ b/.github/workflows/create-hotfix-tag.yml
@@ -8,14 +8,22 @@ jobs:
runs-on: ubuntu-latest
steps:
+ - name: Generate a token
+ if: ${{ github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name }}
+ id: generate_token
+ uses: actions/create-github-app-token@v1
+ with:
+ app-id: ${{ secrets.HYPERSWITCH_BOT_APP_ID }}
+ private-key: ${{ secrets.HYPERSWITCH_BOT_APP_PRIVATE_KEY }}
+
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
- token: ${{ secrets.AUTO_RELEASE_PAT }}
+ token: ${{ steps.generate_token.outputs.token }}
- name: Install git-cliff
- uses: baptiste0928/cargo-install@v2.1.0
+ uses: baptiste0928/cargo-install@v2.2.0
with:
crate: git-cliff
version: 1.2.0
@@ -86,8 +94,8 @@ jobs:
- name: Set Git Configuration
shell: bash
run: |
- git config --local user.name 'github-actions'
- git config --local user.email '41898282+github-actions[bot]@users.noreply.github.com'
+ git config --local user.name 'hyperswitch-bot[bot]'
+ git config --local user.email '148525504+hyperswitch-bot[bot]@users.noreply.github.com'
- name: Push created commit and tag
shell: bash
diff --git a/.github/workflows/hotfix-pr-check.yml b/.github/workflows/hotfix-pr-check.yml
index 7a724b602586..e178ba31c1e8 100644
--- a/.github/workflows/hotfix-pr-check.yml
+++ b/.github/workflows/hotfix-pr-check.yml
@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Get hotfix pull request body
shell: bash
diff --git a/.github/workflows/manual-release.yml b/.github/workflows/manual-release.yml
index 0b70631e113d..9ae80047a669 100644
--- a/.github/workflows/manual-release.yml
+++ b/.github/workflows/manual-release.yml
@@ -17,18 +17,18 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Login to Docker Hub
- uses: docker/login-action@v2
+ uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USER }}
password: ${{ secrets.DOCKERHUB_PASSWD }}
- name: Build and push router Docker image
- uses: docker/build-push-action@v4
+ uses: docker/build-push-action@v5
with:
build-args: |
RUN_ENV=${{ inputs.environment }}
@@ -39,7 +39,7 @@ jobs:
tags: juspaydotin/orca:${{ github.sha }}
- name: Build and push consumer Docker image
- uses: docker/build-push-action@v4
+ uses: docker/build-push-action@v5
with:
build-args: |
RUN_ENV=${{ inputs.environment }}
@@ -50,7 +50,7 @@ jobs:
tags: juspaydotin/orca-consumer:${{ github.sha }}
- name: Build and push producer Docker image
- uses: docker/build-push-action@v4
+ uses: docker/build-push-action@v5
with:
build-args: |
RUN_ENV=${{ inputs.environment }}
@@ -61,7 +61,7 @@ jobs:
tags: juspaydotin/orca-producer:${{ github.sha }}
- name: Build and push drainer Docker image
- uses: docker/build-push-action@v4
+ uses: docker/build-push-action@v5
with:
build-args: |
RUN_ENV=${{ inputs.environment }}
diff --git a/.github/workflows/migration-check.yaml b/.github/workflows/migration-check.yaml
index 0c4baaa96193..b740bd3a5b77 100644
--- a/.github/workflows/migration-check.yaml
+++ b/.github/workflows/migration-check.yaml
@@ -40,14 +40,14 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: stable 2 weeks ago
- - uses: baptiste0928/cargo-install@v2.1.0
+ - uses: baptiste0928/cargo-install@v2.2.0
with:
crate: diesel_cli
features: postgres
diff --git a/.github/workflows/postman-collection-runner.yml b/.github/workflows/postman-collection-runner.yml
index 3291755b56cf..d5434520715f 100644
--- a/.github/workflows/postman-collection-runner.yml
+++ b/.github/workflows/postman-collection-runner.yml
@@ -50,7 +50,7 @@ jobs:
steps:
- name: Repository checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Decrypt connector auth file
if: ${{ ((github.event_name == 'pull_request') && (github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name)) || (github.event_name == 'merge_group')}}
@@ -82,11 +82,11 @@ jobs:
- name: Build and Cache Rust Dependencies
if: ${{ ((github.event_name == 'pull_request') && (github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name)) || (github.event_name == 'merge_group')}}
- uses: Swatinem/rust-cache@v2.4.0
+ uses: Swatinem/rust-cache@v2.7.0
- name: Install Diesel CLI with Postgres Support
if: ${{ ((github.event_name == 'pull_request') && (github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name)) || (github.event_name == 'merge_group')}}
- uses: baptiste0928/cargo-install@v2.1.0
+ uses: baptiste0928/cargo-install@v2.2.0
with:
crate: diesel_cli
features: postgres
diff --git a/.github/workflows/pr-title-spell-check.yml b/.github/workflows/pr-title-spell-check.yml
index 6ab6f184739d..03b5a8758870 100644
--- a/.github/workflows/pr-title-spell-check.yml
+++ b/.github/workflows/pr-title-spell-check.yml
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Store PR title in a file
shell: bash
diff --git a/.github/workflows/release-new-version.yml b/.github/workflows/release-new-version.yml
index eda2df05153b..b54e240d96fc 100644
--- a/.github/workflows/release-new-version.yml
+++ b/.github/workflows/release-new-version.yml
@@ -23,11 +23,19 @@ jobs:
runs-on: ubuntu-latest
steps:
+ - name: Generate a token
+ if: ${{ github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name }}
+ id: generate_token
+ uses: actions/create-github-app-token@v1
+ with:
+ app-id: ${{ secrets.HYPERSWITCH_BOT_APP_ID }}
+ private-key: ${{ secrets.HYPERSWITCH_BOT_APP_PRIVATE_KEY }}
+
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
- token: ${{ secrets.AUTO_RELEASE_PAT }}
+ token: ${{ steps.generate_token.outputs.token }}
- name: Install Rust
uses: dtolnay/rust-toolchain@master
@@ -35,7 +43,7 @@ jobs:
toolchain: stable 2 weeks ago
- name: Install cocogitto
- uses: baptiste0928/cargo-install@v2.1.0
+ uses: baptiste0928/cargo-install@v2.2.0
with:
crate: cocogitto
version: 5.4.0
@@ -43,8 +51,8 @@ jobs:
- name: Set Git Configuration
shell: bash
run: |
- git config --local user.name 'github-actions'
- git config --local user.email '41898282+github-actions[bot]@users.noreply.github.com'
+ git config --local user.name 'hyperswitch-bot[bot]'
+ git config --local user.email '148525504+hyperswitch-bot[bot]@users.noreply.github.com'
- name: Update Postman collection files from Postman directories
shell: bash
diff --git a/.github/workflows/validate-openapi-spec.yml b/.github/workflows/validate-openapi-spec.yml
index 530c59c9236d..bdb987d625ac 100644
--- a/.github/workflows/validate-openapi-spec.yml
+++ b/.github/workflows/validate-openapi-spec.yml
@@ -16,24 +16,32 @@ jobs:
name: Validate generated OpenAPI spec file
runs-on: ubuntu-latest
steps:
+ - name: Generate a token
+ if: ${{ github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name }}
+ id: generate_token
+ uses: actions/create-github-app-token@v1
+ with:
+ app-id: ${{ secrets.HYPERSWITCH_BOT_APP_ID }}
+ private-key: ${{ secrets.HYPERSWITCH_BOT_APP_PRIVATE_KEY }}
+
- name: Checkout PR from fork
if: ${{ (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name) }}
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.ref }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
- name: Checkout PR with token
if: ${{ (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name) }}
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.ref }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
- token: ${{ secrets.AUTO_FILE_UPDATE_PAT }}
+ token: ${{ steps.generate_token.outputs.token }}
- name: Checkout merge group HEAD commit
if: ${{ github.event_name == 'merge_group' }}
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
ref: ${{ github.event.merge_group.head_sha }}
@@ -60,8 +68,8 @@ jobs:
shell: bash
run: |
if ! git diff --quiet --exit-code -- openapi/openapi_spec.json ; then
- git config --local user.name 'github-actions[bot]'
- git config --local user.email '41898282+github-actions[bot]@users.noreply.github.com'
+ git config --local user.name 'hyperswitch-bot[bot]'
+ git config --local user.email '148525504+hyperswitch-bot[bot]@users.noreply.github.com'
git add openapi/openapi_spec.json
git commit --message 'docs(openapi): re-generate OpenAPI specification'
git push
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f4b86696691e..8b3abf1d5781 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,93 @@ All notable changes to HyperSwitch will be documented here.
- - -
+## 1.90.0 (2023-11-27)
+
+### Features
+
+- **auth:** Add Authorization for JWT Authentication types ([#2973](https://github.com/juspay/hyperswitch/pull/2973)) ([`03c0a77`](https://github.com/juspay/hyperswitch/commit/03c0a772a99000acf4676db8ca2ce916036281d1))
+- **user:** Implement change password for user ([#2959](https://github.com/juspay/hyperswitch/pull/2959)) ([`bfa1645`](https://github.com/juspay/hyperswitch/commit/bfa1645b847fb881eb2370d5dbfef6fd0b53725d))
+
+### Bug Fixes
+
+- **router:** Added validation to check total orderDetails amount equal to amount in request ([#2965](https://github.com/juspay/hyperswitch/pull/2965)) ([`37532d4`](https://github.com/juspay/hyperswitch/commit/37532d46f599a99e0e021b0455a6f02381005dd7))
+- Add prefix to connector_transaction_id ([#2981](https://github.com/juspay/hyperswitch/pull/2981)) ([`107c3b9`](https://github.com/juspay/hyperswitch/commit/107c3b99417dd7bca7b62741ad601485700f37be))
+
+### Refactors
+
+- **connector:** [Nuvei] update error message ([#2867](https://github.com/juspay/hyperswitch/pull/2867)) ([`04b7c03`](https://github.com/juspay/hyperswitch/commit/04b7c0384dc9290bd60f49033fd35732527720f1))
+
+### Testing
+
+- **postman:** Update postman collection files ([`aee59e0`](https://github.com/juspay/hyperswitch/commit/aee59e088a8e7c1b81aca1015c90c7b4fd07511d))
+
+### Documentation
+
+- **try_local_system:** Add instructions to run using Docker Compose by pulling standalone images ([#2984](https://github.com/juspay/hyperswitch/pull/2984)) ([`0fa8ad1`](https://github.com/juspay/hyperswitch/commit/0fa8ad1b7c27010bf83e4035de9881d29e192e8a))
+
+### Miscellaneous Tasks
+
+- **connector:** Update connector addition script ([#2801](https://github.com/juspay/hyperswitch/pull/2801)) ([`34953a0`](https://github.com/juspay/hyperswitch/commit/34953a046429fe0341e8469bd9b036e176bda205))
+
+**Full Changelog:** [`v1.89.0...v1.90.0`](https://github.com/juspay/hyperswitch/compare/v1.89.0...v1.90.0)
+
+- - -
+
+
+## 1.89.0 (2023-11-24)
+
+### Features
+
+- **router:** Add `connector_transaction_id` in error_response from connector flows ([#2972](https://github.com/juspay/hyperswitch/pull/2972)) ([`3322103`](https://github.com/juspay/hyperswitch/commit/3322103f5c9b7c2a5b663980246c6ca36b8dc63e))
+
+### Bug Fixes
+
+- **connector:** [BANKOFAMERICA] Add status VOIDED in enum Bankofameri… ([#2969](https://github.com/juspay/hyperswitch/pull/2969)) ([`203bbd7`](https://github.com/juspay/hyperswitch/commit/203bbd73751e1513206e81d7cf920ec263f83c58))
+- **core:** Error propagation for not supporting partial refund ([#2976](https://github.com/juspay/hyperswitch/pull/2976)) ([`97a38a7`](https://github.com/juspay/hyperswitch/commit/97a38a78e514e4fa3b5db46b6de985be6312dcc3))
+- **router:** Mark refund status as failure for not_implemented error from connector flows ([#2978](https://github.com/juspay/hyperswitch/pull/2978)) ([`d56d805`](https://github.com/juspay/hyperswitch/commit/d56d80557050336d5ed37282f1aa34b6c17389d1))
+- Return none instead of err when payment method data is not found for bank debit during listing ([#2967](https://github.com/juspay/hyperswitch/pull/2967)) ([`5cc829a`](https://github.com/juspay/hyperswitch/commit/5cc829a11f515a413fe19f657a90aa05cebb99b5))
+- Surcharge related status and rules fix ([#2974](https://github.com/juspay/hyperswitch/pull/2974)) ([`3db7213`](https://github.com/juspay/hyperswitch/commit/3db721388a7f0e291d7eb186661fc69a57068ea6))
+
+### Documentation
+
+- **README:** Updated Community Platform Mentions ([#2960](https://github.com/juspay/hyperswitch/pull/2960)) ([`e0bde43`](https://github.com/juspay/hyperswitch/commit/e0bde433282a34eb9eb28a2d9c43c2b17b5e65e5))
+- Add Rust locker information in architecture doc ([#2964](https://github.com/juspay/hyperswitch/pull/2964)) ([`b2f7dd1`](https://github.com/juspay/hyperswitch/commit/b2f7dd13925a1429e316cd9eaf0e2d31d46b6d4a))
+
+**Full Changelog:** [`v1.88.0...v1.89.0`](https://github.com/juspay/hyperswitch/compare/v1.88.0...v1.89.0)
+
+- - -
+
+
+## 1.88.0 (2023-11-23)
+
+### Features
+
+- **connector:** [BANKOFAMERICA] Implement Google Pay ([#2940](https://github.com/juspay/hyperswitch/pull/2940)) ([`f91d4ae`](https://github.com/juspay/hyperswitch/commit/f91d4ae11b02def92c1dde743a0c01b5aac5703f))
+- **router:** Allow billing and shipping address update in payments confirm flow ([#2963](https://github.com/juspay/hyperswitch/pull/2963)) ([`59ef162`](https://github.com/juspay/hyperswitch/commit/59ef162219db3e4650dde65710850bc9f3280530))
+
+### Bug Fixes
+
+- **connector:** [Prophetpay] Use refund_id as reference_id for Refund ([#2966](https://github.com/juspay/hyperswitch/pull/2966)) ([`dd3e22a`](https://github.com/juspay/hyperswitch/commit/dd3e22a938714f373477e08d1d25e4b84ac796c6))
+- **core:** Fix Default Values Enum FieldType ([#2934](https://github.com/juspay/hyperswitch/pull/2934)) ([`35a44ed`](https://github.com/juspay/hyperswitch/commit/35a44ed2533b748e3fabb8a2f8db4fa7e5d3cf7e))
+- **drainer:** Increase jobs picked only when stream is not empty ([#2958](https://github.com/juspay/hyperswitch/pull/2958)) ([`42eedf3`](https://github.com/juspay/hyperswitch/commit/42eedf3a8c2e62fc22bcead370d129ebaf11a00b))
+- Amount_captured goes to 0 for 3ds payments ([#2954](https://github.com/juspay/hyperswitch/pull/2954)) ([`75eea7e`](https://github.com/juspay/hyperswitch/commit/75eea7e81787f2e0697b930b82a8188193f8d51f))
+- Make drainer sleep on every loop interval instead of cycle end ([#2951](https://github.com/juspay/hyperswitch/pull/2951)) ([`e8df690`](https://github.com/juspay/hyperswitch/commit/e8df69092f4c6acee58109aaff2a9454fceb571a))
+
+### Refactors
+
+- **connector:**
+ - [Payeezy] update error message ([#2919](https://github.com/juspay/hyperswitch/pull/2919)) ([`cb65370`](https://github.com/juspay/hyperswitch/commit/cb653706066b889eaa9423a6227ce1df954b4759))
+ - [Worldline] change error message from NotSupported to NotImplemented ([#2893](https://github.com/juspay/hyperswitch/pull/2893)) ([`e721b06`](https://github.com/juspay/hyperswitch/commit/e721b06c7077e00458450a4fb98f4497e8227dc6))
+
+### Testing
+
+- **postman:** Update postman collection files ([`9a3fa00`](https://github.com/juspay/hyperswitch/commit/9a3fa00426d74f6d18b3c712b292d98d80d517ba))
+
+**Full Changelog:** [`v1.87.0...v1.88.0`](https://github.com/juspay/hyperswitch/compare/v1.87.0...v1.88.0)
+
+- - -
+
+
## 1.87.0 (2023-11-22)
### Features
diff --git a/README.md b/README.md
index 8c5ad9e03b2d..db8e820ef142 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,6 @@
-
The open-source payments switch
@@ -35,7 +34,6 @@ The single API to access payment ecosystems across 130+ countries
-
@@ -57,14 +55,14 @@ Using Hyperswitch, you can:
⚡️ Quick Start Guide
- One-click deployment on AWS cloud
+### One-click deployment on AWS cloud
-The fastest and easiest way to try hyperswitch is via our CDK scripts
+The fastest and easiest way to try Hyperswitch is via our CDK scripts
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.
-
+
2. Sign-in to your AWS console.
@@ -72,12 +70,27 @@ The fastest and easiest way to try hyperswitch is via our CDK scripts
For an early access to the production-ready setup fill this Early Access Form
+### Run it on your system
+
+You can run Hyperswitch on your system using Docker Compose after cloning this repository:
+
+```shell
+docker compose up -d
+```
+
+This will start the payments router, the primary component within Hyperswitch.
+
+Check out the [local setup guide][local-setup-guide] for a more comprehensive
+setup, which includes the [scheduler and monitoring services][docker-compose-scheduler-monitoring].
+
+[local-setup-guide]: /docs/try_local_system.md
+[docker-compose-scheduler-monitoring]: /docs/try_local_system.md#run-the-scheduler-and-monitoring-services
+
🔌 Fast Integration for Stripe Users
-If you are already using Stripe, integrating with Hyperswitch is fun, fast &
-easy.
+If you are already using Stripe, integrating with Hyperswitch is fun, fast & easy.
Try the steps below to get a feel for how quick the setup is:
1. Get API keys from our [dashboard].
@@ -96,9 +109,7 @@ Try the steps below to get a feel for how quick the setup is:
As of Sept 2023, we support 50+ payment processors and multiple global payment methods.
In addition, we are continuously integrating new processors based on their reach and community requests.
Our target is to support 100+ processors by H2 2023.
-You can find the latest list of payment processors, supported methods, and
-features
-[here][supported-connectors-and-features].
+You can find the latest list of payment processors, supported methods, and features [here][supported-connectors-and-features].
[supported-connectors-and-features]: https://hyperswitch.io/pm-list
@@ -252,11 +263,11 @@ We welcome contributions from the community. Please read through our
Included are directions for opening issues, coding standards, and notes on
development.
-🦀 **Important note for Rust developers**: We aim for contributions from the community
-across a broad range of tracks. Hence, we have prioritised simplicity and code
-readability over purely idiomatic code. For example, some of the code in core
-functions (e.g., `payments_core`) is written to be more readable than
-pure-idiomatic.
+- We appreciate all types of contributions: code, documentation, demo creation, or some new way you want to contribute to us.
+ We will reward every contribution with a Hyperswitch branded t-shirt.
+- 🦀 **Important note for Rust developers**: We aim for contributions from the community across a broad range of tracks.
+ Hence, we have prioritised simplicity and code readability over purely idiomatic code.
+ For example, some of the code in core functions (e.g., `payments_core`) is written to be more readable than pure-idiomatic.
@@ -264,12 +275,10 @@ pure-idiomatic.
Get updates on Hyperswitch development and chat with the community:
-- Read and subscribe to [the official Hyperswitch blog][blog].
-- Join our [Discord server][discord].
-- Join our [Slack workspace][slack].
-- Ask and explore our [GitHub Discussions][github-discussions].
+- [Discord server][discord] for questions related to contributing to hyperswitch, questions about the architecture, components, etc.
+- [Slack workspace][slack] for questions related to integrating hyperswitch, integrating a connector in hyperswitch, etc.
+- [GitHub Discussions][github-discussions] to drop feature requests or suggest anything payments-related you need for your stack.
-[blog]: https://hyperswitch.io/blog
[discord]: https://discord.gg/wJZ7DVW8mm
[slack]: https://join.slack.com/t/hyperswitch-io/shared_invite/zt-1k6cz4lee-SAJzhz6bjmpp4jZCDOtOIg
[github-discussions]: https://github.com/juspay/hyperswitch/discussions
@@ -314,7 +323,6 @@ Check the [CHANGELOG.md](./CHANGELOG.md) file for details.
This product is licensed under the [Apache 2.0 License](LICENSE).
-
✨ Thanks to all contributors
diff --git a/config/docker_compose.toml b/config/docker_compose.toml
index a5294546de41..986240f0a36b 100644
--- a/config/docker_compose.toml
+++ b/config/docker_compose.toml
@@ -15,7 +15,7 @@ level = "DEBUG" # What you see in your terminal.
[log.telemetry]
traces_enabled = false # Whether traces are enabled.
-metrics_enabled = false # Whether metrics are enabled.
+metrics_enabled = true # Whether metrics are enabled.
ignore_errors = false # Whether to ignore errors during traces or metrics pipeline setup.
otel_exporter_otlp_endpoint = "https://otel-collector:4317" # Endpoint to send metrics and traces to.
use_xray_generator = false
diff --git a/connector-template/test.rs b/connector-template/test.rs
index 5bbf761dea19..7b093ddb6efa 100644
--- a/connector-template/test.rs
+++ b/connector-template/test.rs
@@ -17,6 +17,7 @@ impl utils::Connector for {{project-name | downcase | pascal_case}}Test {
connector: Box::new(&{{project-name | downcase | pascal_case}}),
connector_name: types::Connector::{{project-name | downcase | pascal_case}},
get_token: types::api::GetToken::Connector,
+ merchant_connector_id: None,
}
}
diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs
index c4e4aa90c4b8..ffefaa2ad2c4 100644
--- a/crates/api_models/src/enums.rs
+++ b/crates/api_models/src/enums.rs
@@ -531,8 +531,8 @@ pub enum FieldType {
UserCountry { options: Vec }, //for country inside payment method data ex- bank redirect
UserCurrency { options: Vec },
UserBillingName,
- UserAddressline1,
- UserAddressline2,
+ UserAddressLine1,
+ UserAddressLine2,
UserAddressCity,
UserAddressPincode,
UserAddressState,
diff --git a/crates/api_models/src/events/user.rs b/crates/api_models/src/events/user.rs
index 2a896cc38776..4e9f2f284173 100644
--- a/crates/api_models/src/events/user.rs
+++ b/crates/api_models/src/events/user.rs
@@ -1,6 +1,6 @@
use common_utils::events::{ApiEventMetric, ApiEventsType};
-use crate::user::{ConnectAccountRequest, ConnectAccountResponse};
+use crate::user::{ChangePasswordRequest, ConnectAccountRequest, ConnectAccountResponse};
impl ApiEventMetric for ConnectAccountResponse {
fn get_api_event_type(&self) -> Option {
@@ -12,3 +12,5 @@ impl ApiEventMetric for ConnectAccountResponse {
}
impl ApiEventMetric for ConnectAccountRequest {}
+
+common_utils::impl_misc_api_event_type!(ChangePasswordRequest);
diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs
index 8710c69aa5c6..dfb8e8999771 100644
--- a/crates/api_models/src/payment_methods.rs
+++ b/crates/api_models/src/payment_methods.rs
@@ -352,6 +352,9 @@ impl SurchargeDetailsResponse {
request_surcharge_details.surcharge_amount == self.surcharge_amount
&& request_surcharge_details.tax_amount.unwrap_or(0) == self.tax_on_surcharge_amount
}
+ pub fn get_total_surcharge_amount(&self) -> i64 {
+ self.surcharge_amount + self.tax_on_surcharge_amount
+ }
}
#[derive(Clone, Debug)]
diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs
index a077a6d56366..5556c0a282c3 100644
--- a/crates/api_models/src/payments.rs
+++ b/crates/api_models/src/payments.rs
@@ -312,6 +312,18 @@ pub struct PaymentsRequest {
pub payment_type: Option,
}
+impl PaymentsRequest {
+ pub fn get_total_capturable_amount(&self) -> Option {
+ let surcharge_amount = self
+ .surcharge_details
+ .map(|surcharge_details| {
+ surcharge_details.surcharge_amount + surcharge_details.tax_amount.unwrap_or(0)
+ })
+ .unwrap_or(0);
+ self.amount
+ .map(|amount| i64::from(amount) + surcharge_amount)
+ }
+}
#[derive(
Default, Debug, Clone, serde::Serialize, serde::Deserialize, Copy, ToSchema, PartialEq,
)]
@@ -335,6 +347,9 @@ impl RequestSurchargeDetails {
final_amount: original_amount + surcharge_amount + tax_on_surcharge_amount,
}
}
+ pub fn get_total_surcharge_amount(&self) -> i64 {
+ self.surcharge_amount + self.tax_amount.unwrap_or(0)
+ }
}
#[derive(Default, Debug, Clone, Copy)]
diff --git a/crates/api_models/src/user.rs b/crates/api_models/src/user.rs
index 91f7702c654e..41ea9cc5193a 100644
--- a/crates/api_models/src/user.rs
+++ b/crates/api_models/src/user.rs
@@ -19,3 +19,9 @@ pub struct ConnectAccountResponse {
#[serde(skip_serializing)]
pub user_id: String,
}
+
+#[derive(serde::Deserialize, Debug, serde::Serialize)]
+pub struct ChangePasswordRequest {
+ pub new_password: Secret,
+ pub old_password: Secret,
+}
diff --git a/crates/data_models/src/payments/payment_attempt.rs b/crates/data_models/src/payments/payment_attempt.rs
index 80ae283be85b..a937c785902f 100644
--- a/crates/data_models/src/payments/payment_attempt.rs
+++ b/crates/data_models/src/payments/payment_attempt.rs
@@ -264,6 +264,8 @@ pub enum PaymentAttemptUpdate {
error_message: Option>,
amount_capturable: Option,
updated_by: String,
+ surcharge_amount: Option,
+ tax_amount: Option,
merchant_connector_id: Option,
},
RejectUpdate {
@@ -291,8 +293,6 @@ pub enum PaymentAttemptUpdate {
error_reason: Option>,
connector_response_reference_id: Option,
amount_capturable: Option,
- surcharge_amount: Option,
- tax_amount: Option,
updated_by: String,
authentication_data: Option,
encoded_data: Option,
@@ -321,11 +321,10 @@ pub enum PaymentAttemptUpdate {
error_message: Option>,
error_reason: Option >,
amount_capturable: Option,
- surcharge_amount: Option,
- tax_amount: Option,
updated_by: String,
unified_code: Option>,
unified_message: Option >,
+ connector_transaction_id: Option,
},
CaptureUpdate {
amount_to_capture: Option,
diff --git a/crates/diesel_models/src/payment_attempt.rs b/crates/diesel_models/src/payment_attempt.rs
index 82ab9a1c02e1..9cc6632c638e 100644
--- a/crates/diesel_models/src/payment_attempt.rs
+++ b/crates/diesel_models/src/payment_attempt.rs
@@ -180,6 +180,8 @@ pub enum PaymentAttemptUpdate {
error_code: Option>,
error_message: Option >,
amount_capturable: Option,
+ surcharge_amount: Option,
+ tax_amount: Option,
updated_by: String,
merchant_connector_id: Option,
},
@@ -208,8 +210,6 @@ pub enum PaymentAttemptUpdate {
error_reason: Option>,
connector_response_reference_id: Option,
amount_capturable: Option,
- surcharge_amount: Option,
- tax_amount: Option,
updated_by: String,
authentication_data: Option,
encoded_data: Option,
@@ -238,11 +238,10 @@ pub enum PaymentAttemptUpdate {
error_message: Option>,
error_reason: Option >,
amount_capturable: Option,
- surcharge_amount: Option,
- tax_amount: Option,
updated_by: String,
unified_code: Option>,
unified_message: Option >,
+ connector_transaction_id: Option,
},
CaptureUpdate {
amount_to_capture: Option,
@@ -442,6 +441,8 @@ impl From for PaymentAttemptUpdateInternal {
amount_capturable,
updated_by,
merchant_connector_id,
+ surcharge_amount,
+ tax_amount,
} => Self {
amount: Some(amount),
currency: Some(currency),
@@ -462,6 +463,8 @@ impl From for PaymentAttemptUpdateInternal {
amount_capturable,
updated_by,
merchant_connector_id,
+ surcharge_amount,
+ tax_amount,
..Default::default()
},
PaymentAttemptUpdate::VoidUpdate {
@@ -500,8 +503,6 @@ impl From for PaymentAttemptUpdateInternal {
error_reason,
connector_response_reference_id,
amount_capturable,
- surcharge_amount,
- tax_amount,
updated_by,
authentication_data,
encoded_data,
@@ -523,8 +524,6 @@ impl From for PaymentAttemptUpdateInternal {
connector_response_reference_id,
amount_capturable,
updated_by,
- surcharge_amount,
- tax_amount,
authentication_data,
encoded_data,
unified_code,
@@ -538,11 +537,10 @@ impl From for PaymentAttemptUpdateInternal {
error_message,
error_reason,
amount_capturable,
- surcharge_amount,
- tax_amount,
updated_by,
unified_code,
unified_message,
+ connector_transaction_id,
} => Self {
connector,
status: Some(status),
@@ -552,10 +550,9 @@ impl From for PaymentAttemptUpdateInternal {
error_reason,
amount_capturable,
updated_by,
- surcharge_amount,
- tax_amount,
unified_code,
unified_message,
+ connector_transaction_id,
..Default::default()
},
PaymentAttemptUpdate::StatusUpdate { status, updated_by } => Self {
diff --git a/crates/drainer/src/lib.rs b/crates/drainer/src/lib.rs
index 7ccfd600d662..94a29e3b0a04 100644
--- a/crates/drainer/src/lib.rs
+++ b/crates/drainer/src/lib.rs
@@ -23,7 +23,7 @@ pub async fn start_drainer(
loop_interval: u32,
) -> errors::DrainerResult<()> {
let mut stream_index: u8 = 0;
- let mut jobs_picked: u8 = 0;
+ let jobs_picked = Arc::new(atomic::AtomicU8::new(0));
let mut shutdown_interval =
tokio::time::interval(std::time::Duration::from_millis(shutdown_interval.into()));
@@ -61,15 +61,15 @@ pub async fn start_drainer(
stream_index,
max_read_count,
active_tasks.clone(),
+ jobs_picked.clone(),
));
- jobs_picked += 1;
}
- (stream_index, jobs_picked) = utils::increment_stream_index(
- (stream_index, jobs_picked),
+ stream_index = utils::increment_stream_index(
+ (stream_index, jobs_picked.clone()),
number_of_streams,
- &mut loop_interval,
)
.await;
+ loop_interval.tick().await;
}
Ok(()) | Err(mpsc::error::TryRecvError::Disconnected) => {
logger::info!("Awaiting shutdown!");
@@ -114,18 +114,25 @@ pub async fn redis_error_receiver(rx: oneshot::Receiver<()>, shutdown_channel: m
}
}
+#[router_env::instrument(skip_all)]
async fn drainer_handler(
store: Arc,
stream_index: u8,
max_read_count: u64,
active_tasks: Arc,
+ jobs_picked: Arc,
) -> errors::DrainerResult<()> {
active_tasks.fetch_add(1, atomic::Ordering::Release);
let stream_name = utils::get_drainer_stream_name(store.clone(), stream_index);
- let drainer_result =
- Box::pin(drainer(store.clone(), max_read_count, stream_name.as_str())).await;
+ let drainer_result = Box::pin(drainer(
+ store.clone(),
+ max_read_count,
+ stream_name.as_str(),
+ jobs_picked,
+ ))
+ .await;
if let Err(error) = drainer_result {
logger::error!(?error)
@@ -145,11 +152,15 @@ async fn drainer(
store: Arc,
max_read_count: u64,
stream_name: &str,
+ jobs_picked: Arc,
) -> errors::DrainerResult<()> {
let stream_read =
match utils::read_from_stream(stream_name, max_read_count, store.redis_conn.as_ref()).await
{
- Ok(result) => result,
+ Ok(result) => {
+ jobs_picked.fetch_add(1, atomic::Ordering::SeqCst);
+ result
+ }
Err(error) => {
if let errors::DrainerError::RedisError(redis_err) = error.current_context() {
if let redis_interface::errors::RedisError::StreamEmptyOrNotAvailable =
diff --git a/crates/drainer/src/settings.rs b/crates/drainer/src/settings.rs
index cc64a99e463c..8101abf5028e 100644
--- a/crates/drainer/src/settings.rs
+++ b/crates/drainer/src/settings.rs
@@ -79,7 +79,7 @@ impl Default for DrainerSettings {
num_partitions: 64,
max_read_count: 100,
shutdown_interval: 1000, // in milliseconds
- loop_interval: 500, // in milliseconds
+ loop_interval: 100, // in milliseconds
}
}
}
diff --git a/crates/drainer/src/utils.rs b/crates/drainer/src/utils.rs
index 5a995652bb11..2bd9f092f12c 100644
--- a/crates/drainer/src/utils.rs
+++ b/crates/drainer/src/utils.rs
@@ -1,16 +1,20 @@
-use std::{collections::HashMap, sync::Arc};
+use std::{
+ collections::HashMap,
+ sync::{atomic, Arc},
+};
use error_stack::IntoReport;
use redis_interface as redis;
use crate::{
errors::{self, DrainerError},
- logger, metrics, services,
+ logger, metrics, services, tracing,
};
pub type StreamEntries = Vec<(String, HashMap)>;
pub type StreamReadResult = HashMap;
+#[router_env::instrument(skip_all)]
pub async fn is_stream_available(stream_index: u8, store: Arc) -> bool {
let stream_key_flag = get_stream_key_flag(store.clone(), stream_index);
@@ -127,19 +131,18 @@ pub fn parse_stream_entries<'a>(
// Here the output is in the format (stream_index, jobs_picked),
// similar to the first argument of the function
pub async fn increment_stream_index(
- (index, jobs_picked): (u8, u8),
+ (index, jobs_picked): (u8, Arc),
total_streams: u8,
- interval: &mut tokio::time::Interval,
-) -> (u8, u8) {
+) -> u8 {
if index == total_streams - 1 {
- interval.tick().await;
- match jobs_picked {
+ match jobs_picked.load(atomic::Ordering::SeqCst) {
0 => metrics::CYCLES_COMPLETED_UNSUCCESSFULLY.add(&metrics::CONTEXT, 1, &[]),
_ => metrics::CYCLES_COMPLETED_SUCCESSFULLY.add(&metrics::CONTEXT, 1, &[]),
}
- (0, 0)
+ jobs_picked.store(0, atomic::Ordering::SeqCst);
+ 0
} else {
- (index + 1, jobs_picked)
+ index + 1
}
}
diff --git a/crates/euclid/src/backend/vir_interpreter/types.rs b/crates/euclid/src/backend/vir_interpreter/types.rs
index a144cdaafd08..d0eca5fec2ef 100644
--- a/crates/euclid/src/backend/vir_interpreter/types.rs
+++ b/crates/euclid/src/backend/vir_interpreter/types.rs
@@ -74,6 +74,10 @@ impl Context {
}
}
+ if let Some(card_network) = payment_method.card_network {
+ enum_values.insert(EuclidValue::CardNetwork(card_network));
+ }
+
if let Some(at) = payment.authentication_type {
enum_values.insert(EuclidValue::AuthenticationType(at));
}
diff --git a/crates/router/src/analytics.rs b/crates/router/src/analytics.rs
index 43033cf9cfd1..f31e908e0dc3 100644
--- a/crates/router/src/analytics.rs
+++ b/crates/router/src/analytics.rs
@@ -21,6 +21,7 @@ pub mod routes {
services::{
api,
authentication::{self as auth, AuthToken, AuthenticationData},
+ authorization::permissions::Permission,
ApplicationResponse,
},
types::domain::UserEmail,
@@ -135,7 +136,7 @@ pub mod routes {
.await
.map(ApplicationResponse::Json)
},
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::Analytics),
api_locking::LockAction::NotApplicable,
))
.await
@@ -171,7 +172,7 @@ pub mod routes {
.await
.map(ApplicationResponse::Json)
},
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::Analytics),
api_locking::LockAction::NotApplicable,
))
.await
@@ -207,7 +208,7 @@ pub mod routes {
.await
.map(ApplicationResponse::Json)
},
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::Analytics),
api_locking::LockAction::NotApplicable,
))
.await
@@ -233,7 +234,7 @@ pub mod routes {
.await
.map(ApplicationResponse::Json)
},
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::Analytics),
api_locking::LockAction::NotApplicable,
))
.await
@@ -259,7 +260,7 @@ pub mod routes {
.await
.map(ApplicationResponse::Json)
},
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::Analytics),
api_locking::LockAction::NotApplicable,
))
.await
@@ -285,7 +286,7 @@ pub mod routes {
.await
.map(ApplicationResponse::Json)
},
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::Analytics),
api_locking::LockAction::NotApplicable,
))
.await
@@ -307,7 +308,7 @@ pub mod routes {
.await
.map(ApplicationResponse::Json)
},
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::Analytics),
api_locking::LockAction::NotApplicable,
))
.await
@@ -333,7 +334,7 @@ pub mod routes {
.await
.map(ApplicationResponse::Json)
},
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::Analytics),
api_locking::LockAction::NotApplicable,
))
.await
@@ -385,7 +386,7 @@ pub mod routes {
.await
.map(ApplicationResponse::Json)
},
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::Analytics),
api_locking::LockAction::NotApplicable,
))
.await
@@ -437,7 +438,7 @@ pub mod routes {
.await
.map(ApplicationResponse::Json)
},
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::Analytics),
api_locking::LockAction::NotApplicable,
))
.await
@@ -489,7 +490,7 @@ pub mod routes {
.await
.map(ApplicationResponse::Json)
},
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::Analytics),
api_locking::LockAction::NotApplicable,
))
.await
@@ -525,7 +526,7 @@ pub mod routes {
.await
.map(ApplicationResponse::Json)
},
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::Analytics),
api_locking::LockAction::NotApplicable,
))
.await
@@ -551,7 +552,7 @@ pub mod routes {
.await
.map(ApplicationResponse::Json)
},
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::Analytics),
api_locking::LockAction::NotApplicable,
))
.await
diff --git a/crates/router/src/configs/defaults.rs b/crates/router/src/configs/defaults.rs
index a0da9c88ef35..2eddaf3084d7 100644
--- a/crates/router/src/configs/defaults.rs
+++ b/crates/router/src/configs/defaults.rs
@@ -99,7 +99,7 @@ impl Default for super::settings::DrainerSettings {
num_partitions: 64,
max_read_count: 100,
shutdown_interval: 1000,
- loop_interval: 500,
+ loop_interval: 100,
}
}
}
@@ -582,7 +582,7 @@ impl Default for super::settings::RequiredFields {
RequiredFieldInfo {
required_field: "billing.address.line1".to_string(),
display_name: "line1".to_string(),
- field_type: enums::FieldType::UserAddressline1,
+ field_type: enums::FieldType::UserAddressLine1,
value: None,
}
),
@@ -806,7 +806,7 @@ impl Default for super::settings::RequiredFields {
RequiredFieldInfo {
required_field: "billing.address.line1".to_string(),
display_name: "line1".to_string(),
- field_type: enums::FieldType::UserAddressline1,
+ field_type: enums::FieldType::UserAddressLine1,
value: None,
}
),
@@ -1238,7 +1238,7 @@ impl Default for super::settings::RequiredFields {
RequiredFieldInfo {
required_field: "billing.address.line1".to_string(),
display_name: "line1".to_string(),
- field_type: enums::FieldType::UserAddressline1,
+ field_type: enums::FieldType::UserAddressLine1,
value: None,
}
),
@@ -1247,7 +1247,7 @@ impl Default for super::settings::RequiredFields {
RequiredFieldInfo {
required_field: "billing.address.line2".to_string(),
display_name: "line2".to_string(),
- field_type: enums::FieldType::UserAddressline2,
+ field_type: enums::FieldType::UserAddressLine2,
value: None,
}
),
@@ -2582,7 +2582,7 @@ impl Default for super::settings::RequiredFields {
RequiredFieldInfo {
required_field: "billing.address.line1".to_string(),
display_name: "line1".to_string(),
- field_type: enums::FieldType::UserAddressline1,
+ field_type: enums::FieldType::UserAddressLine1,
value: None,
}
),
@@ -3014,7 +3014,7 @@ impl Default for super::settings::RequiredFields {
RequiredFieldInfo {
required_field: "billing.address.line1".to_string(),
display_name: "line1".to_string(),
- field_type: enums::FieldType::UserAddressline1,
+ field_type: enums::FieldType::UserAddressLine1,
value: None,
}
),
@@ -3023,7 +3023,7 @@ impl Default for super::settings::RequiredFields {
RequiredFieldInfo {
required_field: "billing.address.line2".to_string(),
display_name: "line2".to_string(),
- field_type: enums::FieldType::UserAddressline2,
+ field_type: enums::FieldType::UserAddressLine2,
value: None,
}
),
diff --git a/crates/router/src/connector/aci.rs b/crates/router/src/connector/aci.rs
index f51c91f441df..f6384bf0a5c5 100644
--- a/crates/router/src/connector/aci.rs
+++ b/crates/router/src/connector/aci.rs
@@ -79,6 +79,7 @@ impl ConnectorCommon for Aci {
.join("; ")
}),
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/adyen.rs b/crates/router/src/connector/adyen.rs
index 676f15d2f564..e101b796b8d4 100644
--- a/crates/router/src/connector/adyen.rs
+++ b/crates/router/src/connector/adyen.rs
@@ -74,6 +74,7 @@ impl ConnectorCommon for Adyen {
message: response.message,
reason: None,
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
@@ -256,6 +257,7 @@ impl
message: response.message,
reason: None,
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
@@ -375,6 +377,7 @@ impl
message: response.message,
reason: None,
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
@@ -546,6 +549,7 @@ impl
message: response.message,
reason: None,
attempt_status: None,
+ connector_transaction_id: None,
})
}
@@ -716,6 +720,7 @@ impl
message: response.message,
reason: None,
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
@@ -920,6 +925,7 @@ impl
message: response.message,
reason: None,
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
@@ -1439,6 +1445,7 @@ impl services::ConnectorIntegration {
@@ -929,6 +931,7 @@ fn get_error_response(
reason: Some(message.to_string()),
status_code,
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/authorizedotnet/transformers.rs b/crates/router/src/connector/authorizedotnet/transformers.rs
index 884504154e8f..2c8a63a53e5c 100644
--- a/crates/router/src/connector/authorizedotnet/transformers.rs
+++ b/crates/router/src/connector/authorizedotnet/transformers.rs
@@ -574,6 +574,7 @@ impl
reason: None,
status_code: item.http_code,
attempt_status: None,
+ connector_transaction_id: None,
})
});
let metadata = transaction_response
@@ -649,6 +650,7 @@ impl
reason: None,
status_code: item.http_code,
attempt_status: None,
+ connector_transaction_id: None,
})
});
let metadata = transaction_response
@@ -792,6 +794,7 @@ impl TryFrom types::Error
reason: None,
status_code,
attempt_status: None,
+ connector_transaction_id: None,
}
}
diff --git a/crates/router/src/connector/bambora.rs b/crates/router/src/connector/bambora.rs
index ff6fdcb46769..19849763ed8e 100644
--- a/crates/router/src/connector/bambora.rs
+++ b/crates/router/src/connector/bambora.rs
@@ -96,6 +96,7 @@ impl ConnectorCommon for Bambora {
message: response.message,
reason: Some(serde_json::to_string(&response.details).unwrap_or_default()),
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/bankofamerica.rs b/crates/router/src/connector/bankofamerica.rs
index b6e19fa0d296..a01ea72338c5 100644
--- a/crates/router/src/connector/bankofamerica.rs
+++ b/crates/router/src/connector/bankofamerica.rs
@@ -233,6 +233,7 @@ impl ConnectorCommon for Bankofamerica {
message,
reason: Some(connector_reason),
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/bankofamerica/transformers.rs b/crates/router/src/connector/bankofamerica/transformers.rs
index f6cda8ac23ce..70db9a6d8797 100644
--- a/crates/router/src/connector/bankofamerica/transformers.rs
+++ b/crates/router/src/connector/bankofamerica/transformers.rs
@@ -540,6 +540,7 @@ impl
reason: error_response.error_information.reason,
status_code: item.http_code,
attempt_status: None,
+ connector_transaction_id: None,
}),
..item.data
}),
@@ -596,6 +597,7 @@ impl
reason: error_response.error_information.reason,
status_code: item.http_code,
attempt_status: None,
+ connector_transaction_id: None,
}),
..item.data
}),
@@ -652,6 +654,7 @@ impl
reason: error_response.error_information.reason,
status_code: item.http_code,
attempt_status: None,
+ connector_transaction_id: None,
}),
..item.data
}),
@@ -851,7 +854,7 @@ impl From for enums::RefundStatus {
BankofamericaRefundStatus::Succeeded | BankofamericaRefundStatus::Transmitted => {
Self::Success
}
- BankofamericaRefundStatus::Failed => Self::Failure,
+ BankofamericaRefundStatus::Failed | BankofamericaRefundStatus::Voided => Self::Failure,
BankofamericaRefundStatus::Pending => Self::Pending,
}
}
@@ -888,6 +891,7 @@ pub enum BankofamericaRefundStatus {
Transmitted,
Failed,
Pending,
+ Voided,
}
#[derive(Debug, Deserialize)]
diff --git a/crates/router/src/connector/bitpay.rs b/crates/router/src/connector/bitpay.rs
index 856d0a9ec9d7..b6bbaafc4a38 100644
--- a/crates/router/src/connector/bitpay.rs
+++ b/crates/router/src/connector/bitpay.rs
@@ -121,6 +121,7 @@ impl ConnectorCommon for Bitpay {
message: response.error,
reason: response.message,
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/bluesnap.rs b/crates/router/src/connector/bluesnap.rs
index d1aa1fa25ee6..0bc56d4e9955 100644
--- a/crates/router/src/connector/bluesnap.rs
+++ b/crates/router/src/connector/bluesnap.rs
@@ -127,6 +127,7 @@ impl ConnectorCommon for Bluesnap {
.unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
reason: Some(reason),
attempt_status: None,
+ connector_transaction_id: None,
}
}
bluesnap::BluesnapErrors::Auth(error_res) => ErrorResponse {
@@ -135,6 +136,7 @@ impl ConnectorCommon for Bluesnap {
message: error_res.error_name.clone().unwrap_or(error_res.error_code),
reason: Some(error_res.error_description),
attempt_status: None,
+ connector_transaction_id: None,
},
bluesnap::BluesnapErrors::General(error_response) => {
let (error_res, attempt_status) = if res.status_code == 403
@@ -156,6 +158,7 @@ impl ConnectorCommon for Bluesnap {
message: error_response,
reason: Some(error_res),
attempt_status,
+ connector_transaction_id: None,
}
}
};
diff --git a/crates/router/src/connector/boku.rs b/crates/router/src/connector/boku.rs
index 87e8fd0eb96a..a2ae9d628134 100644
--- a/crates/router/src/connector/boku.rs
+++ b/crates/router/src/connector/boku.rs
@@ -131,6 +131,7 @@ impl ConnectorCommon for Boku {
message: response.message,
reason: response.reason,
attempt_status: None,
+ connector_transaction_id: None,
}),
Err(_) => get_xml_deserialized(res),
}
@@ -668,6 +669,7 @@ fn get_xml_deserialized(res: Response) -> CustomResult Ok(ErrorResponse {
@@ -141,6 +142,7 @@ impl ConnectorCommon for Braintree {
message: consts::NO_ERROR_MESSAGE.to_string(),
reason: Some(response.errors),
attempt_status: None,
+ connector_transaction_id: None,
}),
Err(error_msg) => {
logger::error!(deserialization_error =? error_msg);
diff --git a/crates/router/src/connector/braintree/braintree_graphql_transformers.rs b/crates/router/src/connector/braintree/braintree_graphql_transformers.rs
index bf51973237c5..5069a9fe38d2 100644
--- a/crates/router/src/connector/braintree/braintree_graphql_transformers.rs
+++ b/crates/router/src/connector/braintree/braintree_graphql_transformers.rs
@@ -317,6 +317,7 @@ fn get_error_response(
reason: error_reason,
status_code: http_code,
attempt_status: None,
+ connector_transaction_id: None,
})
}
diff --git a/crates/router/src/connector/cashtocode.rs b/crates/router/src/connector/cashtocode.rs
index a8d7d6d80504..6749f4189340 100644
--- a/crates/router/src/connector/cashtocode.rs
+++ b/crates/router/src/connector/cashtocode.rs
@@ -120,6 +120,7 @@ impl ConnectorCommon for Cashtocode {
message: response.error_description,
reason: None,
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/cashtocode/transformers.rs b/crates/router/src/connector/cashtocode/transformers.rs
index 42e47c077e8c..cfca998e06c3 100644
--- a/crates/router/src/connector/cashtocode/transformers.rs
+++ b/crates/router/src/connector/cashtocode/transformers.rs
@@ -218,6 +218,7 @@ impl
message: error_data.error_description,
reason: None,
attempt_status: None,
+ connector_transaction_id: None,
}),
),
CashtocodePaymentsResponse::CashtoCodeData(response_data) => {
diff --git a/crates/router/src/connector/checkout.rs b/crates/router/src/connector/checkout.rs
index ca2556544f90..312a91196de7 100644
--- a/crates/router/src/connector/checkout.rs
+++ b/crates/router/src/connector/checkout.rs
@@ -132,6 +132,7 @@ impl ConnectorCommon for Checkout {
.map(|errors| errors.join(" & "))
.or(response.error_type),
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/checkout/transformers.rs b/crates/router/src/connector/checkout/transformers.rs
index 6ad040da2842..90e65c8b0474 100644
--- a/crates/router/src/connector/checkout/transformers.rs
+++ b/crates/router/src/connector/checkout/transformers.rs
@@ -577,6 +577,7 @@ impl TryFrom>
.unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()),
reason: item.response.response_summary,
attempt_status: None,
+ connector_transaction_id: None,
})
} else {
None
@@ -625,6 +626,7 @@ impl TryFrom>
.unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()),
reason: item.response.response_summary,
attempt_status: None,
+ connector_transaction_id: None,
})
} else {
None
diff --git a/crates/router/src/connector/coinbase.rs b/crates/router/src/connector/coinbase.rs
index 9c0a06a52c90..b294a4474f69 100644
--- a/crates/router/src/connector/coinbase.rs
+++ b/crates/router/src/connector/coinbase.rs
@@ -109,6 +109,7 @@ impl ConnectorCommon for Coinbase {
message: response.error.message,
reason: response.error.code,
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/cryptopay.rs b/crates/router/src/connector/cryptopay.rs
index 417a36145b92..2af40a298ce0 100644
--- a/crates/router/src/connector/cryptopay.rs
+++ b/crates/router/src/connector/cryptopay.rs
@@ -168,6 +168,7 @@ impl ConnectorCommon for Cryptopay {
message: response.error.message,
reason: response.error.reason,
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/cybersource.rs b/crates/router/src/connector/cybersource.rs
index ce283b12b798..1868611184f9 100644
--- a/crates/router/src/connector/cybersource.rs
+++ b/crates/router/src/connector/cybersource.rs
@@ -137,6 +137,7 @@ impl ConnectorCommon for Cybersource {
message,
reason: Some(connector_reason),
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/cybersource/transformers.rs b/crates/router/src/connector/cybersource/transformers.rs
index 0e81b6b59dff..33b8fa56d00e 100644
--- a/crates/router/src/connector/cybersource/transformers.rs
+++ b/crates/router/src/connector/cybersource/transformers.rs
@@ -552,6 +552,7 @@ impl
reason: Some(error.reason),
status_code: item.http_code,
attempt_status: None,
+ connector_transaction_id: None,
}),
_ => Ok(types::PaymentsResponseData::TransactionResponse {
resource_id: types::ResponseId::ConnectorTransactionId(
diff --git a/crates/router/src/connector/dlocal.rs b/crates/router/src/connector/dlocal.rs
index 4ae3a292fdae..28ae058286f0 100644
--- a/crates/router/src/connector/dlocal.rs
+++ b/crates/router/src/connector/dlocal.rs
@@ -136,6 +136,7 @@ impl ConnectorCommon for Dlocal {
message: response.message,
reason: response.param,
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/dummyconnector.rs b/crates/router/src/connector/dummyconnector.rs
index 9edcd957ff09..961ef005f2f3 100644
--- a/crates/router/src/connector/dummyconnector.rs
+++ b/crates/router/src/connector/dummyconnector.rs
@@ -112,6 +112,7 @@ impl ConnectorCommon for DummyConnector {
message: response.error.message,
reason: response.error.reason,
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/fiserv.rs b/crates/router/src/connector/fiserv.rs
index 2bdb7177d941..28b6d932760d 100644
--- a/crates/router/src/connector/fiserv.rs
+++ b/crates/router/src/connector/fiserv.rs
@@ -152,6 +152,7 @@ impl ConnectorCommon for Fiserv {
reason: first_error.field.to_owned(),
status_code: res.status_code,
attempt_status: None,
+ connector_transaction_id: None,
})
})
.unwrap_or(types::ErrorResponse {
@@ -160,6 +161,7 @@ impl ConnectorCommon for Fiserv {
reason: None,
status_code: res.status_code,
attempt_status: None,
+ connector_transaction_id: None,
}))
}
}
diff --git a/crates/router/src/connector/forte.rs b/crates/router/src/connector/forte.rs
index 3aa7cee32878..948db00c936f 100644
--- a/crates/router/src/connector/forte.rs
+++ b/crates/router/src/connector/forte.rs
@@ -131,6 +131,7 @@ impl ConnectorCommon for Forte {
message,
reason: None,
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/globalpay.rs b/crates/router/src/connector/globalpay.rs
index 26494d349b88..39452e53df17 100644
--- a/crates/router/src/connector/globalpay.rs
+++ b/crates/router/src/connector/globalpay.rs
@@ -105,6 +105,7 @@ impl ConnectorCommon for Globalpay {
message: response.detailed_error_description,
reason: None,
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
@@ -319,6 +320,7 @@ impl ConnectorIntegration
reason: Some(error_response.error_info),
status_code: item.http_code,
attempt_status: None,
+ connector_transaction_id: None,
}),
..item.data
}),
@@ -810,6 +811,7 @@ impl TryFrom for types::ErrorResponse {
reason: None,
status_code: http_code,
attempt_status: None,
+ connector_transaction_id: None,
}
}
}
diff --git a/crates/router/src/connector/noon.rs b/crates/router/src/connector/noon.rs
index b6ed231e5b50..457928642554 100644
--- a/crates/router/src/connector/noon.rs
+++ b/crates/router/src/connector/noon.rs
@@ -137,6 +137,7 @@ impl ConnectorCommon for Noon {
message: response.class_description,
reason: Some(response.message),
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/noon/transformers.rs b/crates/router/src/connector/noon/transformers.rs
index 27a874930bcc..5ff92582051a 100644
--- a/crates/router/src/connector/noon/transformers.rs
+++ b/crates/router/src/connector/noon/transformers.rs
@@ -512,6 +512,7 @@ impl
reason: Some(error_message),
status_code: item.http_code,
attempt_status: None,
+ connector_transaction_id: None,
}),
_ => {
let connector_response_reference_id =
diff --git a/crates/router/src/connector/nuvei/transformers.rs b/crates/router/src/connector/nuvei/transformers.rs
index c23114e2a96b..b79b2c892643 100644
--- a/crates/router/src/connector/nuvei/transformers.rs
+++ b/crates/router/src/connector/nuvei/transformers.rs
@@ -623,11 +623,9 @@ impl TryFrom for NuveiBIC {
| api_models::enums::BankNames::TsbBank
| api_models::enums::BankNames::TescoBank
| api_models::enums::BankNames::UlsterBank => {
- Err(errors::ConnectorError::NotSupported {
- message: bank.to_string(),
- connector: "Nuvei",
- }
- .into())
+ Err(errors::ConnectorError::NotImplemented(
+ utils::get_unimplemented_payment_method_error_message("Nuvei"),
+ ))?
}
}
}
@@ -693,10 +691,9 @@ impl
bank_name.map(NuveiBIC::try_from).transpose()?,
)
}
- _ => Err(errors::ConnectorError::NotSupported {
- message: "Bank Redirect".to_string(),
- connector: "Nuvei",
- })?,
+ _ => Err(errors::ConnectorError::NotImplemented(
+ utils::get_unimplemented_payment_method_error_message("Nuvei"),
+ ))?,
};
Ok(Self {
payment_option: PaymentOption {
@@ -1580,6 +1577,7 @@ fn get_error_response(
reason: None,
status_code: http_code,
attempt_status: None,
+ connector_transaction_id: None,
})
}
diff --git a/crates/router/src/connector/opayo.rs b/crates/router/src/connector/opayo.rs
index ba0fb2046b7c..73a793adcf70 100644
--- a/crates/router/src/connector/opayo.rs
+++ b/crates/router/src/connector/opayo.rs
@@ -108,6 +108,7 @@ impl ConnectorCommon for Opayo {
message: response.message,
reason: response.reason,
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/opennode.rs b/crates/router/src/connector/opennode.rs
index 41d1e6c3d88c..c4f3d3682dca 100644
--- a/crates/router/src/connector/opennode.rs
+++ b/crates/router/src/connector/opennode.rs
@@ -111,6 +111,7 @@ impl ConnectorCommon for Opennode {
message: response.message,
reason: None,
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/payeezy.rs b/crates/router/src/connector/payeezy.rs
index 33a8ec65152e..0be640f8fbe4 100644
--- a/crates/router/src/connector/payeezy.rs
+++ b/crates/router/src/connector/payeezy.rs
@@ -124,6 +124,7 @@ impl ConnectorCommon for Payeezy {
message: error_messages.join(", "),
reason: None,
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/payeezy/transformers.rs b/crates/router/src/connector/payeezy/transformers.rs
index e2e837929c41..817ab43ac717 100644
--- a/crates/router/src/connector/payeezy/transformers.rs
+++ b/crates/router/src/connector/payeezy/transformers.rs
@@ -72,11 +72,9 @@ impl TryFrom for PayeezyCardType {
utils::CardIssuer::Maestro
| utils::CardIssuer::DinersClub
| utils::CardIssuer::JCB
- | utils::CardIssuer::CarteBlanche => Err(errors::ConnectorError::NotSupported {
- message: utils::SELECTED_PAYMENT_METHOD.to_string(),
- connector: "Payeezy",
- }
- .into()),
+ | utils::CardIssuer::CarteBlanche => Err(errors::ConnectorError::NotImplemented(
+ utils::get_unimplemented_payment_method_error_message("Payeezy"),
+ ))?,
}
}
}
@@ -262,11 +260,9 @@ fn get_payment_method_data(
| api::PaymentMethodData::Reward
| api::PaymentMethodData::Upi(_)
| api::PaymentMethodData::Voucher(_)
- | api::PaymentMethodData::GiftCard(_) => Err(errors::ConnectorError::NotSupported {
- message: utils::SELECTED_PAYMENT_METHOD.to_string(),
- connector: "Payeezy",
- }
- .into()),
+ | api::PaymentMethodData::GiftCard(_) => Err(errors::ConnectorError::NotImplemented(
+ utils::get_unimplemented_payment_method_error_message("Payeezy"),
+ ))?,
}
}
diff --git a/crates/router/src/connector/payme.rs b/crates/router/src/connector/payme.rs
index 1e67f8a9f350..84367b3a96f6 100644
--- a/crates/router/src/connector/payme.rs
+++ b/crates/router/src/connector/payme.rs
@@ -98,6 +98,7 @@ impl ConnectorCommon for Payme {
response.status_error_details, response.status_additional_info
)),
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/payme/transformers.rs b/crates/router/src/connector/payme/transformers.rs
index 24b7f2b3a0bd..092a8b49fd86 100644
--- a/crates/router/src/connector/payme/transformers.rs
+++ b/crates/router/src/connector/payme/transformers.rs
@@ -227,6 +227,7 @@ impl From<(&PaymePaySaleResponse, u16)> for types::ErrorResponse {
reason: pay_sale_response.status_error_details.to_owned(),
status_code: http_code,
attempt_status: None,
+ connector_transaction_id: None,
}
}
}
@@ -310,6 +311,7 @@ impl From<(&SaleQuery, u16)> for types::ErrorResponse {
reason: sale_query_response.sale_error_text.clone(),
status_code: http_code,
attempt_status: None,
+ connector_transaction_id: None,
}
}
}
diff --git a/crates/router/src/connector/paypal.rs b/crates/router/src/connector/paypal.rs
index 0e8cff8c0569..4e50bc924b33 100644
--- a/crates/router/src/connector/paypal.rs
+++ b/crates/router/src/connector/paypal.rs
@@ -92,6 +92,7 @@ impl Paypal {
message: response.message.clone(),
reason: error_reason.or(Some(response.message)),
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
@@ -245,6 +246,7 @@ impl ConnectorCommon for Paypal {
message: response.message.clone(),
reason,
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
@@ -380,6 +382,7 @@ impl ConnectorIntegration
reason: Some(item.response.response_text),
status_code: item.http_code,
attempt_status: None,
+ connector_transaction_id: None,
}),
..item.data
})
@@ -432,7 +434,6 @@ pub struct ProphetpaySyncResponse {
pub response_text: String,
#[serde(rename = "transactionID")]
pub transaction_id: String,
- pub response_code: String,
}
impl
@@ -462,11 +463,12 @@ impl
Ok(Self {
status: enums::AttemptStatus::Failure,
response: Err(types::ErrorResponse {
- code: item.response.response_code,
+ code: const_val::NO_ERROR_CODE.to_string(),
message: item.response.response_text.clone(),
reason: Some(item.response.response_text),
status_code: item.http_code,
attempt_status: None,
+ connector_transaction_id: None,
}),
..item.data
})
@@ -481,7 +483,6 @@ pub struct ProphetpayVoidResponse {
pub response_text: String,
#[serde(rename = "transactionID")]
pub transaction_id: String,
- pub response_code: String,
}
impl
@@ -511,11 +512,12 @@ impl
Ok(Self {
status: enums::AttemptStatus::VoidFailed,
response: Err(types::ErrorResponse {
- code: item.response.response_code,
+ code: const_val::NO_ERROR_CODE.to_string(),
message: item.response.response_text.clone(),
reason: Some(item.response.response_text),
status_code: item.http_code,
attempt_status: None,
+ connector_transaction_id: None,
}),
..item.data
})
@@ -576,15 +578,12 @@ impl TryFrom<&ProphetpayRouterData<&types::RefundsRouterData>> for Prophet
amount: item.amount.to_owned(),
card_token: card_token_data.card_token,
profile: auth_data.profile_id,
- ref_info: item.router_data.connector_request_reference_id.to_owned(),
- inquiry_reference: item.router_data.connector_request_reference_id.clone(),
+ ref_info: item.router_data.request.refund_id.to_owned(),
+ inquiry_reference: item.router_data.request.refund_id.clone(),
action_type: ProphetpayActionType::get_action_type(&ProphetpayActionType::Refund),
})
} else {
- Err(errors::ConnectorError::NotImplemented(
- "Partial Refund is Not Supported".to_string(),
- )
- .into())
+ Err(errors::ConnectorError::NotImplemented("Partial Refund".to_string()).into())
}
}
}
@@ -594,8 +593,7 @@ impl TryFrom<&ProphetpayRouterData<&types::RefundsRouterData>> for Prophet
pub struct ProphetpayRefundResponse {
pub success: bool,
pub response_text: String,
- pub tran_seq_number: String,
- pub response_code: String,
+ pub tran_seq_number: Option,
}
impl TryFrom>
@@ -609,7 +607,11 @@ impl TryFrom TryFrom>
@@ -658,11 +660,12 @@ impl TryFrom {
logger::error!(deserialization_error =? error_msg);
diff --git a/crates/router/src/connector/rapyd/transformers.rs b/crates/router/src/connector/rapyd/transformers.rs
index 08985ba022fc..898b6ed6d147 100644
--- a/crates/router/src/connector/rapyd/transformers.rs
+++ b/crates/router/src/connector/rapyd/transformers.rs
@@ -458,6 +458,7 @@ impl
message: item.response.status.status.unwrap_or_default(),
reason: data.failure_message.to_owned(),
attempt_status: None,
+ connector_transaction_id: None,
}),
),
_ => {
@@ -499,6 +500,7 @@ impl
message: item.response.status.status.unwrap_or_default(),
reason: item.response.status.message,
attempt_status: None,
+ connector_transaction_id: None,
}),
),
};
diff --git a/crates/router/src/connector/shift4.rs b/crates/router/src/connector/shift4.rs
index 6f3a2b802014..dfb4a7de0811 100644
--- a/crates/router/src/connector/shift4.rs
+++ b/crates/router/src/connector/shift4.rs
@@ -100,6 +100,7 @@ impl ConnectorCommon for Shift4 {
message: response.error.message,
reason: None,
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/square.rs b/crates/router/src/connector/square.rs
index d836285755d4..1f1dee6b9e1b 100644
--- a/crates/router/src/connector/square.rs
+++ b/crates/router/src/connector/square.rs
@@ -124,6 +124,7 @@ impl ConnectorCommon for Square {
.unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
reason: Some(reason),
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/stax.rs b/crates/router/src/connector/stax.rs
index 024211c8caaa..1a0cc54a128d 100644
--- a/crates/router/src/connector/stax.rs
+++ b/crates/router/src/connector/stax.rs
@@ -110,6 +110,7 @@ impl ConnectorCommon for Stax {
.to_owned(),
),
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/stripe.rs b/crates/router/src/connector/stripe.rs
index ccf843ec78d6..475105c9cebe 100644
--- a/crates/router/src/connector/stripe.rs
+++ b/crates/router/src/connector/stripe.rs
@@ -227,6 +227,7 @@ impl
.unwrap_or(message)
}),
attempt_status: None,
+ connector_transaction_id: response.error.payment_intent.map(|pi| pi.id),
})
}
}
@@ -357,6 +358,7 @@ impl
.unwrap_or(message)
}),
attempt_status: None,
+ connector_transaction_id: response.error.payment_intent.map(|pi| pi.id),
})
}
}
@@ -483,6 +485,7 @@ impl
.unwrap_or(message)
}),
attempt_status: None,
+ connector_transaction_id: response.error.payment_intent.map(|pi| pi.id),
})
}
}
@@ -617,6 +620,7 @@ impl
.unwrap_or(message)
}),
attempt_status: None,
+ connector_transaction_id: response.error.payment_intent.map(|pi| pi.id),
})
}
}
@@ -760,6 +764,7 @@ impl
.unwrap_or(message)
}),
attempt_status: None,
+ connector_transaction_id: response.error.payment_intent.map(|pi| pi.id),
})
}
}
@@ -918,6 +923,7 @@ impl
.unwrap_or(message)
}),
attempt_status: None,
+ connector_transaction_id: response.error.payment_intent.map(|pi| pi.id),
})
}
}
@@ -1041,6 +1047,7 @@ impl
.unwrap_or(message)
}),
attempt_status: None,
+ connector_transaction_id: response.error.payment_intent.map(|pi| pi.id),
})
}
}
@@ -1197,6 +1204,7 @@ impl
.unwrap_or(message)
}),
attempt_status: None,
+ connector_transaction_id: response.error.payment_intent.map(|pi| pi.id),
})
}
}
@@ -1318,6 +1326,7 @@ impl services::ConnectorIntegration
.or(Some(error.message.clone())),
status_code: item.http_code,
attempt_status: None,
+ connector_transaction_id: None,
});
let connector_metadata =
@@ -2788,6 +2789,12 @@ pub struct ErrorDetails {
pub message: Option,
pub param: Option,
pub decline_code: Option,
+ pub payment_intent: Option,
+}
+
+#[derive(Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
+pub struct PaymentIntentErrorResponse {
+ pub id: String,
}
#[derive(Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
diff --git a/crates/router/src/connector/trustpay.rs b/crates/router/src/connector/trustpay.rs
index 65ab5a7ba58d..2430aac6c19f 100644
--- a/crates/router/src/connector/trustpay.rs
+++ b/crates/router/src/connector/trustpay.rs
@@ -139,6 +139,7 @@ impl ConnectorCommon for Trustpay {
.unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
reason: reason.or(response_data.description),
attempt_status: None,
+ connector_transaction_id: None,
})
}
Err(error_msg) => {
@@ -298,6 +299,7 @@ impl ConnectorIntegration TryFrom {
- let captured_amount = if self.request.is_psync() {
- payment_data
- .payment_attempt
- .amount_to_capture
- .or(Some(payment_data.payment_attempt.get_total_amount()))
- } else {
- types::Capturable::get_capture_amount(&self.request)
- };
- if Some(payment_data.payment_attempt.get_total_amount()) == captured_amount {
+ let captured_amount =
+ types::Capturable::get_capture_amount(&self.request, payment_data);
+ let total_capturable_amount = payment_data.payment_attempt.get_total_amount();
+ if Some(total_capturable_amount) == captured_amount {
enums::AttemptStatus::Charged
} else if captured_amount.is_some() {
enums::AttemptStatus::PartialCharged
diff --git a/crates/router/src/connector/volt.rs b/crates/router/src/connector/volt.rs
index 43b6b3a3406d..14b5c67804f6 100644
--- a/crates/router/src/connector/volt.rs
+++ b/crates/router/src/connector/volt.rs
@@ -130,6 +130,7 @@ impl ConnectorCommon for Volt {
message: response.exception.message.clone(),
reason: Some(reason),
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/wise.rs b/crates/router/src/connector/wise.rs
index 865dcd5fff35..4fa66f0d8e5d 100644
--- a/crates/router/src/connector/wise.rs
+++ b/crates/router/src/connector/wise.rs
@@ -95,6 +95,7 @@ impl ConnectorCommon for Wise {
message: e.message.clone(),
reason: None,
attempt_status: None,
+ connector_transaction_id: None,
})
} else {
Ok(types::ErrorResponse {
@@ -103,6 +104,7 @@ impl ConnectorCommon for Wise {
message: response.message.unwrap_or_default(),
reason: None,
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
@@ -112,6 +114,7 @@ impl ConnectorCommon for Wise {
message: response.message.unwrap_or_default(),
reason: None,
attempt_status: None,
+ connector_transaction_id: None,
}),
}
}
@@ -293,6 +296,7 @@ impl services::ConnectorIntegration for Gateway {
utils::CardIssuer::Master => Ok(Self::MasterCard),
utils::CardIssuer::Discover => Ok(Self::Discover),
utils::CardIssuer::Visa => Ok(Self::Visa),
- _ => Err(errors::ConnectorError::NotSupported {
- message: issuer.to_string(),
- connector: "worldline",
- }
+ _ => Err(errors::ConnectorError::NotImplemented(
+ utils::get_unimplemented_payment_method_error_message("worldline"),
+ )
.into()),
}
}
diff --git a/crates/router/src/connector/worldpay.rs b/crates/router/src/connector/worldpay.rs
index ef01aa9a6ada..4edee3624ef6 100644
--- a/crates/router/src/connector/worldpay.rs
+++ b/crates/router/src/connector/worldpay.rs
@@ -95,6 +95,7 @@ impl ConnectorCommon for Worldpay {
message: response.message,
reason: response.validation_errors.map(|e| e.to_string()),
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/connector/zen.rs b/crates/router/src/connector/zen.rs
index 102d54bab427..5164407a2eed 100644
--- a/crates/router/src/connector/zen.rs
+++ b/crates/router/src/connector/zen.rs
@@ -127,6 +127,7 @@ impl ConnectorCommon for Zen {
),
reason: None,
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/consts.rs b/crates/router/src/consts.rs
index 410e3c1113b1..c5490ee00e63 100644
--- a/crates/router/src/consts.rs
+++ b/crates/router/src/consts.rs
@@ -58,3 +58,5 @@ pub const LOCKER_REDIS_EXPIRY_SECONDS: u32 = 60 * 15; // 15 minutes
#[cfg(any(feature = "olap", feature = "oltp"))]
pub const JWT_TOKEN_TIME_IN_SECS: u64 = 60 * 60 * 24 * 2; // 2 days
+
+pub const ROLE_ID_ORGANIZATION_ADMIN: &str = "org_admin";
diff --git a/crates/router/src/consts/user.rs b/crates/router/src/consts/user.rs
index 3a71fed01a12..c570aca76038 100644
--- a/crates/router/src/consts/user.rs
+++ b/crates/router/src/consts/user.rs
@@ -1,8 +1,2 @@
-#[cfg(feature = "olap")]
pub const MAX_NAME_LENGTH: usize = 70;
-#[cfg(feature = "olap")]
pub const MAX_COMPANY_NAME_LENGTH: usize = 70;
-
-// USER ROLES
-#[cfg(any(feature = "olap", feature = "oltp"))]
-pub const ROLE_ID_ORGANIZATION_ADMIN: &str = "org_admin";
diff --git a/crates/router/src/core/errors/user.rs b/crates/router/src/core/errors/user.rs
index b4d48365dc84..b86c395b9814 100644
--- a/crates/router/src/core/errors/user.rs
+++ b/crates/router/src/core/errors/user.rs
@@ -13,6 +13,8 @@ pub enum UserErrors {
InvalidCredentials,
#[error("UserExists")]
UserExists,
+ #[error("InvalidOldPassword")]
+ InvalidOldPassword,
#[error("EmailParsingError")]
EmailParsingError,
#[error("NameParsingError")]
@@ -27,6 +29,8 @@ pub enum UserErrors {
InvalidEmailError,
#[error("DuplicateOrganizationId")]
DuplicateOrganizationId,
+ #[error("MerchantIdNotFound")]
+ MerchantIdNotFound,
}
impl common_utils::errors::ErrorSwitch for UserErrors {
@@ -49,6 +53,12 @@ impl common_utils::errors::ErrorSwitch AER::BadRequest(ApiError::new(
+ sub_code,
+ 6,
+ "Old password incorrect. Please enter the correct password",
+ None,
+ )),
Self::EmailParsingError => {
AER::BadRequest(ApiError::new(sub_code, 7, "Invalid Email", None))
}
@@ -73,6 +83,9 @@ impl common_utils::errors::ErrorSwitch {
+ AER::BadRequest(ApiError::new(sub_code, 18, "Invalid Merchant ID", None))
+ }
}
}
}
diff --git a/crates/router/src/core/errors/utils.rs b/crates/router/src/core/errors/utils.rs
index 869a5b6bde95..b62abd0e336e 100644
--- a/crates/router/src/core/errors/utils.rs
+++ b/crates/router/src/core/errors/utils.rs
@@ -136,25 +136,81 @@ pub trait ConnectorErrorExt {
impl ConnectorErrorExt for error_stack::Result {
fn to_refund_failed_response(self) -> error_stack::Result {
- self.map_err(|err| {
- let data = match err.current_context() {
- errors::ConnectorError::ProcessingStepFailed(Some(bytes)) => {
- let response_str = std::str::from_utf8(bytes);
- match response_str {
- Ok(s) => serde_json::from_str(s)
- .map_err(
- |error| logger::error!(%error,"Failed to convert response to JSON"),
- )
- .ok(),
- Err(error) => {
- logger::error!(%error,"Failed to convert response to UTF8 string");
- None
- }
+ self.map_err(|err| match err.current_context() {
+ errors::ConnectorError::ProcessingStepFailed(Some(bytes)) => {
+ let response_str = std::str::from_utf8(bytes);
+ let data = match response_str {
+ Ok(s) => serde_json::from_str(s)
+ .map_err(
+ |error| logger::error!(%error,"Failed to convert response to JSON"),
+ )
+ .ok(),
+ Err(error) => {
+ logger::error!(%error,"Failed to convert response to UTF8 string");
+ None
}
+ };
+ err.change_context(errors::ApiErrorResponse::RefundFailed { data })
+ }
+ errors::ConnectorError::NotImplemented(reason) => {
+ errors::ApiErrorResponse::NotImplemented {
+ message: errors::api_error_response::NotImplementedMessage::Reason(
+ reason.to_string(),
+ ),
}
- _ => None,
- };
- err.change_context(errors::ApiErrorResponse::RefundFailed { data })
+ .into()
+ }
+ errors::ConnectorError::FailedToObtainIntegrationUrl
+ | errors::ConnectorError::RequestEncodingFailed
+ | errors::ConnectorError::RequestEncodingFailedWithReason(_)
+ | errors::ConnectorError::ParsingFailed
+ | errors::ConnectorError::ResponseDeserializationFailed
+ | errors::ConnectorError::UnexpectedResponseError(_)
+ | errors::ConnectorError::RoutingRulesParsingError
+ | errors::ConnectorError::FailedToObtainPreferredConnector
+ | errors::ConnectorError::ProcessingStepFailed(_)
+ | errors::ConnectorError::InvalidConnectorName
+ | errors::ConnectorError::InvalidWallet
+ | errors::ConnectorError::ResponseHandlingFailed
+ | errors::ConnectorError::MissingRequiredField { .. }
+ | errors::ConnectorError::MissingRequiredFields { .. }
+ | errors::ConnectorError::FailedToObtainAuthType
+ | errors::ConnectorError::FailedToObtainCertificate
+ | errors::ConnectorError::NoConnectorMetaData
+ | errors::ConnectorError::FailedToObtainCertificateKey
+ | errors::ConnectorError::NotSupported { .. }
+ | errors::ConnectorError::FlowNotSupported { .. }
+ | errors::ConnectorError::CaptureMethodNotSupported
+ | errors::ConnectorError::MissingConnectorMandateID
+ | errors::ConnectorError::MissingConnectorTransactionID
+ | errors::ConnectorError::MissingConnectorRefundID
+ | errors::ConnectorError::MissingApplePayTokenData
+ | errors::ConnectorError::WebhooksNotImplemented
+ | errors::ConnectorError::WebhookBodyDecodingFailed
+ | errors::ConnectorError::WebhookSignatureNotFound
+ | errors::ConnectorError::WebhookSourceVerificationFailed
+ | errors::ConnectorError::WebhookVerificationSecretNotFound
+ | errors::ConnectorError::WebhookVerificationSecretInvalid
+ | errors::ConnectorError::WebhookReferenceIdNotFound
+ | errors::ConnectorError::WebhookEventTypeNotFound
+ | errors::ConnectorError::WebhookResourceObjectNotFound
+ | errors::ConnectorError::WebhookResponseEncodingFailed
+ | errors::ConnectorError::InvalidDateFormat
+ | errors::ConnectorError::DateFormattingFailed
+ | errors::ConnectorError::InvalidDataFormat { .. }
+ | errors::ConnectorError::MismatchedPaymentData
+ | errors::ConnectorError::InvalidWalletToken
+ | errors::ConnectorError::MissingConnectorRelatedTransactionID { .. }
+ | errors::ConnectorError::FileValidationFailed { .. }
+ | errors::ConnectorError::MissingConnectorRedirectionPayload { .. }
+ | errors::ConnectorError::FailedAtConnector { .. }
+ | errors::ConnectorError::MissingPaymentMethodType
+ | errors::ConnectorError::InSufficientBalanceInPaymentMethod
+ | errors::ConnectorError::RequestTimeoutReceived
+ | errors::ConnectorError::CurrencyNotSupported { .. }
+ | errors::ConnectorError::InvalidConnectorConfig { .. } => {
+ err.change_context(errors::ApiErrorResponse::RefundFailed { data: None })
+ }
})
}
diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs
index 85a0ca5f2441..044e270a7ea9 100644
--- a/crates/router/src/core/payment_methods/cards.rs
+++ b/crates/router/src/core/payment_methods/cards.rs
@@ -2459,8 +2459,7 @@ async fn get_bank_account_connector_details(
}))
}
},
- None => Err(errors::ApiErrorResponse::InternalServerError.into())
- .attach_printable("Unable to fetch payment method data"),
+ None => Ok(None),
}
}
diff --git a/crates/router/src/core/payments/access_token.rs b/crates/router/src/core/payments/access_token.rs
index af10e91b5a08..b95c294466d3 100644
--- a/crates/router/src/core/payments/access_token.rs
+++ b/crates/router/src/core/payments/access_token.rs
@@ -174,6 +174,7 @@ pub async fn refresh_connector_auth(
reason: Some(consts::REQUEST_TIMEOUT_ERROR_MESSAGE.to_string()),
status_code: 504,
attempt_status: None,
+ connector_transaction_id: None,
};
Ok(Err(error_response))
diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs
index 4d8daa1fe69d..f57c0640f1a8 100644
--- a/crates/router/src/core/payments/helpers.rs
+++ b/crates/router/src/core/payments/helpers.rs
@@ -601,19 +601,19 @@ pub fn validate_request_amount_and_amount_to_capture(
}
}
-/// if confirm = true and capture method = automatic, amount_to_capture(if provided) must be equal to amount
+/// if capture method = automatic, amount_to_capture(if provided) must be equal to amount
#[instrument(skip_all)]
pub fn validate_amount_to_capture_in_create_call_request(
request: &api_models::payments::PaymentsRequest,
) -> CustomResult<(), errors::ApiErrorResponse> {
- if request.capture_method.unwrap_or_default() == api_enums::CaptureMethod::Automatic
- && request.confirm.unwrap_or(false)
- {
- if let Some((amount_to_capture, amount)) = request.amount_to_capture.zip(request.amount) {
- let amount_int: i64 = amount.into();
- utils::when(amount_to_capture != amount_int, || {
+ if request.capture_method.unwrap_or_default() == api_enums::CaptureMethod::Automatic {
+ let total_capturable_amount = request.get_total_capturable_amount();
+ if let Some((amount_to_capture, total_capturable_amount)) =
+ request.amount_to_capture.zip(total_capturable_amount)
+ {
+ utils::when(amount_to_capture != total_capturable_amount, || {
Err(report!(errors::ApiErrorResponse::PreconditionFailed {
- message: "amount_to_capture must be equal to amount when confirm = true and capture_method = automatic".into()
+ message: "amount_to_capture must be equal to total_capturable_amount when capture_method = automatic".into()
}))
})
} else {
@@ -1693,7 +1693,8 @@ pub(crate) fn validate_status_with_capture_method(
field_name: "payment.status".to_string(),
current_flow: "captured".to_string(),
current_value: status.to_string(),
- states: "requires_capture, partially_captured, processing".to_string()
+ states: "requires_capture, partially_captured_and_capturable, processing"
+ .to_string()
}))
},
)
@@ -3685,3 +3686,22 @@ pub async fn get_gsm_record(
})
.ok()
}
+
+pub fn validate_order_details_amount(
+ order_details: Vec,
+ amount: i64,
+) -> Result<(), errors::ApiErrorResponse> {
+ let total_order_details_amount: i64 = order_details
+ .iter()
+ .map(|order| order.amount * i64::from(order.quantity))
+ .sum();
+
+ if total_order_details_amount != amount {
+ Err(errors::ApiErrorResponse::InvalidRequestData {
+ message: "Total sum of order details doesn't match amount in payment request"
+ .to_string(),
+ })
+ } else {
+ Ok(())
+ }
+}
diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs
index 125787e1a30f..28b6dbec96ab 100644
--- a/crates/router/src/core/payments/operations/payment_confirm.rs
+++ b/crates/router/src/core/payments/operations/payment_confirm.rs
@@ -102,6 +102,13 @@ impl
utils::flatten_join_error(mandate_details_fut)
)?;
+ if let Some(order_details) = &request.order_details {
+ helpers::validate_order_details_amount(
+ order_details.to_owned(),
+ payment_intent.amount,
+ )?;
+ }
+
helpers::validate_customer_access(&payment_intent, auth_flow, request)?;
helpers::validate_payment_status_against_not_allowed_statuses(
@@ -185,7 +192,7 @@ impl
let shipping_address_fut = tokio::spawn(
async move {
- helpers::create_or_find_address_for_payment_by_request(
+ helpers::create_or_update_address_for_payment_by_request(
store.as_ref(),
m_request_shipping.as_ref(),
m_payment_intent_shipping_address_id.as_deref(),
@@ -213,7 +220,7 @@ impl
let billing_address_fut = tokio::spawn(
async move {
- helpers::create_or_find_address_for_payment_by_request(
+ helpers::create_or_update_address_for_payment_by_request(
store.as_ref(),
m_request_billing.as_ref(),
m_payment_intent_billing_address_id.as_deref(),
@@ -693,6 +700,15 @@ impl
let m_error_message = error_message.clone();
let m_db = state.clone().store;
+ let surcharge_amount = payment_data
+ .surcharge_details
+ .as_ref()
+ .map(|surcharge_details| surcharge_details.surcharge_amount);
+ let tax_amount = payment_data
+ .surcharge_details
+ .as_ref()
+ .map(|surcharge_details| surcharge_details.tax_on_surcharge_amount);
+
let payment_attempt_fut = tokio::spawn(
async move {
m_db.update_payment_attempt_with_attempt_id(
@@ -716,6 +732,8 @@ impl
amount_capturable: Some(authorized_amount),
updated_by: storage_scheme.to_string(),
merchant_connector_id,
+ surcharge_amount,
+ tax_amount,
},
storage_scheme,
)
diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs
index ccf9fc3fad1c..c12f28e23390 100644
--- a/crates/router/src/core/payments/operations/payment_create.rs
+++ b/crates/router/src/core/payments/operations/payment_create.rs
@@ -186,6 +186,13 @@ impl
payment_id: payment_id.clone(),
})?;
+ if let Some(order_details) = &request.order_details {
+ helpers::validate_order_details_amount(
+ order_details.to_owned(),
+ payment_intent.amount,
+ )?;
+ }
+
payment_attempt = db
.insert_payment_attempt(payment_attempt_new, storage_scheme)
.await
diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs
index 3734abfc6ab5..2de5df38dba4 100644
--- a/crates/router/src/core/payments/operations/payment_response.rs
+++ b/crates/router/src/core/payments/operations/payment_response.rs
@@ -372,11 +372,10 @@ async fn payment_response_update_tracker(
} else {
None
},
- surcharge_amount: router_data.request.get_surcharge_amount(),
- tax_amount: router_data.request.get_tax_on_surcharge_amount(),
updated_by: storage_scheme.to_string(),
unified_code: option_gsm.clone().map(|gsm| gsm.unified_code),
unified_message: option_gsm.map(|gsm| gsm.unified_message),
+ connector_transaction_id: err.connector_transaction_id,
}),
)
}
@@ -496,8 +495,6 @@ async fn payment_response_update_tracker(
} else {
None
},
- surcharge_amount: router_data.request.get_surcharge_amount(),
- tax_amount: router_data.request.get_tax_on_surcharge_amount(),
updated_by: storage_scheme.to_string(),
authentication_data,
encoded_data,
@@ -751,7 +748,7 @@ fn get_total_amount_captured(
}
None => {
//Non multiple capture
- let amount = request.get_capture_amount();
+ let amount = request.get_capture_amount(payment_data);
amount_captured.or_else(|| {
if router_data_status == enums::AttemptStatus::Charged {
amount
diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs
index 75d3b6b82b4c..1176eeb1dd3f 100644
--- a/crates/router/src/core/payments/operations/payment_update.rs
+++ b/crates/router/src/core/payments/operations/payment_update.rs
@@ -60,6 +60,13 @@ impl
.await
.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
+ if let Some(order_details) = &request.order_details {
+ helpers::validate_order_details_amount(
+ order_details.to_owned(),
+ payment_intent.amount,
+ )?;
+ }
+
payment_intent.setup_future_usage = request
.setup_future_usage
.or(payment_intent.setup_future_usage);
diff --git a/crates/router/src/core/payments/retry.rs b/crates/router/src/core/payments/retry.rs
index f16f7629578b..0fd45c5af3b5 100644
--- a/crates/router/src/core/payments/retry.rs
+++ b/crates/router/src/core/payments/retry.rs
@@ -382,8 +382,6 @@ where
} else {
None
},
- surcharge_amount: None,
- tax_amount: None,
updated_by: storage_scheme.to_string(),
authentication_data,
encoded_data,
@@ -410,11 +408,10 @@ where
status: storage_enums::AttemptStatus::Failure,
error_reason: Some(error_response.reason.clone()),
amount_capturable: Some(0),
- surcharge_amount: None,
- tax_amount: None,
updated_by: storage_scheme.to_string(),
unified_code: option_gsm.clone().map(|gsm| gsm.unified_code),
unified_message: option_gsm.map(|gsm| gsm.unified_message),
+ connector_transaction_id: error_response.connector_transaction_id.clone(),
},
storage_scheme,
)
diff --git a/crates/router/src/core/refunds.rs b/crates/router/src/core/refunds.rs
index daa39bc60989..5ea3520c4e8f 100644
--- a/crates/router/src/core/refunds.rs
+++ b/crates/router/src/core/refunds.rs
@@ -58,13 +58,12 @@ pub async fn refund_create_core(
)?;
// Amount is not passed in request refer from payment intent.
- amount = req.amount.unwrap_or(
- payment_intent
- .amount_captured
- .ok_or(errors::ApiErrorResponse::InternalServerError)
- .into_report()
- .attach_printable("amount captured is none in a successful payment")?,
- );
+ amount = req
+ .amount
+ .or(payment_intent.amount_captured)
+ .ok_or(errors::ApiErrorResponse::InternalServerError)
+ .into_report()
+ .attach_printable("amount captured is none in a successful payment")?;
//[#299]: Can we change the flow based on some workflow idea
utils::when(amount <= 0, || {
@@ -190,15 +189,48 @@ pub async fn trigger_refund_to_gateway(
types::RefundsData,
types::RefundsResponseData,
> = connector.connector.get_connector_integration();
- services::execute_connector_processing_step(
+ let router_data_res = services::execute_connector_processing_step(
state,
connector_integration,
&router_data,
payments::CallConnectorAction::Trigger,
None,
)
- .await
- .to_refund_failed_response()?
+ .await;
+ let option_refund_error_update =
+ router_data_res
+ .as_ref()
+ .err()
+ .and_then(|error| match error.current_context() {
+ errors::ConnectorError::NotImplemented(message) => {
+ Some(storage::RefundUpdate::ErrorUpdate {
+ refund_status: Some(enums::RefundStatus::Failure),
+ refund_error_message: Some(message.to_string()),
+ refund_error_code: Some("NOT_IMPLEMENTED".to_string()),
+ updated_by: storage_scheme.to_string(),
+ })
+ }
+ _ => None,
+ });
+ // Update the refund status as failure if connector_error is NotImplemented
+ if let Some(refund_error_update) = option_refund_error_update {
+ state
+ .store
+ .update_refund(
+ refund.to_owned(),
+ refund_error_update,
+ merchant_account.storage_scheme,
+ )
+ .await
+ .to_not_found_response(errors::ApiErrorResponse::InternalServerError)
+ .attach_printable_lazy(|| {
+ format!(
+ "Failed while updating refund: refund_id: {}",
+ refund.refund_id
+ )
+ })?;
+ }
+ router_data_res.to_refund_failed_response()?
} else {
router_data
};
@@ -889,7 +921,9 @@ pub async fn start_refund_workflow(
) -> Result<(), errors::ProcessTrackerError> {
match refund_tracker.name.as_deref() {
Some("EXECUTE_REFUND") => trigger_refund_execute_workflow(state, refund_tracker).await,
- Some("SYNC_REFUND") => Box::pin(sync_refund_with_gateway_workflow(state, refund_tracker)).await,
+ Some("SYNC_REFUND") => {
+ Box::pin(sync_refund_with_gateway_workflow(state, refund_tracker)).await
+ }
_ => Err(errors::ProcessTrackerError::JobNotFound),
}
}
diff --git a/crates/router/src/core/user.rs b/crates/router/src/core/user.rs
index 710dc9281bfa..94cd482a2291 100644
--- a/crates/router/src/core/user.rs
+++ b/crates/router/src/core/user.rs
@@ -1,12 +1,16 @@
use api_models::user as api;
use diesel_models::enums::UserStatus;
-use error_stack::IntoReport;
+use error_stack::{IntoReport, ResultExt};
use masking::{ExposeInterface, Secret};
use router_env::env;
use super::errors::{UserErrors, UserResponse};
use crate::{
- consts::user as consts, routes::AppState, services::ApplicationResponse, types::domain,
+ consts,
+ db::user::UserInterface,
+ routes::AppState,
+ services::{authentication::UserFromToken, ApplicationResponse},
+ types::domain,
};
pub async fn connect_account(
@@ -79,3 +83,35 @@ pub async fn connect_account(
Err(UserErrors::InternalServerError.into())
}
}
+
+pub async fn change_password(
+ state: AppState,
+ request: api::ChangePasswordRequest,
+ user_from_token: UserFromToken,
+) -> UserResponse<()> {
+ let user: domain::UserFromStorage =
+ UserInterface::find_user_by_id(&*state.store, &user_from_token.user_id)
+ .await
+ .change_context(UserErrors::InternalServerError)?
+ .into();
+
+ user.compare_password(request.old_password)
+ .change_context(UserErrors::InvalidOldPassword)?;
+
+ let new_password_hash =
+ crate::utils::user::password::generate_password_hash(request.new_password)?;
+
+ let _ = UserInterface::update_user_by_user_id(
+ &*state.store,
+ user.get_user_id(),
+ diesel_models::user::UserUpdate::AccountUpdate {
+ name: None,
+ password: Some(new_password_hash),
+ is_verified: None,
+ },
+ )
+ .await
+ .change_context(UserErrors::InternalServerError)?;
+
+ Ok(ApplicationResponse::StatusOk)
+}
diff --git a/crates/router/src/routes/admin.rs b/crates/router/src/routes/admin.rs
index eef8cacc5f92..0586faabbf76 100644
--- a/crates/router/src/routes/admin.rs
+++ b/crates/router/src/routes/admin.rs
@@ -4,7 +4,7 @@ use router_env::{instrument, tracing, Flow};
use super::app::AppState;
use crate::{
core::{admin::*, api_locking},
- services::{api, authentication as auth},
+ services::{api, authentication as auth, authorization::permissions::Permission},
types::api::admin,
};
@@ -77,7 +77,10 @@ pub async fn retrieve_merchant_account(
|state, _, req| get_merchant_account(state, req),
auth::auth_type(
&auth::AdminApiAuth,
- &auth::JWTAuthMerchantFromRoute { merchant_id },
+ &auth::JWTAuthMerchantFromRoute {
+ merchant_id,
+ required_permission: Permission::MerchantAccountRead,
+ },
req.headers(),
),
api_locking::LockAction::NotApplicable,
@@ -141,6 +144,7 @@ pub async fn update_merchant_account(
&auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute {
merchant_id: merchant_id.clone(),
+ required_permission: Permission::MerchantAccountWrite,
},
req.headers(),
),
@@ -220,6 +224,7 @@ pub async fn payment_connector_create(
&auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute {
merchant_id: merchant_id.clone(),
+ required_permission: Permission::MerchantConnectorAccountWrite,
},
req.headers(),
),
@@ -270,7 +275,10 @@ pub async fn payment_connector_retrieve(
},
auth::auth_type(
&auth::AdminApiAuth,
- &auth::JWTAuthMerchantFromRoute { merchant_id },
+ &auth::JWTAuthMerchantFromRoute {
+ merchant_id,
+ required_permission: Permission::MerchantConnectorAccountRead,
+ },
req.headers(),
),
api_locking::LockAction::NotApplicable,
@@ -312,7 +320,10 @@ pub async fn payment_connector_list(
|state, _, merchant_id| list_payment_connectors(state, merchant_id),
auth::auth_type(
&auth::AdminApiAuth,
- &auth::JWTAuthMerchantFromRoute { merchant_id },
+ &auth::JWTAuthMerchantFromRoute {
+ merchant_id,
+ required_permission: Permission::MerchantConnectorAccountRead,
+ },
req.headers(),
),
api_locking::LockAction::NotApplicable,
@@ -359,6 +370,7 @@ pub async fn payment_connector_update(
&auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute {
merchant_id: merchant_id.clone(),
+ required_permission: Permission::MerchantConnectorAccountWrite,
},
req.headers(),
),
@@ -407,7 +419,10 @@ pub async fn payment_connector_delete(
|state, _, req| delete_payment_connector(state, req.merchant_id, req.merchant_connector_id),
auth::auth_type(
&auth::AdminApiAuth,
- &auth::JWTAuthMerchantFromRoute { merchant_id },
+ &auth::JWTAuthMerchantFromRoute {
+ merchant_id,
+ required_permission: Permission::MerchantConnectorAccountWrite,
+ },
req.headers(),
),
api_locking::LockAction::NotApplicable,
@@ -460,6 +475,7 @@ pub async fn business_profile_create(
&auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute {
merchant_id: merchant_id.clone(),
+ required_permission: Permission::MerchantAccountWrite,
},
req.headers(),
),
@@ -484,7 +500,10 @@ pub async fn business_profile_retrieve(
|state, _, profile_id| retrieve_business_profile(state, profile_id),
auth::auth_type(
&auth::AdminApiAuth,
- &auth::JWTAuthMerchantFromRoute { merchant_id },
+ &auth::JWTAuthMerchantFromRoute {
+ merchant_id,
+ required_permission: Permission::MerchantAccountRead,
+ },
req.headers(),
),
api_locking::LockAction::NotApplicable,
@@ -511,6 +530,7 @@ pub async fn business_profile_update(
&auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute {
merchant_id: merchant_id.clone(),
+ required_permission: Permission::MerchantAccountWrite,
},
req.headers(),
),
@@ -555,7 +575,10 @@ pub async fn business_profiles_list(
|state, _, merchant_id| list_business_profile(state, merchant_id),
auth::auth_type(
&auth::AdminApiAuth,
- &auth::JWTAuthMerchantFromRoute { merchant_id },
+ &auth::JWTAuthMerchantFromRoute {
+ merchant_id,
+ required_permission: Permission::MerchantAccountRead,
+ },
req.headers(),
),
api_locking::LockAction::NotApplicable,
diff --git a/crates/router/src/routes/api_keys.rs b/crates/router/src/routes/api_keys.rs
index 7299aa696390..5b4c047b1466 100644
--- a/crates/router/src/routes/api_keys.rs
+++ b/crates/router/src/routes/api_keys.rs
@@ -4,7 +4,7 @@ use router_env::{instrument, tracing, Flow};
use super::app::AppState;
use crate::{
core::{api_keys, api_locking},
- services::{api, authentication as auth},
+ services::{api, authentication as auth, authorization::permissions::Permission},
types::api as api_types,
};
@@ -57,6 +57,7 @@ pub async fn api_key_create(
&auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute {
merchant_id: merchant_id.clone(),
+ required_permission: Permission::ApiKeyWrite,
},
req.headers(),
),
@@ -101,6 +102,7 @@ pub async fn api_key_retrieve(
&auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute {
merchant_id: merchant_id.clone(),
+ required_permission: Permission::ApiKeyRead,
},
req.headers(),
),
@@ -189,6 +191,7 @@ pub async fn api_key_revoke(
&auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute {
merchant_id: merchant_id.clone(),
+ required_permission: Permission::ApiKeyWrite,
},
req.headers(),
),
@@ -237,7 +240,10 @@ pub async fn api_key_list(
},
auth::auth_type(
&auth::AdminApiAuth,
- &auth::JWTAuthMerchantFromRoute { merchant_id },
+ &auth::JWTAuthMerchantFromRoute {
+ merchant_id,
+ required_permission: Permission::ApiKeyRead,
+ },
req.headers(),
),
api_locking::LockAction::NotApplicable,
diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs
index c5ab28ebcf6f..7f620241d303 100644
--- a/crates/router/src/routes/app.rs
+++ b/crates/router/src/routes/app.rs
@@ -153,10 +153,7 @@ impl AppState {
};
#[cfg(feature = "olap")]
- let pool = crate::analytics::AnalyticsProvider::from_conf(
- &conf.analytics,
- )
- .await;
+ let pool = crate::analytics::AnalyticsProvider::from_conf(&conf.analytics).await;
#[cfg(feature = "kms")]
#[allow(clippy::expect_used)]
@@ -775,6 +772,7 @@ impl User {
.service(web::resource("/signup").route(web::post().to(user_connect_account)))
.service(web::resource("/v2/signin").route(web::post().to(user_connect_account)))
.service(web::resource("/v2/signup").route(web::post().to(user_connect_account)))
+ .service(web::resource("/change_password").route(web::post().to(change_password)))
}
}
diff --git a/crates/router/src/routes/disputes.rs b/crates/router/src/routes/disputes.rs
index aaeb118645db..7bcd8ad35124 100644
--- a/crates/router/src/routes/disputes.rs
+++ b/crates/router/src/routes/disputes.rs
@@ -3,7 +3,7 @@ use actix_web::{web, HttpRequest, HttpResponse};
use api_models::disputes as dispute_models;
use router_env::{instrument, tracing, Flow};
-use crate::core::api_locking;
+use crate::{core::api_locking, services::authorization::permissions::Permission};
pub mod utils;
use super::app::AppState;
@@ -44,7 +44,11 @@ pub async fn retrieve_dispute(
&req,
dispute_id,
|state, auth, req| disputes::retrieve_dispute(state, auth.merchant_account, req),
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::DisputeRead),
+ req.headers(),
+ ),
api_locking::LockAction::NotApplicable,
)
.await
@@ -87,7 +91,11 @@ pub async fn retrieve_disputes_list(
&req,
payload,
|state, auth, req| disputes::retrieve_disputes_list(state, auth.merchant_account, req),
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::DisputeRead),
+ req.headers(),
+ ),
api_locking::LockAction::NotApplicable,
)
.await
@@ -125,7 +133,11 @@ pub async fn accept_dispute(
|state, auth, req| {
disputes::accept_dispute(state, auth.merchant_account, auth.key_store, req)
},
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::DisputeWrite),
+ req.headers(),
+ ),
api_locking::LockAction::NotApplicable,
))
.await
@@ -158,7 +170,11 @@ pub async fn submit_dispute_evidence(
|state, auth, req| {
disputes::submit_evidence(state, auth.merchant_account, auth.key_store, req)
},
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::DisputeWrite),
+ req.headers(),
+ ),
api_locking::LockAction::NotApplicable,
))
.await
@@ -199,7 +215,11 @@ pub async fn attach_dispute_evidence(
|state, auth, req| {
disputes::attach_evidence(state, auth.merchant_account, auth.key_store, req)
},
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::DisputeWrite),
+ req.headers(),
+ ),
api_locking::LockAction::NotApplicable,
))
.await
@@ -235,7 +255,11 @@ pub async fn retrieve_dispute_evidence(
&req,
dispute_id,
|state, auth, req| disputes::retrieve_dispute_evidence(state, auth.merchant_account, req),
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::DisputeRead),
+ req.headers(),
+ ),
api_locking::LockAction::NotApplicable,
))
.await
diff --git a/crates/router/src/routes/files.rs b/crates/router/src/routes/files.rs
index bde221ebc161..95f4007cb91b 100644
--- a/crates/router/src/routes/files.rs
+++ b/crates/router/src/routes/files.rs
@@ -2,7 +2,7 @@ use actix_multipart::Multipart;
use actix_web::{web, HttpRequest, HttpResponse};
use router_env::{instrument, tracing, Flow};
-use crate::core::api_locking;
+use crate::{core::api_locking, services::authorization::permissions::Permission};
pub mod transformers;
use super::app::AppState;
@@ -45,7 +45,11 @@ pub async fn files_create(
&req,
create_file_request,
|state, auth, req| files_create_core(state, auth.merchant_account, auth.key_store, req),
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::FileWrite),
+ req.headers(),
+ ),
api_locking::LockAction::NotApplicable,
))
.await
@@ -83,7 +87,11 @@ pub async fn files_delete(
&req,
file_id,
|state, auth, req| files_delete_core(state, auth.merchant_account, req),
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::FileWrite),
+ req.headers(),
+ ),
api_locking::LockAction::NotApplicable,
))
.await
@@ -121,7 +129,11 @@ pub async fn files_retrieve(
&req,
file_id,
|state, auth, req| files_retrieve_core(state, auth.merchant_account, auth.key_store, req),
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::FileRead),
+ req.headers(),
+ ),
api_locking::LockAction::NotApplicable,
))
.await
diff --git a/crates/router/src/routes/lock_utils.rs b/crates/router/src/routes/lock_utils.rs
index a9cf7b44a73d..219948bdd4d2 100644
--- a/crates/router/src/routes/lock_utils.rs
+++ b/crates/router/src/routes/lock_utils.rs
@@ -144,7 +144,7 @@ impl From for ApiIdentifier {
| Flow::GsmRuleUpdate
| Flow::GsmRuleDelete => Self::Gsm,
- Flow::UserConnectAccount => Self::User,
+ Flow::UserConnectAccount | Flow::ChangePassword => Self::User,
}
}
}
diff --git a/crates/router/src/routes/mandates.rs b/crates/router/src/routes/mandates.rs
index 0213d48ddca7..1e4461362975 100644
--- a/crates/router/src/routes/mandates.rs
+++ b/crates/router/src/routes/mandates.rs
@@ -4,7 +4,7 @@ use router_env::{instrument, tracing, Flow};
use super::app::AppState;
use crate::{
core::{api_locking, mandate},
- services::{api, authentication as auth},
+ services::{api, authentication as auth, authorization::permissions::Permission},
types::api::mandates,
};
@@ -122,7 +122,11 @@ pub async fn retrieve_mandates_list(
&req,
payload,
|state, auth, req| mandate::retrieve_mandates_list(state, auth.merchant_account, req),
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::MandateRead),
+ req.headers(),
+ ),
api_locking::LockAction::NotApplicable,
)
.await
diff --git a/crates/router/src/routes/payment_link.rs b/crates/router/src/routes/payment_link.rs
index 4c26ea71f7d5..d45d67568b89 100644
--- a/crates/router/src/routes/payment_link.rs
+++ b/crates/router/src/routes/payment_link.rs
@@ -118,7 +118,7 @@ pub async fn payments_link_list(
&req,
payload,
|state, auth, payload| list_payment_link(state, auth.merchant_account, payload),
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ &auth::ApiKeyAuth,
api_locking::LockAction::NotApplicable,
)
.await
diff --git a/crates/router/src/routes/payments.rs b/crates/router/src/routes/payments.rs
index 81e53ade5e96..979b15a3d7f2 100644
--- a/crates/router/src/routes/payments.rs
+++ b/crates/router/src/routes/payments.rs
@@ -1,4 +1,7 @@
-use crate::core::api_locking::{self, GetLockingInput};
+use crate::{
+ core::api_locking::{self, GetLockingInput},
+ services::authorization::permissions::Permission,
+};
pub mod helpers;
use actix_web::{web, Responder};
@@ -128,7 +131,11 @@ pub async fn payments_create(
},
match env::which() {
env::Env::Production => &auth::ApiKeyAuth,
- _ => auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ _ => auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::PaymentWrite),
+ req.headers(),
+ ),
},
locking_action,
))
@@ -262,7 +269,7 @@ pub async fn payments_retrieve(
},
auth::auth_type(
&*auth_type,
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::PaymentRead),
req.headers(),
),
locking_action,
@@ -843,7 +850,11 @@ pub async fn payments_list(
&req,
payload,
|state, auth, req| payments::list_payments(state, auth.merchant_account, req),
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::PaymentRead),
+ req.headers(),
+ ),
api_locking::LockAction::NotApplicable,
)
.await
@@ -863,7 +874,11 @@ pub async fn payments_list_by_filter(
&req,
payload,
|state, auth, req| payments::apply_filters_on_payments(state, auth.merchant_account, req),
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::PaymentRead),
+ req.headers(),
+ ),
api_locking::LockAction::NotApplicable,
)
.await
@@ -883,7 +898,11 @@ pub async fn get_filters_for_payments(
&req,
payload,
|state, auth, req| payments::get_filters_for_payments(state, auth.merchant_account, req),
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::PaymentRead),
+ req.headers(),
+ ),
api_locking::LockAction::NotApplicable,
)
.await
diff --git a/crates/router/src/routes/refunds.rs b/crates/router/src/routes/refunds.rs
index d370af6b8d7a..47e9f2bf42a8 100644
--- a/crates/router/src/routes/refunds.rs
+++ b/crates/router/src/routes/refunds.rs
@@ -4,7 +4,7 @@ use router_env::{instrument, tracing, Flow};
use super::app::AppState;
use crate::{
core::{api_locking, refunds::*},
- services::{api, authentication as auth},
+ services::{api, authentication as auth, authorization::permissions::Permission},
types::api::refunds,
};
@@ -37,7 +37,11 @@ pub async fn refunds_create(
&req,
json_payload.into_inner(),
|state, auth, req| refund_create_core(state, auth.merchant_account, auth.key_store, req),
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::RefundWrite),
+ req.headers(),
+ ),
api_locking::LockAction::NotApplicable,
))
.await
@@ -88,7 +92,11 @@ pub async fn refunds_retrieve(
refund_retrieve_core,
)
},
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::RefundRead),
+ req.headers(),
+ ),
api_locking::LockAction::NotApplicable,
))
.await
@@ -202,7 +210,11 @@ pub async fn refunds_list(
&req,
payload.into_inner(),
|state, auth, req| refund_list(state, auth.merchant_account, req),
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::RefundRead),
+ req.headers(),
+ ),
api_locking::LockAction::NotApplicable,
)
.await
@@ -235,7 +247,11 @@ pub async fn refunds_filter_list(
&req,
payload.into_inner(),
|state, auth, req| refund_filter_list(state, auth.merchant_account, req),
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::RefundRead),
+ req.headers(),
+ ),
api_locking::LockAction::NotApplicable,
)
.await
diff --git a/crates/router/src/routes/routing.rs b/crates/router/src/routes/routing.rs
index 1d2549bb047a..e7e31cb36aeb 100644
--- a/crates/router/src/routes/routing.rs
+++ b/crates/router/src/routes/routing.rs
@@ -14,7 +14,7 @@ use router_env::{
use crate::{
core::{api_locking, conditional_config, routing, surcharge_decision_config},
routes::AppState,
- services::{api as oss_api, authentication as auth},
+ services::{api as oss_api, authentication as auth, authorization::permissions::Permission},
};
#[cfg(feature = "olap")]
@@ -34,9 +34,13 @@ pub async fn routing_create_config(
routing::create_routing_config(state, auth.merchant_account, auth.key_store, payload)
},
#[cfg(not(feature = "release"))]
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::RoutingWrite),
+ req.headers(),
+ ),
#[cfg(feature = "release")]
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::RoutingWrite),
api_locking::LockAction::NotApplicable,
))
.await
@@ -65,9 +69,13 @@ pub async fn routing_link_config(
)
},
#[cfg(not(feature = "release"))]
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::RoutingWrite),
+ req.headers(),
+ ),
#[cfg(feature = "release")]
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::RoutingWrite),
api_locking::LockAction::NotApplicable,
))
.await
@@ -91,9 +99,13 @@ pub async fn routing_retrieve_config(
routing::retrieve_routing_config(state, auth.merchant_account, algorithm_id)
},
#[cfg(not(feature = "release"))]
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::RoutingRead),
+ req.headers(),
+ ),
#[cfg(feature = "release")]
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::RoutingRead),
api_locking::LockAction::NotApplicable,
))
.await
@@ -122,9 +134,13 @@ pub async fn routing_retrieve_dictionary(
)
},
#[cfg(not(feature = "release"))]
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::RoutingRead),
+ req.headers(),
+ ),
#[cfg(feature = "release")]
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::RoutingRead),
api_locking::LockAction::NotApplicable,
))
.await
@@ -142,9 +158,13 @@ pub async fn routing_retrieve_dictionary(
routing::retrieve_merchant_routing_dictionary(state, auth.merchant_account)
},
#[cfg(not(feature = "release"))]
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::RoutingRead),
+ req.headers(),
+ ),
#[cfg(feature = "release")]
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::RoutingRead),
api_locking::LockAction::NotApplicable,
))
.await
@@ -172,9 +192,13 @@ pub async fn routing_unlink_config(
routing::unlink_routing_config(state, auth.merchant_account, payload_req)
},
#[cfg(not(feature = "release"))]
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::RoutingWrite),
+ req.headers(),
+ ),
#[cfg(feature = "release")]
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::RoutingWrite),
api_locking::LockAction::NotApplicable,
))
.await
@@ -192,9 +216,13 @@ pub async fn routing_unlink_config(
routing::unlink_routing_config(state, auth.merchant_account, auth.key_store)
},
#[cfg(not(feature = "release"))]
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::RoutingWrite),
+ req.headers(),
+ ),
#[cfg(feature = "release")]
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::RoutingWrite),
api_locking::LockAction::NotApplicable,
))
.await
@@ -217,9 +245,13 @@ pub async fn routing_update_default_config(
routing::update_default_routing_config(state, auth.merchant_account, updated_config)
},
#[cfg(not(feature = "release"))]
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::RoutingWrite),
+ req.headers(),
+ ),
#[cfg(feature = "release")]
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::RoutingWrite),
api_locking::LockAction::NotApplicable,
)
.await
@@ -240,9 +272,13 @@ pub async fn routing_retrieve_default_config(
routing::retrieve_default_routing_config(state, auth.merchant_account)
},
#[cfg(not(feature = "release"))]
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::RoutingRead),
+ req.headers(),
+ ),
#[cfg(feature = "release")]
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::RoutingRead),
api_locking::LockAction::NotApplicable,
)
.await
@@ -270,9 +306,13 @@ pub async fn upsert_surcharge_decision_manager_config(
)
},
#[cfg(not(feature = "release"))]
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::SurchargeDecisionManagerWrite),
+ req.headers(),
+ ),
#[cfg(feature = "release")]
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::SurchargeDecisionManagerWrite),
api_locking::LockAction::NotApplicable,
))
.await
@@ -297,9 +337,13 @@ pub async fn delete_surcharge_decision_manager_config(
)
},
#[cfg(not(feature = "release"))]
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::SurchargeDecisionManagerWrite),
+ req.headers(),
+ ),
#[cfg(feature = "release")]
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::SurchargeDecisionManagerWrite),
api_locking::LockAction::NotApplicable,
))
.await
@@ -324,9 +368,13 @@ pub async fn retrieve_surcharge_decision_manager_config(
)
},
#[cfg(not(feature = "release"))]
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::SurchargeDecisionManagerRead),
+ req.headers(),
+ ),
#[cfg(feature = "release")]
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::SurchargeDecisionManagerRead),
api_locking::LockAction::NotApplicable,
)
.await
@@ -354,9 +402,13 @@ pub async fn upsert_decision_manager_config(
)
},
#[cfg(not(feature = "release"))]
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::SurchargeDecisionManagerRead),
+ req.headers(),
+ ),
#[cfg(feature = "release")]
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::SurchargeDecisionManagerRead),
api_locking::LockAction::NotApplicable,
))
.await
@@ -382,9 +434,13 @@ pub async fn delete_decision_manager_config(
)
},
#[cfg(not(feature = "release"))]
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::SurchargeDecisionManagerWrite),
+ req.headers(),
+ ),
#[cfg(feature = "release")]
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::SurchargeDecisionManagerWrite),
api_locking::LockAction::NotApplicable,
))
.await
@@ -406,9 +462,13 @@ pub async fn retrieve_decision_manager_config(
conditional_config::retrieve_conditional_config(state, auth.merchant_account)
},
#[cfg(not(feature = "release"))]
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::SurchargeDecisionManagerRead),
+ req.headers(),
+ ),
#[cfg(feature = "release")]
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::SurchargeDecisionManagerRead),
api_locking::LockAction::NotApplicable,
)
.await
@@ -434,9 +494,13 @@ pub async fn routing_retrieve_linked_config(
routing::retrieve_linked_routing_config(state, auth.merchant_account, query_params)
},
#[cfg(not(feature = "release"))]
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::RoutingRead),
+ req.headers(),
+ ),
#[cfg(feature = "release")]
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::RoutingRead),
api_locking::LockAction::NotApplicable,
))
.await
@@ -454,9 +518,13 @@ pub async fn routing_retrieve_linked_config(
routing::retrieve_linked_routing_config(state, auth.merchant_account)
},
#[cfg(not(feature = "release"))]
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::RoutingRead),
+ req.headers(),
+ ),
#[cfg(feature = "release")]
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::RoutingRead),
api_locking::LockAction::NotApplicable,
))
.await
@@ -478,9 +546,17 @@ pub async fn routing_retrieve_default_config_for_profiles(
routing::retrieve_default_routing_config_for_profiles(state, auth.merchant_account)
},
#[cfg(not(feature = "release"))]
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::RoutingRead),
+ req.headers(),
+ ),
#[cfg(feature = "release")]
- &auth::JWTAuth,
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::RoutingRead),
+ req.headers(),
+ ),
api_locking::LockAction::NotApplicable,
)
.await
@@ -512,9 +588,13 @@ pub async fn routing_update_default_config_for_profile(
)
},
#[cfg(not(feature = "release"))]
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::RoutingWrite),
+ req.headers(),
+ ),
#[cfg(feature = "release")]
- &auth::JWTAuth,
+ &auth::JWTAuth(Permission::RoutingWrite),
api_locking::LockAction::NotApplicable,
)
.await
diff --git a/crates/router/src/routes/user.rs b/crates/router/src/routes/user.rs
index 0ff11ce087b5..7d3d183eda76 100644
--- a/crates/router/src/routes/user.rs
+++ b/crates/router/src/routes/user.rs
@@ -29,3 +29,21 @@ pub async fn user_connect_account(
))
.await
}
+
+pub async fn change_password(
+ state: web::Data,
+ http_req: HttpRequest,
+ json_payload: web::Json,
+) -> HttpResponse {
+ let flow = Flow::ChangePassword;
+ Box::pin(api::server_wrap(
+ flow,
+ state.clone(),
+ &http_req,
+ json_payload.into_inner(),
+ |state, user, req| user::change_password(state, req, user),
+ &auth::DashboardNoPermissionAuth,
+ api_locking::LockAction::NotApplicable,
+ ))
+ .await
+}
diff --git a/crates/router/src/routes/verification.rs b/crates/router/src/routes/verification.rs
index d0525bb272e8..4bcbacdf9912 100644
--- a/crates/router/src/routes/verification.rs
+++ b/crates/router/src/routes/verification.rs
@@ -5,7 +5,7 @@ use router_env::{instrument, tracing, Flow};
use super::app::AppState;
use crate::{
core::{api_locking, verification},
- services::{api, authentication as auth},
+ services::{api, authentication as auth, authorization::permissions::Permission},
};
#[instrument(skip_all, fields(flow = ?Flow::Verification))]
@@ -32,7 +32,11 @@ pub async fn apple_pay_merchant_registration(
merchant_id.clone(),
)
},
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::MerchantAccountWrite),
+ req.headers(),
+ ),
api_locking::LockAction::NotApplicable,
))
.await
@@ -60,7 +64,11 @@ pub async fn retrieve_apple_pay_verified_domains(
mca_id.to_string(),
)
},
- auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+ auth::auth_type(
+ &auth::ApiKeyAuth,
+ &auth::JWTAuth(Permission::MerchantAccountRead),
+ req.headers(),
+ ),
api_locking::LockAction::NotApplicable,
)
.await
diff --git a/crates/router/src/services.rs b/crates/router/src/services.rs
index 0cd0313446a0..6f791681fb11 100644
--- a/crates/router/src/services.rs
+++ b/crates/router/src/services.rs
@@ -1,5 +1,6 @@
pub mod api;
pub mod authentication;
+pub mod authorization;
pub mod encryption;
#[cfg(feature = "olap")]
pub mod jwt;
diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs
index aae17195517d..5481d5c5cf9d 100644
--- a/crates/router/src/services/api.rs
+++ b/crates/router/src/services/api.rs
@@ -224,6 +224,7 @@ pub trait ConnectorIntegration: ConnectorIntegrationAny errors::UserResult {
+ ) -> UserResult {
let exp_duration = std::time::Duration::from_secs(consts::JWT_TOKEN_TIME_IN_SECS);
let exp = jwt::generate_exp(exp_duration)?.as_secs();
let token_payload = Self {
@@ -110,6 +113,14 @@ impl AuthToken {
}
}
+#[derive(Clone)]
+pub struct UserFromToken {
+ pub user_id: String,
+ pub merchant_id: String,
+ pub role_id: String,
+ pub org_id: String,
+}
+
pub trait AuthInfo {
fn get_merchant_id(&self) -> Option<&str>;
}
@@ -387,7 +398,7 @@ where
}
#[derive(Debug)]
-pub(crate) struct JWTAuth;
+pub(crate) struct JWTAuth(pub Permission);
#[derive(serde::Deserialize)]
struct JwtAuthPayloadFetchUnit {
@@ -406,6 +417,10 @@ where
state: &A,
) -> RouterResult<((), AuthenticationType)> {
let payload = parse_jwt_payload::(request_headers, state).await?;
+
+ let permissions = authorization::get_permissions(&payload.role_id)?;
+ authorization::check_authorization(&self.0, permissions)?;
+
Ok((
(),
AuthenticationType::MerchantJWT {
@@ -416,8 +431,37 @@ where
}
}
+#[cfg(feature = "olap")]
+#[async_trait]
+impl AuthenticateAndFetch for JWTAuth
+where
+ A: AppStateInfo + Sync,
+{
+ async fn authenticate_and_fetch(
+ &self,
+ request_headers: &HeaderMap,
+ state: &A,
+ ) -> RouterResult<(UserFromToken, AuthenticationType)> {
+ let payload = parse_jwt_payload::(request_headers, state).await?;
+
+ Ok((
+ UserFromToken {
+ user_id: payload.user_id.clone(),
+ merchant_id: payload.merchant_id.clone(),
+ org_id: payload.org_id,
+ role_id: payload.role_id,
+ },
+ AuthenticationType::MerchantJWT {
+ merchant_id: payload.merchant_id,
+ user_id: Some(payload.user_id),
+ },
+ ))
+ }
+}
+
pub struct JWTAuthMerchantFromRoute {
pub merchant_id: String,
+ pub required_permission: Permission,
}
#[async_trait]
@@ -432,6 +476,9 @@ where
) -> RouterResult<((), AuthenticationType)> {
let payload = parse_jwt_payload:: (request_headers, state).await?;
+ let permissions = authorization::get_permissions(&payload.role_id)?;
+ authorization::check_authorization(&self.required_permission, permissions)?;
+
// Check if token has access to merchantID that has been requested through query param
if payload.merchant_id != self.merchant_id {
return Err(report!(errors::ApiErrorResponse::InvalidJwtToken));
@@ -460,6 +507,7 @@ where
#[derive(serde::Deserialize)]
struct JwtAuthPayloadFetchMerchantAccount {
merchant_id: String,
+ role_id: String,
}
#[async_trait]
@@ -475,6 +523,10 @@ where
let payload =
parse_jwt_payload:: (request_headers, state)
.await?;
+
+ let permissions = authorization::get_permissions(&payload.role_id)?;
+ authorization::check_authorization(&self.0, permissions)?;
+
let key_store = state
.store()
.get_merchant_key_store_by_merchant_id(
@@ -505,6 +557,53 @@ where
}
}
+pub struct DashboardNoPermissionAuth;
+
+#[cfg(feature = "olap")]
+#[async_trait]
+impl AuthenticateAndFetch for DashboardNoPermissionAuth
+where
+ A: AppStateInfo + Sync,
+{
+ async fn authenticate_and_fetch(
+ &self,
+ request_headers: &HeaderMap,
+ state: &A,
+ ) -> RouterResult<(UserFromToken, AuthenticationType)> {
+ let payload = parse_jwt_payload::(request_headers, state).await?;
+
+ Ok((
+ UserFromToken {
+ user_id: payload.user_id.clone(),
+ merchant_id: payload.merchant_id.clone(),
+ org_id: payload.org_id,
+ role_id: payload.role_id,
+ },
+ AuthenticationType::MerchantJWT {
+ merchant_id: payload.merchant_id,
+ user_id: Some(payload.user_id),
+ },
+ ))
+ }
+}
+
+#[cfg(feature = "olap")]
+#[async_trait]
+impl AuthenticateAndFetch<(), A> for DashboardNoPermissionAuth
+where
+ A: AppStateInfo + Sync,
+{
+ async fn authenticate_and_fetch(
+ &self,
+ request_headers: &HeaderMap,
+ state: &A,
+ ) -> RouterResult<((), AuthenticationType)> {
+ parse_jwt_payload:: (request_headers, state).await?;
+
+ Ok(((), AuthenticationType::NoAuth))
+ }
+}
+
pub trait ClientSecretFetch {
fn get_client_secret(&self) -> Option<&String>;
}
diff --git a/crates/router/src/services/authorization.rs b/crates/router/src/services/authorization.rs
new file mode 100644
index 000000000000..cad9b1ece62e
--- /dev/null
+++ b/crates/router/src/services/authorization.rs
@@ -0,0 +1,27 @@
+use crate::core::errors::{ApiErrorResponse, RouterResult};
+
+pub mod info;
+pub mod permissions;
+pub mod predefined_permissions;
+
+pub fn get_permissions(role: &str) -> RouterResult<&Vec> {
+ predefined_permissions::PREDEFINED_PERMISSIONS
+ .get(role)
+ .map(|role_info| role_info.get_permissions())
+ .ok_or(ApiErrorResponse::InvalidJwtToken.into())
+}
+
+pub fn check_authorization(
+ required_permission: &permissions::Permission,
+ permissions: &[permissions::Permission],
+) -> RouterResult<()> {
+ permissions
+ .contains(required_permission)
+ .then_some(())
+ .ok_or(
+ ApiErrorResponse::AccessForbidden {
+ resource: required_permission.to_string(),
+ }
+ .into(),
+ )
+}
diff --git a/crates/router/src/services/authorization/info.rs b/crates/router/src/services/authorization/info.rs
new file mode 100644
index 000000000000..c6b649f3de5c
--- /dev/null
+++ b/crates/router/src/services/authorization/info.rs
@@ -0,0 +1,168 @@
+use strum::{EnumIter, IntoEnumIterator};
+
+use super::permissions::Permission;
+
+pub fn get_authorization_info() -> Vec {
+ PermissionModule::iter()
+ .map(|module| ModuleInfo::new(&module))
+ .collect()
+}
+
+pub struct PermissionInfo {
+ pub enum_name: Permission,
+ pub description: &'static str,
+}
+
+impl PermissionInfo {
+ pub fn new(permissions: &[Permission]) -> Vec {
+ let mut permission_infos = Vec::with_capacity(permissions.len());
+ for permission in permissions {
+ if let Some(description) = Permission::get_permission_description(permission) {
+ permission_infos.push(Self {
+ enum_name: permission.clone(),
+ description,
+ })
+ }
+ }
+ permission_infos
+ }
+}
+
+#[derive(PartialEq, EnumIter, Clone)]
+pub enum PermissionModule {
+ Payments,
+ Refunds,
+ MerchantAccount,
+ Connectors,
+ Forex,
+ Routing,
+ Analytics,
+ Mandates,
+ Disputes,
+ Files,
+ ThreeDsDecisionManager,
+ SurchargeDecisionManager,
+}
+
+impl PermissionModule {
+ pub fn get_module_description(&self) -> &'static str {
+ match self {
+ Self::Payments => "Everything related to payments - like creating and viewing payment related information are within this module",
+ Self::Refunds => "Refunds module encompasses everything related to refunds - like creating and viewing payment related information",
+ Self::MerchantAccount => "Accounts module permissions allow the user to view and update account details, configure webhooks and much more",
+ Self::Connectors => "All connector related actions - like configuring new connectors, viewing and updating connector configuration lies with this module",
+ Self::Routing => "All actions related to new, active, and past routing stacks take place here",
+ Self::Forex => "Forex module permissions allow the user to view and query the forex rates",
+ Self::Analytics => "Permission to view and analyse the data relating to payments, refunds, sdk etc.",
+ Self::Mandates => "Everything related to mandates - like creating and viewing mandate related information are within this module",
+ Self::Disputes => "Everything related to disputes - like creating and viewing dispute related information are within this module",
+ Self::Files => "Permissions for uploading, deleting and viewing files for disputes",
+ Self::ThreeDsDecisionManager => "View and configure 3DS decision rules configured for a merchant",
+ Self::SurchargeDecisionManager =>"View and configure surcharge decision rules configured for a merchant"
+ }
+ }
+}
+
+pub struct ModuleInfo {
+ pub module: PermissionModule,
+ pub description: &'static str,
+ pub permissions: Vec,
+}
+
+impl ModuleInfo {
+ pub fn new(module: &PermissionModule) -> Self {
+ let module_name = module.clone();
+ let description = module.get_module_description();
+
+ match module {
+ PermissionModule::Payments => Self {
+ module: module_name,
+ description,
+ permissions: PermissionInfo::new(&[
+ Permission::PaymentRead,
+ Permission::PaymentWrite,
+ ]),
+ },
+ PermissionModule::Refunds => Self {
+ module: module_name,
+ description,
+ permissions: PermissionInfo::new(&[
+ Permission::RefundRead,
+ Permission::RefundWrite,
+ ]),
+ },
+ PermissionModule::MerchantAccount => Self {
+ module: module_name,
+ description,
+ permissions: PermissionInfo::new(&[
+ Permission::MerchantAccountRead,
+ Permission::MerchantAccountWrite,
+ ]),
+ },
+ PermissionModule::Connectors => Self {
+ module: module_name,
+ description,
+ permissions: PermissionInfo::new(&[
+ Permission::MerchantConnectorAccountRead,
+ Permission::MerchantConnectorAccountWrite,
+ ]),
+ },
+ PermissionModule::Forex => Self {
+ module: module_name,
+ description,
+ permissions: PermissionInfo::new(&[Permission::ForexRead]),
+ },
+ PermissionModule::Routing => Self {
+ module: module_name,
+ description,
+ permissions: PermissionInfo::new(&[
+ Permission::RoutingRead,
+ Permission::RoutingWrite,
+ ]),
+ },
+ PermissionModule::Analytics => Self {
+ module: module_name,
+ description,
+ permissions: PermissionInfo::new(&[Permission::Analytics]),
+ },
+ PermissionModule::Mandates => Self {
+ module: module_name,
+ description,
+ permissions: PermissionInfo::new(&[
+ Permission::MandateRead,
+ Permission::MandateWrite,
+ ]),
+ },
+ PermissionModule::Disputes => Self {
+ module: module_name,
+ description,
+ permissions: PermissionInfo::new(&[
+ Permission::DisputeRead,
+ Permission::DisputeWrite,
+ ]),
+ },
+ PermissionModule::Files => Self {
+ module: module_name,
+ description,
+ permissions: PermissionInfo::new(&[Permission::FileRead, Permission::FileWrite]),
+ },
+ PermissionModule::ThreeDsDecisionManager => Self {
+ module: module_name,
+ description,
+ permissions: PermissionInfo::new(&[
+ Permission::ThreeDsDecisionManagerWrite,
+ Permission::ThreeDsDecisionManagerRead,
+ ]),
+ },
+
+ PermissionModule::SurchargeDecisionManager => Self {
+ module: module_name,
+ description,
+ permissions: PermissionInfo::new(&[
+ Permission::SurchargeDecisionManagerWrite,
+ Permission::SurchargeDecisionManagerRead,
+ ]),
+ },
+ }
+ }
+}
diff --git a/crates/router/src/services/authorization/permissions.rs b/crates/router/src/services/authorization/permissions.rs
new file mode 100644
index 000000000000..708da97e1e39
--- /dev/null
+++ b/crates/router/src/services/authorization/permissions.rs
@@ -0,0 +1,74 @@
+use strum::Display;
+
+#[derive(PartialEq, Display, Clone, Debug)]
+pub enum Permission {
+ PaymentRead,
+ PaymentWrite,
+ RefundRead,
+ RefundWrite,
+ ApiKeyRead,
+ ApiKeyWrite,
+ MerchantAccountRead,
+ MerchantAccountWrite,
+ MerchantConnectorAccountRead,
+ MerchantConnectorAccountWrite,
+ ForexRead,
+ RoutingRead,
+ RoutingWrite,
+ DisputeRead,
+ DisputeWrite,
+ MandateRead,
+ MandateWrite,
+ FileRead,
+ FileWrite,
+ Analytics,
+ ThreeDsDecisionManagerWrite,
+ ThreeDsDecisionManagerRead,
+ SurchargeDecisionManagerWrite,
+ SurchargeDecisionManagerRead,
+ UsersRead,
+ UsersWrite,
+ MerchantAccountCreate,
+}
+
+impl Permission {
+ pub fn get_permission_description(&self) -> Option<&'static str> {
+ match self {
+ Self::PaymentRead => Some("View all payments"),
+ Self::PaymentWrite => Some("Create payment, download payments data"),
+ Self::RefundRead => Some("View all refunds"),
+ Self::RefundWrite => Some("Create refund, download refunds data"),
+ Self::ApiKeyRead => Some("View API keys (masked generated for the system"),
+ Self::ApiKeyWrite => Some("Create and update API keys"),
+ Self::MerchantAccountRead => Some("View merchant account details"),
+ Self::MerchantAccountWrite => {
+ Some("Update merchant account details, configure webhooks, manage api keys")
+ }
+ Self::MerchantConnectorAccountRead => Some("View connectors configured"),
+ Self::MerchantConnectorAccountWrite => {
+ Some("Create, update, verify and delete connector configurations")
+ }
+ Self::ForexRead => Some("Query Forex data"),
+ Self::RoutingRead => Some("View routing configuration"),
+ Self::RoutingWrite => Some("Create and activate routing configurations"),
+ Self::DisputeRead => Some("View disputes"),
+ Self::DisputeWrite => Some("Create and update disputes"),
+ Self::MandateRead => Some("View mandates"),
+ Self::MandateWrite => Some("Create and update mandates"),
+ Self::FileRead => Some("View files"),
+ Self::FileWrite => Some("Create, update and delete files"),
+ Self::Analytics => Some("Access to analytics module"),
+ Self::ThreeDsDecisionManagerWrite => Some("Create and update 3DS decision rules"),
+ Self::ThreeDsDecisionManagerRead => {
+ Some("View all 3DS decision rules configured for a merchant")
+ }
+ Self::SurchargeDecisionManagerWrite => {
+ Some("Create and update the surcharge decision rules")
+ }
+ Self::SurchargeDecisionManagerRead => Some("View all the surcharge decision rules"),
+ Self::UsersRead => Some("View all the users for a merchant"),
+ Self::UsersWrite => Some("Invite users, assign and update roles"),
+ Self::MerchantAccountCreate => None,
+ }
+ }
+}
diff --git a/crates/router/src/services/authorization/predefined_permissions.rs b/crates/router/src/services/authorization/predefined_permissions.rs
new file mode 100644
index 000000000000..89fa2c8f739c
--- /dev/null
+++ b/crates/router/src/services/authorization/predefined_permissions.rs
@@ -0,0 +1,79 @@
+use std::collections::HashMap;
+
+use once_cell::sync::Lazy;
+
+use super::permissions::Permission;
+use crate::consts;
+
+pub struct RoleInfo {
+ permissions: Vec,
+ name: Option<&'static str>,
+ is_invitable: bool,
+}
+
+impl RoleInfo {
+ pub fn get_permissions(&self) -> &Vec {
+ &self.permissions
+ }
+
+ pub fn get_name(&self) -> Option<&'static str> {
+ self.name
+ }
+
+ pub fn is_invitable(&self) -> bool {
+ self.is_invitable
+ }
+}
+
+pub static PREDEFINED_PERMISSIONS: Lazy> = Lazy::new(|| {
+ let mut roles = HashMap::new();
+ roles.insert(
+ consts::ROLE_ID_ORGANIZATION_ADMIN,
+ RoleInfo {
+ permissions: vec![
+ Permission::PaymentRead,
+ Permission::PaymentWrite,
+ Permission::RefundRead,
+ Permission::RefundWrite,
+ Permission::ApiKeyRead,
+ Permission::ApiKeyWrite,
+ Permission::MerchantAccountRead,
+ Permission::MerchantAccountWrite,
+ Permission::MerchantConnectorAccountRead,
+ Permission::MerchantConnectorAccountWrite,
+ Permission::RoutingRead,
+ Permission::RoutingWrite,
+ Permission::ForexRead,
+ Permission::ThreeDsDecisionManagerWrite,
+ Permission::ThreeDsDecisionManagerRead,
+ Permission::SurchargeDecisionManagerWrite,
+ Permission::SurchargeDecisionManagerRead,
+ Permission::DisputeRead,
+ Permission::DisputeWrite,
+ Permission::MandateRead,
+ Permission::MandateWrite,
+ Permission::FileRead,
+ Permission::FileWrite,
+ Permission::Analytics,
+ Permission::UsersRead,
+ Permission::UsersWrite,
+ Permission::MerchantAccountCreate,
+ ],
+ name: Some("Organization Admin"),
+ is_invitable: false,
+ },
+ );
+ roles
+});
+
+pub fn get_role_name_from_id(role_id: &str) -> Option<&'static str> {
+ PREDEFINED_PERMISSIONS
+ .get(role_id)
+ .and_then(|role_info| role_info.name)
+}
+
+pub fn is_role_invitable(role_id: &str) -> bool {
+ PREDEFINED_PERMISSIONS
+ .get(role_id)
+ .map_or(false, |role_info| role_info.is_invitable)
+}
diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs
index a03e41650408..8c9d030965c9 100644
--- a/crates/router/src/types.rs
+++ b/crates/router/src/types.rs
@@ -30,9 +30,10 @@ use crate::core::utils::IRRELEVANT_CONNECTOR_REQUEST_REFERENCE_ID_IN_DISPUTE_FLO
use crate::{
core::{
errors::{self, RouterResult},
- payments::RecurringMandatePaymentData,
+ payments::{PaymentData, RecurringMandatePaymentData},
},
services,
+ types::storage::payment_attempt::PaymentAttemptExt,
utils::OptionExt,
};
@@ -544,59 +545,66 @@ pub struct AccessTokenRequestData {
}
pub trait Capturable {
- fn get_capture_amount(&self) -> Option {
+ fn get_capture_amount(&self, _payment_data: &PaymentData) -> Option
+ where
+ F: Clone,
+ {
None
}
- fn get_surcharge_amount(&self) -> Option {
- None
- }
- fn get_tax_on_surcharge_amount(&self) -> Option {
- None
- }
- fn is_psync(&self) -> bool {
- false
- }
}
impl Capturable for PaymentsAuthorizeData {
- fn get_capture_amount(&self) -> Option {
+ fn get_capture_amount(&self, _payment_data: &PaymentData) -> Option
+ where
+ F: Clone,
+ {
let final_amount = self
.surcharge_details
.as_ref()
.map(|surcharge_details| surcharge_details.final_amount);
final_amount.or(Some(self.amount))
}
- fn get_surcharge_amount(&self) -> Option {
- self.surcharge_details
- .as_ref()
- .map(|surcharge_details| surcharge_details.surcharge_amount)
- }
- fn get_tax_on_surcharge_amount(&self) -> Option {
- self.surcharge_details
- .as_ref()
- .map(|surcharge_details| surcharge_details.tax_on_surcharge_amount)
- }
}
impl Capturable for PaymentsCaptureData {
- fn get_capture_amount(&self) -> Option {
+ fn get_capture_amount(&self, _payment_data: &PaymentData) -> Option
+ where
+ F: Clone,
+ {
Some(self.amount_to_capture)
}
}
impl Capturable for CompleteAuthorizeData {
- fn get_capture_amount(&self) -> Option {
+ fn get_capture_amount(&self, _payment_data: &PaymentData) -> Option
+ where
+ F: Clone,
+ {
Some(self.amount)
}
}
impl Capturable for SetupMandateRequestData {}
-impl Capturable for PaymentsCancelData {}
+impl Capturable for PaymentsCancelData {
+ fn get_capture_amount(&self, payment_data: &PaymentData) -> Option
+ where
+ F: Clone,
+ {
+ // return previously captured amount
+ payment_data.payment_intent.amount_captured
+ }
+}
impl Capturable for PaymentsApproveData {}
impl Capturable for PaymentsRejectData {}
impl Capturable for PaymentsSessionData {}
impl Capturable for PaymentsSyncData {
- fn is_psync(&self) -> bool {
- true
+ fn get_capture_amount(&self, payment_data: &PaymentData) -> Option
+ where
+ F: Clone,
+ {
+ payment_data
+ .payment_attempt
+ .amount_to_capture
+ .or_else(|| Some(payment_data.payment_attempt.get_total_amount()))
}
}
@@ -952,6 +960,7 @@ pub struct ErrorResponse {
pub reason: Option,
pub status_code: u16,
pub attempt_status: Option,
+ pub connector_transaction_id: Option,
}
impl ErrorResponse {
@@ -968,6 +977,7 @@ impl ErrorResponse {
reason: None,
status_code: http::StatusCode::INTERNAL_SERVER_ERROR.as_u16(),
attempt_status: None,
+ connector_transaction_id: None,
}
}
}
@@ -1011,6 +1021,7 @@ impl From for ErrorResponse {
_ => 500,
},
attempt_status: None,
+ connector_transaction_id: None,
}
}
}
diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs
index b7d2fc8db33e..bcb3a9add553 100644
--- a/crates/router/src/types/api.rs
+++ b/crates/router/src/types/api.rs
@@ -114,6 +114,7 @@ pub trait ConnectorCommon {
message: consts::NO_ERROR_MESSAGE.to_string(),
reason: None,
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/utils.rs b/crates/router/src/utils.rs
index 83586e51d66a..901e84997e67 100644
--- a/crates/router/src/utils.rs
+++ b/crates/router/src/utils.rs
@@ -405,6 +405,7 @@ pub fn handle_json_response_deserialization_failure(
message: consts::UNSUPPORTED_ERROR_MESSAGE.to_string(),
reason: Some(response_data),
attempt_status: None,
+ connector_transaction_id: None,
})
}
}
diff --git a/crates/router/src/workflows/payment_sync.rs b/crates/router/src/workflows/payment_sync.rs
index c4b35cd6301a..f2760a00582d 100644
--- a/crates/router/src/workflows/payment_sync.rs
+++ b/crates/router/src/workflows/payment_sync.rs
@@ -135,11 +135,10 @@ impl ProcessTrackerWorkflow for PaymentsSyncWorkflow {
consts::REQUEST_TIMEOUT_ERROR_MESSAGE_FROM_PSYNC.to_string(),
)),
amount_capturable: Some(0),
- surcharge_amount: None,
- tax_amount: None,
updated_by: merchant_account.storage_scheme.to_string(),
unified_code: None,
unified_message: None,
+ connector_transaction_id: None,
};
payment_data.payment_attempt = db
diff --git a/crates/router_env/src/logger/types.rs b/crates/router_env/src/logger/types.rs
index 178f837fce18..7978e98e52c0 100644
--- a/crates/router_env/src/logger/types.rs
+++ b/crates/router_env/src/logger/types.rs
@@ -255,6 +255,8 @@ pub enum Flow {
DecisionManagerDeleteConfig,
/// Retrieve Decision Manager Config
DecisionManagerRetrieveConfig,
+ /// Change password flow
+ ChangePassword,
}
///
diff --git a/crates/storage_impl/src/payments/payment_attempt.rs b/crates/storage_impl/src/payments/payment_attempt.rs
index 238a2d75087c..06aacccc769d 100644
--- a/crates/storage_impl/src/payments/payment_attempt.rs
+++ b/crates/storage_impl/src/payments/payment_attempt.rs
@@ -553,7 +553,7 @@ impl PaymentAttemptInterface for KVRouterStore {
}
MerchantStorageScheme::RedisKv => {
// We assume that PaymentAttempt <=> PaymentIntent is a one-to-one relation for now
- let lookup_id = format!("{merchant_id}_{connector_transaction_id}");
+ let lookup_id = format!("conn_trans_{merchant_id}_{connector_transaction_id}");
let lookup = self
.get_lookup_by_lookup_id(&lookup_id, storage_scheme)
.await?;
@@ -774,7 +774,7 @@ impl PaymentAttemptInterface for KVRouterStore {
.await
}
MerchantStorageScheme::RedisKv => {
- let lookup_id = format!("{merchant_id}_{preprocessing_id}");
+ let lookup_id = format!("preprocessing_{merchant_id}_{preprocessing_id}");
let lookup = self
.get_lookup_by_lookup_id(&lookup_id, storage_scheme)
.await?;
@@ -1215,6 +1215,8 @@ impl DataModelExt for PaymentAttemptUpdate {
error_code,
error_message,
amount_capturable,
+ surcharge_amount,
+ tax_amount,
updated_by,
merchant_connector_id: connector_id,
} => DieselPaymentAttemptUpdate::ConfirmUpdate {
@@ -1234,6 +1236,8 @@ impl DataModelExt for PaymentAttemptUpdate {
error_code,
error_message,
amount_capturable,
+ surcharge_amount,
+ tax_amount,
updated_by,
merchant_connector_id: connector_id,
},
@@ -1261,8 +1265,6 @@ impl DataModelExt for PaymentAttemptUpdate {
connector_response_reference_id,
amount_capturable,
updated_by,
- surcharge_amount,
- tax_amount,
authentication_data,
encoded_data,
unified_code,
@@ -1282,8 +1284,6 @@ impl DataModelExt for PaymentAttemptUpdate {
connector_response_reference_id,
amount_capturable,
updated_by,
- surcharge_amount,
- tax_amount,
authentication_data,
encoded_data,
unified_code,
@@ -1320,11 +1320,10 @@ impl DataModelExt for PaymentAttemptUpdate {
error_message,
error_reason,
amount_capturable,
- tax_amount,
- surcharge_amount,
updated_by,
unified_code,
unified_message,
+ connector_transaction_id,
} => DieselPaymentAttemptUpdate::ErrorUpdate {
connector,
status,
@@ -1332,11 +1331,10 @@ impl DataModelExt for PaymentAttemptUpdate {
error_message,
error_reason,
amount_capturable,
- surcharge_amount,
- tax_amount,
updated_by,
unified_code,
unified_message,
+ connector_transaction_id,
},
Self::CaptureUpdate {
multiple_capture_count,
@@ -1478,6 +1476,8 @@ impl DataModelExt for PaymentAttemptUpdate {
error_code,
error_message,
amount_capturable,
+ surcharge_amount,
+ tax_amount,
updated_by,
merchant_connector_id: connector_id,
} => Self::ConfirmUpdate {
@@ -1497,6 +1497,8 @@ impl DataModelExt for PaymentAttemptUpdate {
error_code,
error_message,
amount_capturable,
+ surcharge_amount,
+ tax_amount,
updated_by,
merchant_connector_id: connector_id,
},
@@ -1524,8 +1526,6 @@ impl DataModelExt for PaymentAttemptUpdate {
connector_response_reference_id,
amount_capturable,
updated_by,
- surcharge_amount,
- tax_amount,
authentication_data,
encoded_data,
unified_code,
@@ -1545,8 +1545,6 @@ impl DataModelExt for PaymentAttemptUpdate {
connector_response_reference_id,
amount_capturable,
updated_by,
- surcharge_amount,
- tax_amount,
authentication_data,
encoded_data,
unified_code,
@@ -1583,11 +1581,10 @@ impl DataModelExt for PaymentAttemptUpdate {
error_message,
error_reason,
amount_capturable,
- surcharge_amount,
- tax_amount,
updated_by,
unified_code,
unified_message,
+ connector_transaction_id,
} => Self::ErrorUpdate {
connector,
status,
@@ -1596,10 +1593,9 @@ impl DataModelExt for PaymentAttemptUpdate {
error_reason,
amount_capturable,
updated_by,
- surcharge_amount,
- tax_amount,
unified_code,
unified_message,
+ connector_transaction_id,
},
DieselPaymentAttemptUpdate::CaptureUpdate {
amount_to_capture,
@@ -1675,7 +1671,7 @@ async fn add_connector_txn_id_to_reverse_lookup(
) -> CustomResult {
let field = format!("pa_{}", updated_attempt_attempt_id);
let reverse_lookup_new = ReverseLookupNew {
- lookup_id: format!("{}_{}", merchant_id, connector_transaction_id),
+ lookup_id: format!("conn_trans_{}_{}", merchant_id, connector_transaction_id),
pk_id: key.to_owned(),
sk_id: field.clone(),
source: "payment_attempt".to_string(),
@@ -1697,7 +1693,7 @@ async fn add_preprocessing_id_to_reverse_lookup(
) -> CustomResult {
let field = format!("pa_{}", updated_attempt_attempt_id);
let reverse_lookup_new = ReverseLookupNew {
- lookup_id: format!("{}_{}", merchant_id, preprocessing_id),
+ lookup_id: format!("preprocessing_{}_{}", merchant_id, preprocessing_id),
pk_id: key.to_owned(),
sk_id: field.clone(),
source: "payment_attempt".to_string(),
diff --git a/docker-compose-development.yml b/docker-compose-development.yml
new file mode 100644
index 000000000000..500f397cfa30
--- /dev/null
+++ b/docker-compose-development.yml
@@ -0,0 +1,301 @@
+version: "3.8"
+
+volumes:
+ cargo_cache:
+ pg_data:
+ router_build_cache:
+ scheduler_build_cache:
+ drainer_build_cache:
+ redisinsight_store:
+
+networks:
+ router_net:
+
+services:
+ ### Dependencies
+ pg:
+ image: postgres:latest
+ ports:
+ - "5432:5432"
+ networks:
+ - router_net
+ volumes:
+ - pg_data:/VAR/LIB/POSTGRESQL/DATA
+ environment:
+ - POSTGRES_USER=db_user
+ - POSTGRES_PASSWORD=db_pass
+ - POSTGRES_DB=hyperswitch_db
+
+ redis-standalone:
+ image: redis:7
+ labels:
+ - redis
+ networks:
+ - router_net
+ ports:
+ - "6379"
+
+ migration_runner:
+ image: rust:latest
+ command: "bash -c 'cargo install diesel_cli --no-default-features --features postgres && diesel migration --database-url postgres://$${DATABASE_USER}:$${DATABASE_PASSWORD}@$${DATABASE_HOST}:$${DATABASE_PORT}/$${DATABASE_NAME} run'"
+ working_dir: /app
+ networks:
+ - router_net
+ volumes:
+ - ./:/app
+ environment:
+ - DATABASE_USER=db_user
+ - DATABASE_PASSWORD=db_pass
+ - DATABASE_HOST=pg
+ - DATABASE_PORT=5432
+ - DATABASE_NAME=hyperswitch_db
+
+ ### Application services
+ hyperswitch-server:
+ image: rust:latest
+ command: cargo run --bin router -- -f ./config/docker_compose.toml
+ working_dir: /app
+ ports:
+ - "8080:8080"
+ networks:
+ - router_net
+ volumes:
+ - ./:/app
+ - cargo_cache:/cargo_cache
+ - router_build_cache:/cargo_build_cache
+ environment:
+ - CARGO_HOME=/cargo_cache
+ - CARGO_TARGET_DIR=/cargo_build_cache
+ labels:
+ logs: "promtail"
+ healthcheck:
+ test: curl --fail http://localhost:8080/health || exit 1
+ interval: 120s
+ retries: 4
+ start_period: 20s
+ timeout: 10s
+
+ hyperswitch-producer:
+ image: rust:latest
+ command: cargo run --bin scheduler -- -f ./config/docker_compose.toml
+ working_dir: /app
+ networks:
+ - router_net
+ profiles:
+ - scheduler
+ volumes:
+ - ./:/app
+ - cargo_cache:/cargo_cache
+ - scheduler_build_cache:/cargo_build_cache
+ environment:
+ - CARGO_HOME=/cargo_cache
+ - CARGO_TARGET_DIR=/cargo_build_cache
+ - SCHEDULER_FLOW=producer
+ depends_on:
+ hyperswitch-consumer:
+ condition: service_healthy
+ labels:
+ logs: "promtail"
+
+ hyperswitch-consumer:
+ image: rust:latest
+ command: cargo run --bin scheduler -- -f ./config/docker_compose.toml
+ working_dir: /app
+ networks:
+ - router_net
+ profiles:
+ - scheduler
+ volumes:
+ - ./:/app
+ - cargo_cache:/cargo_cache
+ - scheduler_build_cache:/cargo_build_cache
+ environment:
+ - CARGO_HOME=/cargo_cache
+ - CARGO_TARGET_DIR=/cargo_build_cache
+ - SCHEDULER_FLOW=consumer
+ depends_on:
+ hyperswitch-server:
+ condition: service_started
+ labels:
+ logs: "promtail"
+ healthcheck:
+ test: (ps -e | grep scheduler) || exit 1
+ interval: 120s
+ retries: 4
+ start_period: 30s
+ timeout: 10s
+
+ hyperswitch-drainer:
+ image: rust:latest
+ command: cargo run --bin drainer -- -f ./config/docker_compose.toml
+ working_dir: /app
+ deploy:
+ replicas: ${DRAINER_INSTANCE_COUNT:-1}
+ networks:
+ - router_net
+ profiles:
+ - full_kv
+ volumes:
+ - ./:/app
+ - cargo_cache:/cargo_cache
+ - drainer_build_cache:/cargo_build_cache
+ environment:
+ - CARGO_HOME=/cargo_cache
+ - CARGO_TARGET_DIR=/cargo_build_cache
+ restart: unless-stopped
+ depends_on:
+ hyperswitch-server:
+ condition: service_started
+ labels:
+ logs: "promtail"
+
+ ### Clustered Redis setup
+ redis-cluster:
+ image: redis:7
+ deploy:
+ replicas: ${REDIS_CLUSTER_COUNT:-3}
+ command: redis-server /usr/local/etc/redis/redis.conf
+ profiles:
+ - clustered_redis
+ volumes:
+ - ./config/redis.conf:/usr/local/etc/redis/redis.conf
+ labels:
+ - redis
+ networks:
+ - router_net
+ ports:
+ - "6379"
+ - "16379"
+
+ redis-init:
+ image: redis:7
+ profiles:
+ - clustered_redis
+ depends_on:
+ - redis-cluster
+ networks:
+ - router_net
+ command: "bash -c 'export COUNT=${REDIS_CLUSTER_COUNT:-3}
+
+ \ if [ $$COUNT -lt 3 ]
+
+ \ then
+
+ \ echo \"Minimum 3 nodes are needed for redis cluster\"
+
+ \ exit 1
+
+ \ fi
+
+ \ HOSTS=\"\"
+
+ \ for ((c=1; c<=$$COUNT;c++))
+
+ \ do
+
+ \ NODE=$COMPOSE_PROJECT_NAME-redis-cluster-$$c:6379
+
+ \ echo $$NODE
+
+ \ HOSTS=\"$$HOSTS $$NODE\"
+
+ \ done
+
+ \ echo Creating a cluster with $$HOSTS
+
+ \ redis-cli --cluster create $$HOSTS --cluster-yes
+
+ \ '"
+
+ ### Monitoring
+ grafana:
+ image: grafana/grafana:latest
+ ports:
+ - "3000:3000"
+ networks:
+ - router_net
+ profiles:
+ - monitoring
+ restart: unless-stopped
+ environment:
+ - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
+ - GF_AUTH_ANONYMOUS_ENABLED=true
+ - GF_AUTH_BASIC_ENABLED=false
+ volumes:
+ - ./config/grafana.ini:/etc/grafana/grafana.ini
+ - ./config/grafana-datasource.yaml:/etc/grafana/provisioning/datasources/datasource.yml
+
+ promtail:
+ image: grafana/promtail:latest
+ volumes:
+ - ./logs:/var/log/router
+ - ./config:/etc/promtail
+ - /var/run/docker.sock:/var/run/docker.sock
+ command: -config.file=/etc/promtail/promtail.yaml
+ profiles:
+ - monitoring
+ networks:
+ - router_net
+
+ loki:
+ image: grafana/loki:latest
+ ports:
+ - "3100"
+ command: -config.file=/etc/loki/loki.yaml
+ networks:
+ - router_net
+ profiles:
+ - monitoring
+ volumes:
+ - ./config:/etc/loki
+
+ otel-collector:
+ image: otel/opentelemetry-collector-contrib:latest
+ command: --config=/etc/otel-collector.yaml
+ networks:
+ - router_net
+ profiles:
+ - monitoring
+ volumes:
+ - ./config/otel-collector.yaml:/etc/otel-collector.yaml
+ ports:
+ - "4317"
+ - "8888"
+ - "8889"
+
+ prometheus:
+ image: prom/prometheus:latest
+ networks:
+ - router_net
+ profiles:
+ - monitoring
+ volumes:
+ - ./config/prometheus.yaml:/etc/prometheus/prometheus.yml
+ ports:
+ - "9090"
+ restart: unless-stopped
+
+ tempo:
+ image: grafana/tempo:latest
+ command: -config.file=/etc/tempo.yaml
+ volumes:
+ - ./config/tempo.yaml:/etc/tempo.yaml
+ networks:
+ - router_net
+ profiles:
+ - monitoring
+ ports:
+ - "3200" # tempo
+ - "4317" # otlp grpc
+ restart: unless-stopped
+
+ redis-insight:
+ image: redislabs/redisinsight:latest
+ networks:
+ - router_net
+ profiles:
+ - full_kv
+ ports:
+ - "8001:8001"
+ volumes:
+ - redisinsight_store:/db
diff --git a/docker-compose.yml b/docker-compose.yml
index f4dce575132e..fd18906143f5 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,76 +1,16 @@
-version: "3.7"
+version: "3.8"
volumes:
- cargo_cache:
pg_data:
- cargo_build_cache:
- p_cargo_build_cache:
- c_cargo_build_cache:
redisinsight_store:
-
networks:
router_net:
-
services:
- promtail:
- image: grafana/promtail:latest
- volumes:
- - ./logs:/var/log/router
- - ./config:/etc/promtail
- - /var/run/docker.sock:/var/run/docker.sock
- command: -config.file=/etc/promtail/promtail.yaml
- profiles:
- - monitoring
- networks:
- - router_net
-
- loki:
- image: grafana/loki:latest
- ports:
- - "3100"
- command: -config.file=/etc/loki/loki.yaml
- networks:
- - router_net
- profiles:
- - monitoring
- volumes:
- - ./config:/etc/loki
-
- otel-collector:
- image: otel/opentelemetry-collector-contrib:latest
- command: --config=/etc/otel-collector.yaml
- networks:
- - router_net
- profiles:
- - monitoring
- volumes:
- - ./config/otel-collector.yaml:/etc/otel-collector.yaml
- ports:
- - "4317"
- - "8888"
- - "8889"
-
- grafana:
- image: grafana/grafana:latest
- ports:
- - "3000:3000"
- networks:
- - router_net
- profiles:
- - monitoring
- restart: unless-stopped
- environment:
- - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
- - GF_AUTH_ANONYMOUS_ENABLED=true
- - GF_AUTH_BASIC_ENABLED=false
- volumes:
- - ./config/grafana.ini:/etc/grafana/grafana.ini
- - ./config/grafana-datasource.yaml:/etc/grafana/provisioning/datasources/datasource.yml
-
+ ### Dependencies
pg:
- image: postgres:14.5
+ image: postgres:latest
ports:
- "5432:5432"
networks:
@@ -82,52 +22,59 @@ services:
- POSTGRES_PASSWORD=db_pass
- POSTGRES_DB=hyperswitch_db
+ redis-standalone:
+ image: redis:7
+ labels:
+ - redis
+ networks:
+ - router_net
+ ports:
+ - "6379"
+
migration_runner:
- image: rust:1.70
- command: "bash -c 'cargo install diesel_cli --no-default-features --features \"postgres\" && diesel migration --database-url postgres://db_user:db_pass@pg:5432/hyperswitch_db run'"
+ image: rust:latest
+ command: "bash -c 'cargo install diesel_cli --no-default-features --features postgres && diesel migration --database-url postgres://$${DATABASE_USER}:$${DATABASE_PASSWORD}@$${DATABASE_HOST}:$${DATABASE_PORT}/$${DATABASE_NAME} run'"
working_dir: /app
networks:
- router_net
volumes:
- ./:/app
+ environment:
+ - DATABASE_USER=db_user
+ - DATABASE_PASSWORD=db_pass
+ - DATABASE_HOST=pg
+ - DATABASE_PORT=5432
+ - DATABASE_NAME=hyperswitch_db
+ ### Application services
hyperswitch-server:
- image: rust:1.70
- command: cargo run -- -f ./config/docker_compose.toml
- working_dir: /app
+ image: juspaydotin/hyperswitch-router:standalone
+ command: /local/bin/router -f /local/config/docker_compose.toml
ports:
- "8080:8080"
networks:
- router_net
volumes:
- - ./:/app
- - cargo_cache:/cargo_cache
- - cargo_build_cache:/cargo_build_cache
- environment:
- - CARGO_TARGET_DIR=/cargo_build_cache
+ - ./config:/local/config
labels:
logs: "promtail"
healthcheck:
test: curl --fail http://localhost:8080/health || exit 1
- interval: 100s
+ interval: 10s
retries: 3
- start_period: 20s
+ start_period: 5s
timeout: 10s
hyperswitch-producer:
- image: rust:1.70
- command: cargo run --bin scheduler -- -f ./config/docker_compose.toml
- working_dir: /app
+ image: juspaydotin/hyperswitch-producer:standalone
+ command: /local/bin/scheduler -f /local/config/docker_compose.toml
networks:
- router_net
profiles:
- scheduler
volumes:
- - ./:/app
- - cargo_cache:/cargo_cache
- - p_cargo_build_cache:/cargo_build_cache
+ - ./config:/local/config
environment:
- - CARGO_TARGET_DIR=/cargo_build_cache
- SCHEDULER_FLOW=producer
depends_on:
hyperswitch-consumer:
@@ -136,39 +83,54 @@ services:
logs: "promtail"
hyperswitch-consumer:
- image: rust:1.70
- command: cargo run --bin scheduler -- -f ./config/docker_compose.toml
- working_dir: /app
+ image: juspaydotin/hyperswitch-consumer:standalone
+ command: /local/bin/scheduler -f /local/config/docker_compose.toml
networks:
- router_net
profiles:
- scheduler
volumes:
- - ./:/app
- - cargo_cache:/cargo_cache
- - c_cargo_build_cache:/cargo_build_cache
+ - ./config:/local/config
environment:
- - CARGO_TARGET_DIR=/cargo_build_cache
- SCHEDULER_FLOW=consumer
depends_on:
hyperswitch-server:
condition: service_started
-
labels:
logs: "promtail"
-
healthcheck:
test: (ps -e | grep scheduler) || exit 1
- interval: 120s
+ interval: 10s
retries: 3
- start_period: 30s
+ start_period: 5s
timeout: 10s
+ hyperswitch-drainer:
+ image: juspaydotin/hyperswitch-drainer:standalone
+ command: /local/bin/drainer -f /local/config/docker_compose.toml
+ deploy:
+ replicas: ${DRAINER_INSTANCE_COUNT:-1}
+ networks:
+ - router_net
+ profiles:
+ - full_kv
+ volumes:
+ - ./config:/local/config
+ restart: unless-stopped
+ depends_on:
+ hyperswitch-server:
+ condition: service_started
+ labels:
+ logs: "promtail"
+
+ ### Clustered Redis setup
redis-cluster:
image: redis:7
deploy:
replicas: ${REDIS_CLUSTER_COUNT:-3}
command: redis-server /usr/local/etc/redis/redis.conf
+ profiles:
+ - clustered_redis
volumes:
- ./config/redis.conf:/usr/local/etc/redis/redis.conf
labels:
@@ -179,17 +141,10 @@ services:
- "6379"
- "16379"
- redis-standalone:
- image: redis:7
- labels:
- - redis
- networks:
- - router_net
- ports:
- - "6379"
-
redis-init:
image: redis:7
+ profiles:
+ - clustered_redis
depends_on:
- redis-cluster
networks:
@@ -226,16 +181,62 @@ services:
\ '"
- redis-insight:
- image: redislabs/redisinsight:latest
+ ### Monitoring
+ grafana:
+ image: grafana/grafana:latest
+ ports:
+ - "3000:3000"
networks:
- router_net
profiles:
- - full_kv
+ - monitoring
+ restart: unless-stopped
+ environment:
+ - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
+ - GF_AUTH_ANONYMOUS_ENABLED=true
+ - GF_AUTH_BASIC_ENABLED=false
+ volumes:
+ - ./config/grafana.ini:/etc/grafana/grafana.ini
+ - ./config/grafana-datasource.yaml:/etc/grafana/provisioning/datasources/datasource.yml
+
+ promtail:
+ image: grafana/promtail:latest
+ volumes:
+ - ./logs:/var/log/router
+ - ./config:/etc/promtail
+ - /var/run/docker.sock:/var/run/docker.sock
+ command: -config.file=/etc/promtail/promtail.yaml
+ profiles:
+ - monitoring
+ networks:
+ - router_net
+
+ loki:
+ image: grafana/loki:latest
ports:
- - "8001:8001"
+ - "3100"
+ command: -config.file=/etc/loki/loki.yaml
+ networks:
+ - router_net
+ profiles:
+ - monitoring
volumes:
- - redisinsight_store:/db
+ - ./config:/etc/loki
+
+ otel-collector:
+ image: otel/opentelemetry-collector-contrib:latest
+ command: --config=/etc/otel-collector.yaml
+ networks:
+ - router_net
+ profiles:
+ - monitoring
+ volumes:
+ - ./config/otel-collector.yaml:/etc/otel-collector.yaml
+ ports:
+ - "4317"
+ - "8888"
+ - "8889"
+
prometheus:
image: prom/prometheus:latest
networks:
@@ -261,25 +262,14 @@ services:
- "3200" # tempo
- "4317" # otlp grpc
restart: unless-stopped
- hyperswitch-drainer:
- image: rust:1.70
- command: cargo run --bin drainer -- -f ./config/docker_compose.toml
- working_dir: /app
- deploy:
- replicas: ${DRAINER_INSTANCE_COUNT:-1}
+
+ redis-insight:
+ image: redislabs/redisinsight:latest
networks:
- router_net
profiles:
- full_kv
+ ports:
+ - "8001:8001"
volumes:
- - ./:/app
- - cargo_cache:/cargo_cache
- - cargo_build_cache:/cargo_build_cache
- environment:
- - CARGO_TARGET_DIR=/cargo_build_cache
- restart: unless-stopped
- depends_on:
- hyperswitch-server:
- condition: service_started
- labels:
- logs: "promtail"
+ - redisinsight_store:/db
diff --git a/docs/architecture.md b/docs/architecture.md
index 3ab3b6a7eafa..24b0c726205a 100644
--- a/docs/architecture.md
+++ b/docs/architecture.md
@@ -49,12 +49,7 @@ In addition to the database, Hyperswitch incorporates Redis for two main purpose
## Locker
-The application utilizes a Locker, which consists of two distinct services: Temporary Locker and Permanent Locker. These services are responsible for securely storing payment-method information and adhere strictly to **Payment Card Industry Data Security Standard (PCI DSS)** compliance standards, ensuring that all payment-related data is handled and stored securely.
-
-- **Temporary Locker:** The Temporary Locker service handles the temporary storage of payment-method information. This temporary storage facilitates the smooth processing of transactions and reduces the exposure of sensitive information.
-- **Permanent Locker:** The Permanent Locker service is responsible for the long-term storage of payment-method related data. It securely stores card details, such as cardholder information or payment method details, for future reference or recurring payments.
-
-> Currently, Locker service is not part of open-source
+The application utilizes a Rust locker built with a GDPR compliant PII (personal identifiable information) storage. It also uses secure encryption algorithms to be fully compliant with **PCI DSS** (Payment Card Industry Data Security Standard) requirements, this ensures that all payment-related data is handled and stored securely. You can find the source code of locker [here](https://github.com/juspay/hyperswitch-card-vault).
## Monitoring
diff --git a/docs/imgs/hyperswitch-architecture.png b/docs/imgs/hyperswitch-architecture.png
index 18f42f9a55c5..f73f60f3e35e 100644
Binary files a/docs/imgs/hyperswitch-architecture.png and b/docs/imgs/hyperswitch-architecture.png differ
diff --git a/docs/try_local_system.md b/docs/try_local_system.md
index 59df43f24810..a9cd080f26d5 100644
--- a/docs/try_local_system.md
+++ b/docs/try_local_system.md
@@ -1,23 +1,20 @@
# Try out hyperswitch on your system
-**NOTE:**
-This guide is aimed at users and developers who wish to set up hyperswitch on
-their local systems and requires quite some time and effort.
-If you'd prefer trying out hyperswitch quickly without the hassle of setting up
-all dependencies, you can [try out hyperswitch sandbox environment][try-sandbox].
-
-There are two options to set up hyperswitch on your system:
-
-1. Use Docker Compose
-2. Set up a Rust environment and other dependencies on your system
+The simplest way to run hyperswitch locally is
+[with Docker Compose](#run-hyperswitch-using-docker-compose) by pulling the
+latest images from Docker Hub.
+However, if you're willing to modify the code and run it, or are a developer
+contributing to hyperswitch, then you can either
+[set up a development environment using Docker Compose](#set-up-a-development-environment-using-docker-compose),
+or [set up a Rust environment on your system](#set-up-a-rust-environment-and-other-dependencies).
Check the Table Of Contents to jump to the relevant section.
-[try-sandbox]: ./try_sandbox.md
-
**Table Of Contents:**
-- [Set up hyperswitch using Docker Compose](#set-up-hyperswitch-using-docker-compose)
+- [Run hyperswitch using Docker Compose](#run-hyperswitch-using-docker-compose)
+ - [Run the scheduler and monitoring services](#run-the-scheduler-and-monitoring-services)
+- [Set up a development environment using Docker Compose](#set-up-a-development-environment-using-docker-compose)
- [Set up a Rust environment and other dependencies](#set-up-a-rust-environment-and-other-dependencies)
- [Set up dependencies on Ubuntu-based systems](#set-up-dependencies-on-ubuntu-based-systems)
- [Set up dependencies on Windows (Ubuntu on WSL2)](#set-up-dependencies-on-windows-ubuntu-on-wsl2)
@@ -33,7 +30,7 @@ Check the Table Of Contents to jump to the relevant section.
- [Create a Payment](#create-a-payment)
- [Create a Refund](#create-a-refund)
-## Set up hyperswitch using Docker Compose
+## Run hyperswitch using Docker Compose
1. Install [Docker Compose][docker-compose-install].
2. Clone the repository and switch to the project directory:
@@ -54,15 +51,15 @@ Check the Table Of Contents to jump to the relevant section.
docker compose up -d
```
-5. Run database migrations:
-
- ```shell
- docker compose run hyperswitch-server bash -c \
- "cargo install diesel_cli && \
- diesel migration --database-url postgres://db_user:db_pass@pg:5432/hyperswitch_db run"
- ```
+ This should run the hyperswitch payments router, the primary component within
+ hyperswitch.
+ Wait for the `migration_runner` container to finish installing `diesel_cli`
+ and running migrations (approximately 2 minutes) before proceeding further.
+ You can also choose to
+ [run the scheduler and monitoring services](#run-the-scheduler-and-monitoring-services)
+ in addition to the payments router.
-6. Verify that the server is up and running by hitting the health endpoint:
+5. Verify that the server is up and running by hitting the health endpoint:
```shell
curl --head --request GET 'http://localhost:8080/health'
@@ -71,9 +68,86 @@ Check the Table Of Contents to jump to the relevant section.
If the command returned a `200 OK` status code, proceed with
[trying out our APIs](#try-out-our-apis).
+### Run the scheduler and monitoring services
+
+You can run the scheduler and monitoring services by specifying suitable profile
+names to the above Docker Compose command.
+To understand more about the hyperswitch architecture and the components
+involved, check out the [architecture document][architecture].
+
+- To run the scheduler components (consumer and producer), you can specify
+ `--profile scheduler`:
+
+ ```shell
+ docker compose --profile scheduler up -d
+ ```
+
+- To run the monitoring services (Grafana, Promtail, Loki, Prometheus and Tempo),
+ you can specify `--profile monitoring`:
+
+ ```shell
+ docker compose --profile monitoring up -d
+ ```
+
+ You can then access Grafana at `http://localhost:3000` and view application
+ logs using the "Explore" tab, select Loki as the data source, and select the
+ container to query logs from.
+
+- You can also specify multiple profile names by specifying the `--profile` flag
+ multiple times.
+ To run both the scheduler components and monitoring services, the Docker
+ Compose command would be:
+
+ ```shell
+ docker compose --profile scheduler --profile monitoring up -d
+ ```
+
+Once the services have been confirmed to be up and running, you can proceed with
+[trying out our APIs](#try-out-our-apis)
+
[docker-compose-install]: https://docs.docker.com/compose/install/
[docker-compose-config]: /config/docker_compose.toml
[docker-compose-yml]: /docker-compose.yml
+[architecture]: /docs/architecture.md
+
+## Set up a development environment using Docker Compose
+
+1. Install [Docker Compose][docker-compose-install].
+2. Clone the repository and switch to the project directory:
+
+ ```shell
+ git clone https://github.com/juspay/hyperswitch
+ cd hyperswitch
+ ```
+
+3. (Optional) Configure the application using the
+ [`config/docker_compose.toml`][docker-compose-config] file.
+ The provided configuration should work as is.
+ If you do update the `docker_compose.toml` file, ensure to also update the
+ corresponding values in the [`docker-compose.yml`][docker-compose-yml] file.
+4. Start all the services using Docker Compose:
+
+ ```shell
+ docker compose --file docker-compose-development.yml up -d
+ ```
+
+ This will compile the payments router, the primary component within
+ hyperswitch and then start it.
+ Depending on the specifications of your machine, compilation can take
+ around 15 minutes.
+
+5. (Optional) You can also choose to
+ [start the scheduler and/or monitoring services](#run-the-scheduler-and-monitoring-services)
+ in addition to the payments router.
+
+6. Verify that the server is up and running by hitting the health endpoint:
+
+ ```shell
+ curl --head --request GET 'http://localhost:8080/health'
+ ```
+
+ If the command returned a `200 OK` status code, proceed with
+ [trying out our APIs](#try-out-our-apis).
## Set up a Rust environment and other dependencies
@@ -134,7 +208,7 @@ for your distribution and follow along.
4. Install `diesel_cli` using `cargo`:
```shell
- cargo install diesel_cli --no-default-features --features "postgres"
+ cargo install diesel_cli --no-default-features --features postgres
```
5. Make sure your system has the `pkg-config` package and OpenSSL installed:
@@ -224,7 +298,7 @@ packages for your distribution and follow along.
6. Install `diesel_cli` using `cargo`:
```shell
- cargo install diesel_cli --no-default-features --features "postgres"
+ cargo install diesel_cli --no-default-features --features postgres
```
7. Make sure your system has the `pkg-config` package and OpenSSL installed:
@@ -260,7 +334,7 @@ You can opt to use your favorite package manager instead.
4. Install `diesel_cli` using `cargo`:
```shell
- cargo install diesel_cli --no-default-features --features "postgres"
+ cargo install diesel_cli --no-default-features --features postgres
```
5. Install OpenSSL with `winget`:
@@ -322,7 +396,7 @@ You can opt to use your favorite package manager instead.
4. Install `diesel_cli` using `cargo`:
```shell
- cargo install diesel_cli --no-default-features --features "postgres"
+ cargo install diesel_cli --no-default-features --features postgres
```
If linking `diesel_cli` fails due to missing `libpq` (if the error message is
@@ -333,7 +407,7 @@ You can opt to use your favorite package manager instead.
brew install libpq
export PQ_LIB_DIR="$(brew --prefix libpq)/lib"
- cargo install diesel_cli --no-default-features --features "postgres"
+ cargo install diesel_cli --no-default-features --features postgres
```
You may also choose to persist the value of `PQ_LIB_DIR` in your shell
diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json
index 056601ac707d..88a0d115ff01 100644
--- a/openapi/openapi_spec.json
+++ b/openapi/openapi_spec.json
@@ -5372,13 +5372,13 @@
{
"type": "string",
"enum": [
- "user_addressline1"
+ "user_address_line1"
]
},
{
"type": "string",
"enum": [
- "user_addressline2"
+ "user_address_line2"
]
},
{
diff --git a/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Confirm/request.json b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Confirm/request.json
index 8559af25e82c..91426564e8e1 100644
--- a/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Confirm/request.json
+++ b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Confirm/request.json
@@ -39,10 +39,6 @@
},
"raw_json_formatted": {
"client_secret": "{{client_secret}}",
- "surcharge_details": {
- "surcharge_amount": 5,
- "tax_amount": 5
- },
"payment_method": "card",
"payment_method_data": {
"card": {
diff --git a/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Create/request.json b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Create/request.json
index f7d813c34efd..9e084a35c8c9 100644
--- a/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Create/request.json
+++ b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Create/request.json
@@ -31,6 +31,10 @@
"description": "Its my first payment request",
"authentication_type": "no_three_ds",
"return_url": "https://duck.com",
+ "surcharge_details": {
+ "surcharge_amount": 5,
+ "tax_amount": 5
+ },
"billing": {
"address": {
"line1": "1467",
diff --git a/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario12-BNPL-klarna/Payments - Create/request.json b/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario12-BNPL-klarna/Payments - Create/request.json
index b0bc12a6ac89..f621bd52f00d 100644
--- a/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario12-BNPL-klarna/Payments - Create/request.json
+++ b/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario12-BNPL-klarna/Payments - Create/request.json
@@ -23,7 +23,7 @@
"confirm": false,
"capture_method": "automatic",
"capture_on": "2022-09-10T10:11:12Z",
- "amount_to_capture": 6540,
+ "amount_to_capture": 8000,
"customer_id": "StripeCustomer",
"email": "guest@example.com",
"name": "John Doe",
diff --git a/postman/collection-json/paypal.postman_collection.json b/postman/collection-json/paypal.postman_collection.json
index d9deae47f9af..a6ee545a9497 100644
--- a/postman/collection-json/paypal.postman_collection.json
+++ b/postman/collection-json/paypal.postman_collection.json
@@ -808,7 +808,7 @@
"language": "json"
}
},
- "raw": "{\"amount\":6540,\"currency\":\"USD\",\"confirm\":false,\"capture_method\":\"manual\",\"capture_on\":\"2022-09-10T10:11:12Z\",\"customer_id\":\"StripeCustomer\",\"email\":\"guest@example.com\",\"name\":\"John Doe\",\"phone\":\"999999999\",\"phone_country_code\":\"+1\",\"description\":\"Its my first payment request\",\"authentication_type\":\"no_three_ds\",\"return_url\":\"https://duck.com\",\"billing\":{\"address\":{\"line1\":\"1467\",\"line2\":\"Harrison Street\",\"line3\":\"Harrison Street\",\"city\":\"San Fransico\",\"state\":\"California\",\"zip\":\"94122\",\"country\":\"US\",\"first_name\":\"PiX\"}},\"shipping\":{\"address\":{\"line1\":\"1467\",\"line2\":\"Harrison Street\",\"line3\":\"Harrison Street\",\"city\":\"San Fransico\",\"state\":\"California\",\"zip\":\"94122\",\"country\":\"US\",\"first_name\":\"PiX\"}},\"statement_descriptor_name\":\"joseph\",\"statement_descriptor_suffix\":\"JS\",\"metadata\":{\"udf1\":\"value1\",\"new_customer\":\"true\",\"login_date\":\"2019-09-10T10:11:12Z\"},\"routing\":{\"type\":\"single\",\"data\":\"paypal\"}}"
+ "raw": "{\"amount\":6540,\"currency\":\"USD\",\"confirm\":false,\"capture_method\":\"manual\",\"capture_on\":\"2022-09-10T10:11:12Z\",\"customer_id\":\"StripeCustomer\",\"email\":\"guest@example.com\",\"name\":\"John Doe\",\"phone\":\"999999999\",\"phone_country_code\":\"+1\",\"description\":\"Its my first payment request\",\"authentication_type\":\"no_three_ds\",\"return_url\":\"https://duck.com\",\"surcharge_details\":{\"surcharge_amount\":5,\"tax_amount\":5},\"billing\":{\"address\":{\"line1\":\"1467\",\"line2\":\"Harrison Street\",\"line3\":\"Harrison Street\",\"city\":\"San Fransico\",\"state\":\"California\",\"zip\":\"94122\",\"country\":\"US\",\"first_name\":\"PiX\"}},\"shipping\":{\"address\":{\"line1\":\"1467\",\"line2\":\"Harrison Street\",\"line3\":\"Harrison Street\",\"city\":\"San Fransico\",\"state\":\"California\",\"zip\":\"94122\",\"country\":\"US\",\"first_name\":\"PiX\"}},\"statement_descriptor_name\":\"joseph\",\"statement_descriptor_suffix\":\"JS\",\"metadata\":{\"udf1\":\"value1\",\"new_customer\":\"true\",\"login_date\":\"2019-09-10T10:11:12Z\"},\"routing\":{\"type\":\"single\",\"data\":\"paypal\"}}"
},
"url": {
"raw": "{{baseUrl}}/payments",
@@ -990,7 +990,7 @@
"language": "json"
}
},
- "raw": "{\"client_secret\":\"{{client_secret}}\",\"surcharge_details\":{\"surcharge_amount\":5,\"tax_amount\":5},\"payment_method\":\"card\",\"payment_method_data\":{\"card\":{\"card_number\":\"4012000033330026\",\"card_exp_month\":\"10\",\"card_exp_year\":\"25\",\"card_holder_name\":\"joseph Doe\",\"card_cvc\":\"123\"}}}"
+ "raw": "{\"client_secret\":\"{{client_secret}}\",\"payment_method\":\"card\",\"payment_method_data\":{\"card\":{\"card_number\":\"4012000033330026\",\"card_exp_month\":\"10\",\"card_exp_year\":\"25\",\"card_holder_name\":\"joseph Doe\",\"card_cvc\":\"123\"}}}"
},
"url": {
"raw": "{{baseUrl}}/payments/:id/confirm",
diff --git a/postman/collection-json/stripe.postman_collection.json b/postman/collection-json/stripe.postman_collection.json
index 9bdb5fdb44d9..4d3e548f535f 100644
--- a/postman/collection-json/stripe.postman_collection.json
+++ b/postman/collection-json/stripe.postman_collection.json
@@ -14445,7 +14445,7 @@
"language": "json"
}
},
- "raw": "{\"amount\":8000,\"currency\":\"USD\",\"confirm\":false,\"capture_method\":\"automatic\",\"capture_on\":\"2022-09-10T10:11:12Z\",\"amount_to_capture\":6540,\"customer_id\":\"StripeCustomer\",\"email\":\"guest@example.com\",\"name\":\"John Doe\",\"phone\":\"999999999\",\"phone_country_code\":\"+65\",\"description\":\"Its my first payment request\",\"authentication_type\":\"no_three_ds\",\"return_url\":\"https://duck.com\",\"statement_descriptor_name\":\"joseph\",\"statement_descriptor_suffix\":\"JS\",\"metadata\":{\"udf1\":\"value1\",\"new_customer\":\"true\",\"login_date\":\"2019-09-10T10:11:12Z\"},\"routing\":{\"type\":\"single\",\"data\":\"stripe\"}}"
+ "raw": "{\"amount\":8000,\"currency\":\"USD\",\"confirm\":false,\"capture_method\":\"automatic\",\"capture_on\":\"2022-09-10T10:11:12Z\",\"amount_to_capture\":8000,\"customer_id\":\"StripeCustomer\",\"email\":\"guest@example.com\",\"name\":\"John Doe\",\"phone\":\"999999999\",\"phone_country_code\":\"+65\",\"description\":\"Its my first payment request\",\"authentication_type\":\"no_three_ds\",\"return_url\":\"https://duck.com\",\"statement_descriptor_name\":\"joseph\",\"statement_descriptor_suffix\":\"JS\",\"metadata\":{\"udf1\":\"value1\",\"new_customer\":\"true\",\"login_date\":\"2019-09-10T10:11:12Z\"},\"routing\":{\"type\":\"single\",\"data\":\"stripe\"}}"
},
"url": {
"raw": "{{baseUrl}}/payments",
diff --git a/scripts/add_connector.sh b/scripts/add_connector.sh
index 9fdc57bf3c81..9a30fe9d7573 100755
--- a/scripts/add_connector.sh
+++ b/scripts/add_connector.sh
@@ -45,7 +45,7 @@ cd $SCRIPT/..
# Remove template files if already created for this connector
rm -rf $conn/$payment_gateway $conn/$payment_gateway.rs
-git checkout $conn.rs $src/types/api.rs $src/configs/settings.rs config/development.toml config/docker_compose.toml config/config.example.toml loadtest/config/development.toml crates/api_models/src/enums.rs $src/core/payments/flows.rs
+git checkout $conn.rs $src/types/api.rs $src/configs/settings.rs config/development.toml config/docker_compose.toml config/config.example.toml loadtest/config/development.toml crates/api_models/src/enums.rs crates/euclid/src/enums.rs crates/api_models/src/routing.rs $src/core/payments/flows.rs $src/core/admin.rs $src/core/payments/routing/transformers.rs $src/types/transformers.rs
# Add enum for this connector in required places
previous_connector=''
@@ -54,15 +54,21 @@ previous_connector_camelcase="$(tr '[:lower:]' '[:upper:]' <<< ${previous_connec
sed -i'' -e "s|pub mod $previous_connector;|pub mod $previous_connector;\npub mod ${payment_gateway};|" $conn.rs
sed -i'' -e "s/};/${payment_gateway}::${payment_gateway_camelcase},\n};/" $conn.rs
sed -i'' -e "s|$previous_connector_camelcase \(.*\)|$previous_connector_camelcase \1\n\t\t\tenums::Connector::${payment_gateway_camelcase} => Ok(Box::new(\&connector::${payment_gateway_camelcase})),|" $src/types/api.rs
+sed -i'' -e "s|$previous_connector_camelcase \(.*\)|$previous_connector_camelcase \1\n\t\t\tRoutableConnectors::${payment_gateway_camelcase} => euclid_enums::Connector::${payment_gateway_camelcase},|" crates/api_models/src/routing.rs
sed -i'' -e "s/pub $previous_connector: \(.*\)/pub $previous_connector: \1\n\tpub ${payment_gateway}: ConnectorParams,/" $src/configs/settings.rs
sed -i'' -e "s|$previous_connector.base_url \(.*\)|$previous_connector.base_url \1\n${payment_gateway}.base_url = \"$base_url\"|" config/development.toml config/docker_compose.toml config/config.example.toml loadtest/config/development.toml
sed -r -i'' -e "s/\"$previous_connector\",/\"$previous_connector\",\n \"${payment_gateway}\",/" config/development.toml config/docker_compose.toml config/config.example.toml loadtest/config/development.toml
sed -i '' -e "s/\(pub enum Connector {\)/\1\n\t${payment_gateway_camelcase},/" crates/api_models/src/enums.rs
+sed -i '' -e "s/\(pub enum Connector {\)/\1\n\t${payment_gateway_camelcase},/" crates/euclid/src/enums.rs
+sed -i '' -e "s/\(match connector_name {\)/\1\n\t\tapi_enums::Connector::${payment_gateway_camelcase} => {${payment_gateway}::transformers::${payment_gateway_camelcase}AuthType::try_from(val)?;Ok(())}/" $src/core/admin.rs
+sed -i'' -e "s|$previous_connector_camelcase \(.*\)|$previous_connector_camelcase \1\n\t\t\tapi_enums::RoutableConnectors::${payment_gateway_camelcase} => Self::${payment_gateway_camelcase},|" $src/core/payments/routing/transformers.rs
+sed -i'' -e "s|dsl_enums::Connector::$previous_connector_camelcase \(.*\)|dsl_enums::Connector::$previous_connector_camelcase \1\n\t\t\tdsl_enums::Connector::${payment_gateway_camelcase} => Self::${payment_gateway_camelcase},|" $src/types/transformers.rs
+sed -i'' -e "s|api_enums::Connector::$previous_connector_camelcase \(.*\)|api_enums::Connector::$previous_connector_camelcase \1\n\t\t\tapi_enums::Connector::${payment_gateway_camelcase} => Self::${payment_gateway_camelcase},|" $src/types/transformers.rs
sed -i'' -e "s/\(pub enum RoutableConnectors {\)/\1\n\t${payment_gateway_camelcase},/" crates/api_models/src/enums.rs
sed -i'' -e "s/^default_imp_for_\(.*\)/default_imp_for_\1\n\tconnector::${payment_gateway_camelcase},/" $src/core/payments/flows.rs
# Remove temporary files created in above step
-rm $conn.rs-e $src/types/api.rs-e $src/configs/settings.rs-e config/development.toml-e config/docker_compose.toml-e config/config.example.toml-e loadtest/config/development.toml-e crates/api_models/src/enums.rs-e $src/core/payments/flows.rs-e
+rm $conn.rs-e $src/types/api.rs-e $src/configs/settings.rs-e config/development.toml-e config/docker_compose.toml-e config/config.example.toml-e loadtest/config/development.toml-e crates/api_models/src/enums.rs-e crates/euclid/src/enums.rs-e crates/api_models/src/routing.rs-e $src/core/payments/flows.rs-e $src/core/admin.rs-e $src/core/payments/routing/transformers.rs-e $src/types/transformers.rs-e
cd $conn/
# Generate template files for the connector