diff --git a/.typos.toml b/.typos.toml
index 1ac38a005c9e..4ce21526604b 100644
--- a/.typos.toml
+++ b/.typos.toml
@@ -24,6 +24,7 @@ optin = "optin" # Boku preflow name
optin_id = "optin_id" # Boku's id for optin flow
deriver = "deriver"
Deriver = "Deriver"
+requestor_card_reference = "requestor_card_reference"
[default.extend-words]
aci = "aci" # Name of a connector
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 427fa7403e4c..141bfd40ac5d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,67 @@ All notable changes to HyperSwitch will be documented here.
- - -
+## 1.84.0 (2023-11-17)
+
+### Features
+
+- **connector:** [BANKOFAMERICA] PSYNC Bugfix ([#2897](https://github.com/juspay/hyperswitch/pull/2897)) ([`bdcc138`](https://github.com/juspay/hyperswitch/commit/bdcc138e8d84577fc99f9a9aef3484b66f98209a))
+
+**Full Changelog:** [`v1.83.1...v1.84.0`](https://github.com/juspay/hyperswitch/compare/v1.83.1...v1.84.0)
+
+- - -
+
+
+## 1.83.1 (2023-11-17)
+
+### Bug Fixes
+
+- **router:** Add choice to use the appropriate key for jws verification ([#2917](https://github.com/juspay/hyperswitch/pull/2917)) ([`606daa9`](https://github.com/juspay/hyperswitch/commit/606daa9367cac8c2ea926313019deab2f938b591))
+
+**Full Changelog:** [`v1.83.0...v1.83.1`](https://github.com/juspay/hyperswitch/compare/v1.83.0...v1.83.1)
+
+- - -
+
+
+## 1.83.0 (2023-11-17)
+
+### Features
+
+- **events:** Add incoming webhook payload to api events logger ([#2852](https://github.com/juspay/hyperswitch/pull/2852)) ([`aea390a`](https://github.com/juspay/hyperswitch/commit/aea390a6a1c331f8e0dbea4f41218e43f7323508))
+- **router:** Custom payment link config for payment create ([#2741](https://github.com/juspay/hyperswitch/pull/2741)) ([`c39beb2`](https://github.com/juspay/hyperswitch/commit/c39beb2501e63bbf7fd41bbc947280d7ff5a71dc))
+
+### Bug Fixes
+
+- **router:** Add rust locker url in proxy_bypass_urls ([#2902](https://github.com/juspay/hyperswitch/pull/2902)) ([`9a201ae`](https://github.com/juspay/hyperswitch/commit/9a201ae698c2cf52e617660f82d5bf1df2e797ae))
+
+### Documentation
+
+- **README:** Replace cloudformation deployment template with latest s3 url. ([#2891](https://github.com/juspay/hyperswitch/pull/2891)) ([`375108b`](https://github.com/juspay/hyperswitch/commit/375108b6df50e041fc9dbeb35a6a6b46b146037a))
+
+**Full Changelog:** [`v1.82.0...v1.83.0`](https://github.com/juspay/hyperswitch/compare/v1.82.0...v1.83.0)
+
+- - -
+
+
+## 1.82.0 (2023-11-17)
+
+### Features
+
+- **router:** Add fallback while add card and retrieve card from rust locker ([#2888](https://github.com/juspay/hyperswitch/pull/2888)) ([`f735fb0`](https://github.com/juspay/hyperswitch/commit/f735fb0551812fd781a2db8bac5a0deef4cabb2b))
+
+### Bug Fixes
+
+- **core:** Introduce new attempt and intent status to handle multiple partial captures ([#2802](https://github.com/juspay/hyperswitch/pull/2802)) ([`cb88be0`](https://github.com/juspay/hyperswitch/commit/cb88be01f22725948648976c2a5606a03b5ce92a))
+
+### Testing
+
+- **postman:** Update postman collection files ([`7d05b74`](https://github.com/juspay/hyperswitch/commit/7d05b74b950d9e078b063e17d046cbeb501d006a))
+
+**Full Changelog:** [`v1.81.0...v1.82.0`](https://github.com/juspay/hyperswitch/compare/v1.81.0...v1.82.0)
+
+- - -
+
+
## 1.81.0 (2023-11-16)
### Features
diff --git a/Cargo.lock b/Cargo.lock
index a03340093c88..730b08774fa3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4797,6 +4797,7 @@ dependencies = [
"digest 0.9.0",
"dyn-clone",
"encoding_rs",
+ "erased-serde",
"error-stack",
"euclid",
"external_services",
diff --git a/README.md b/README.md
index 129a0512d4a0..bc528da9bbf5 100644
--- a/README.md
+++ b/README.md
@@ -64,9 +64,7 @@ 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.
- Click here if you have not bootstrapped your region before deploying
-
-
+
2. Sign-in to your AWS console.
diff --git a/config/config.example.toml b/config/config.example.toml
index 02eff1d42979..7815f2400d04 100644
--- a/config/config.example.toml
+++ b/config/config.example.toml
@@ -21,25 +21,25 @@ idle_pool_connection_timeout = 90 # Timeout for idle pool connections (defaults
# Main SQL data store credentials
[master_database]
-username = "db_user" # DB Username
-password = "db_pass" # DB Password. Use base-64 encoded kms encrypted value here when kms is enabled
-host = "localhost" # DB Host
-port = 5432 # DB Port
-dbname = "hyperswitch_db" # Name of Database
-pool_size = 5 # Number of connections to keep open
-connection_timeout = 10 # Timeout for database connection in seconds
-queue_strategy = "Fifo" # Add the queue strategy used by the database bb8 client
+username = "db_user" # DB Username
+password = "db_pass" # DB Password. Use base-64 encoded kms encrypted value here when kms is enabled
+host = "localhost" # DB Host
+port = 5432 # DB Port
+dbname = "hyperswitch_db" # Name of Database
+pool_size = 5 # Number of connections to keep open
+connection_timeout = 10 # Timeout for database connection in seconds
+queue_strategy = "Fifo" # Add the queue strategy used by the database bb8 client
# Replica SQL data store credentials
[replica_database]
-username = "replica_user" # DB Username
-password = "db_pass" # DB Password. Use base-64 encoded kms encrypted value here when kms is enabled
-host = "localhost" # DB Host
-port = 5432 # DB Port
-dbname = "hyperswitch_db" # Name of Database
-pool_size = 5 # Number of connections to keep open
-connection_timeout = 10 # Timeout for database connection in seconds
-queue_strategy = "Fifo" # Add the queue strategy used by the database bb8 client
+username = "replica_user" # DB Username
+password = "db_pass" # DB Password. Use base-64 encoded kms encrypted value here when kms is enabled
+host = "localhost" # DB Host
+port = 5432 # DB Port
+dbname = "hyperswitch_db" # Name of Database
+pool_size = 5 # Number of connections to keep open
+connection_timeout = 10 # Timeout for database connection in seconds
+queue_strategy = "Fifo" # Add the queue strategy used by the database bb8 client
# Redis credentials
[redis]
@@ -95,17 +95,17 @@ sampling_rate = 0.1 # decimal rate between 0.0
otel_exporter_otlp_endpoint = "http://localhost:4317" # endpoint to send metrics and traces to, can include port number
otel_exporter_otlp_timeout = 5000 # timeout (in milliseconds) for sending metrics and traces
use_xray_generator = false # Set this to true for AWS X-ray compatible traces
-route_to_trace = [ "*/confirm" ]
+route_to_trace = ["*/confirm"]
# This section provides some secret values.
[secrets]
-master_enc_key = "sample_key" # Master Encryption key used to encrypt merchant wise encryption key. Should be 32-byte long.
-admin_api_key = "test_admin" # admin API key for admin authentication. Only applicable when KMS is disabled.
-kms_encrypted_admin_api_key = "" # Base64-encoded (KMS encrypted) ciphertext of the admin_api_key. Only applicable when KMS is enabled.
-jwt_secret = "secret" # JWT secret used for user authentication. Only applicable when KMS is disabled.
-kms_encrypted_jwt_secret = "" # Base64-encoded (KMS encrypted) ciphertext of the jwt_secret. Only applicable when KMS is enabled.
-recon_admin_api_key = "recon_test_admin" # recon_admin API key for recon authentication. Only applicable when KMS is disabled.
-kms_encrypted_recon_admin_api_key = "" # Base64-encoded (KMS encrypted) ciphertext of the recon_admin_api_key. Only applicable when KMS is enabled
+master_enc_key = "sample_key" # Master Encryption key used to encrypt merchant wise encryption key. Should be 32-byte long.
+admin_api_key = "test_admin" # admin API key for admin authentication. Only applicable when KMS is disabled.
+kms_encrypted_admin_api_key = "" # Base64-encoded (KMS encrypted) ciphertext of the admin_api_key. Only applicable when KMS is enabled.
+jwt_secret = "secret" # JWT secret used for user authentication. Only applicable when KMS is disabled.
+kms_encrypted_jwt_secret = "" # Base64-encoded (KMS encrypted) ciphertext of the jwt_secret. Only applicable when KMS is enabled.
+recon_admin_api_key = "recon_test_admin" # recon_admin API key for recon authentication. Only applicable when KMS is disabled.
+kms_encrypted_recon_admin_api_key = "" # Base64-encoded (KMS encrypted) ciphertext of the recon_admin_api_key. Only applicable when KMS is enabled
# Locker settings contain details for accessing a card locker, a
# PCI Compliant storage entity which stores payment method information
@@ -124,15 +124,15 @@ connectors_with_delayed_session_response = "trustpay,payme" # List of connectors
connectors_with_webhook_source_verification_call = "paypal" # List of connectors which has additional source verification api-call
[jwekey] # 4 priv/pub key pair
-locker_key_identifier1 = "" # key identifier for key rotation , should be same as basilisk
-locker_key_identifier2 = "" # key identifier for key rotation , should be same as basilisk
-locker_encryption_key1 = "" # public key 1 in pem format, corresponding private key in basilisk
-locker_encryption_key2 = "" # public key 2 in pem format, corresponding private key in basilisk
-locker_decryption_key1 = "" # private key 1 in pem format, corresponding public key in basilisk
-locker_decryption_key2 = "" # private key 2 in pem format, corresponding public key in basilisk
-vault_encryption_key = "" # public key in pem format, corresponding private key in basilisk-hs
+locker_key_identifier1 = "" # key identifier for key rotation , should be same as basilisk
+locker_key_identifier2 = "" # key identifier for key rotation , should be same as basilisk
+locker_encryption_key1 = "" # public key 1 in pem format, corresponding private key in basilisk
+locker_encryption_key2 = "" # public key 2 in pem format, corresponding private key in basilisk
+locker_decryption_key1 = "" # private key 1 in pem format, corresponding public key in basilisk
+locker_decryption_key2 = "" # private key 2 in pem format, corresponding public key in basilisk
+vault_encryption_key = "" # public key in pem format, corresponding private key in basilisk-hs
rust_locker_encryption_key = "" # public key in pem format, corresponding private key in rust locker
-vault_private_key = "" # private key in pem format, corresponding public key in basilisk-hs
+vault_private_key = "" # private key in pem format, corresponding public key in basilisk-hs
# Refund configuration
@@ -234,11 +234,11 @@ adyen = { banks = "e_platby_vub,postova_banka,sporo_pay,tatra_pay,viamo" }
# Bank redirect configs for allowed banks through online_banking_poland payment method
[bank_config.online_banking_poland]
-adyen = { banks = "blik_psp,place_zipko,m_bank,pay_with_ing,santander_przelew24,bank_pekaosa,bank_millennium,pay_with_alior_bank,banki_spoldzielcze,pay_with_inteligo,bnp_paribas_poland,bank_nowy_sa,credit_agricole,pay_with_bos,pay_with_citi_handlowy,pay_with_plus_bank,toyota_bank,velo_bank,e_transfer_pocztowy24"}
+adyen = { banks = "blik_psp,place_zipko,m_bank,pay_with_ing,santander_przelew24,bank_pekaosa,bank_millennium,pay_with_alior_bank,banki_spoldzielcze,pay_with_inteligo,bnp_paribas_poland,bank_nowy_sa,credit_agricole,pay_with_bos,pay_with_citi_handlowy,pay_with_plus_bank,toyota_bank,velo_bank,e_transfer_pocztowy24" }
# Bank redirect configs for allowed banks through open_banking_uk payment method
[bank_config.open_banking_uk]
-adyen = { banks = "aib,bank_of_scotland,danske_bank,first_direct,first_trust,halifax,lloyds,monzo,nat_west,nationwide_bank,royal_bank_of_scotland,starling,tsb_bank,tesco_bank,ulster_bank,barclays,hsbc_bank,revolut,santander_przelew24,open_bank_success,open_bank_failure,open_bank_cancelled"}
+adyen = { banks = "aib,bank_of_scotland,danske_bank,first_direct,first_trust,halifax,lloyds,monzo,nat_west,nationwide_bank,royal_bank_of_scotland,starling,tsb_bank,tesco_bank,ulster_bank,barclays,hsbc_bank,revolut,santander_przelew24,open_bank_success,open_bank_failure,open_bank_cancelled" }
# Bank redirect configs for allowed banks through przelewy24 payment method
[bank_config.przelewy24]
@@ -313,89 +313,92 @@ region = "" # The AWS region used by the KMS SDK for decrypting data.
# EmailClient configuration. Only applicable when the `email` feature flag is enabled.
[email]
from_email = "notify@example.com" # Sender email
-aws_region = "" # AWS region used by AWS SES
-base_url = "" # Base url used when adding links that should redirect to self
+aws_region = "" # AWS region used by AWS SES
+base_url = "" # Base url used when adding links that should redirect to self
#tokenization configuration which describe token lifetime and payment method for specific connector
[tokenization]
stripe = { long_lived_token = false, payment_method = "wallet", payment_method_type = { type = "disable_only", list = "google_pay" } }
checkout = { long_lived_token = false, payment_method = "wallet" }
-mollie = {long_lived_token = false, payment_method = "card"}
+mollie = { long_lived_token = false, payment_method = "card" }
stax = { long_lived_token = true, payment_method = "card,bank_debit" }
-square = {long_lived_token = false, payment_method = "card"}
+square = { long_lived_token = false, payment_method = "card" }
braintree = { long_lived_token = false, payment_method = "card" }
-gocardless = {long_lived_token = true, payment_method = "bank_debit"}
+gocardless = { long_lived_token = true, payment_method = "bank_debit" }
[temp_locker_enable_config]
-stripe = {payment_method = "bank_transfer"}
-nuvei = {payment_method = "card"}
-shift4 = {payment_method = "card"}
-bluesnap = {payment_method = "card"}
+stripe = { payment_method = "bank_transfer" }
+nuvei = { payment_method = "card" }
+shift4 = { payment_method = "card" }
+bluesnap = { payment_method = "card" }
[dummy_connector]
-enabled = true # Whether dummy connector is enabled or not
-payment_ttl = 172800 # Time to live for dummy connector payment in redis
-payment_duration = 1000 # Fake delay duration for dummy connector payment
-payment_tolerance = 100 # Fake delay tolerance for dummy connector payment
-payment_retrieve_duration = 500 # Fake delay duration for dummy connector payment sync
-payment_retrieve_tolerance = 100 # Fake delay tolerance for dummy connector payment sync
-payment_complete_duration = 500 # Fake delay duration for dummy connector payment complete
-payment_complete_tolerance = 100 # Fake delay tolerance for dummy connector payment complete
-refund_ttl = 172800 # Time to live for dummy connector refund in redis
-refund_duration = 1000 # Fake delay duration for dummy connector refund
-refund_tolerance = 100 # Fake delay tolerance for dummy connector refund
-refund_retrieve_duration = 500 # Fake delay duration for dummy connector refund sync
-refund_retrieve_tolerance = 100 # Fake delay tolerance for dummy connector refund sync
-authorize_ttl = 36000 # Time to live for dummy connector authorize request in redis
+enabled = true # Whether dummy connector is enabled or not
+payment_ttl = 172800 # Time to live for dummy connector payment in redis
+payment_duration = 1000 # Fake delay duration for dummy connector payment
+payment_tolerance = 100 # Fake delay tolerance for dummy connector payment
+payment_retrieve_duration = 500 # Fake delay duration for dummy connector payment sync
+payment_retrieve_tolerance = 100 # Fake delay tolerance for dummy connector payment sync
+payment_complete_duration = 500 # Fake delay duration for dummy connector payment complete
+payment_complete_tolerance = 100 # Fake delay tolerance for dummy connector payment complete
+refund_ttl = 172800 # Time to live for dummy connector refund in redis
+refund_duration = 1000 # Fake delay duration for dummy connector refund
+refund_tolerance = 100 # Fake delay tolerance for dummy connector refund
+refund_retrieve_duration = 500 # Fake delay duration for dummy connector refund sync
+refund_retrieve_tolerance = 100 # Fake delay tolerance for dummy connector refund sync
+authorize_ttl = 36000 # Time to live for dummy connector authorize request in redis
assets_base_url = "https://www.example.com/" # Base url for dummy connector assets
default_return_url = "https://www.example.com/" # Default return url when no return url is passed while payment
slack_invite_url = "https://www.example.com/" # Slack invite url for hyperswitch
discord_invite_url = "https://www.example.com/" # Discord invite url for hyperswitch
[mandates.supported_payment_methods]
-card.credit = {connector_list = "stripe,adyen"} # Mandate supported payment method type and connector for card
-wallet.paypal = {connector_list = "adyen"} # Mandate supported payment method type and connector for wallets
-pay_later.klarna = {connector_list = "adyen"} # Mandate supported payment method type and connector for pay_later
-bank_debit.ach = { connector_list = "gocardless"} # Mandate supported payment method type and connector for bank_debit
-bank_debit.becs = { connector_list = "gocardless"} # Mandate supported payment method type and connector for bank_debit
-bank_debit.sepa = { connector_list = "gocardless"} # Mandate supported payment method type and connector for bank_debit
+card.credit = { connector_list = "stripe,adyen" } # Mandate supported payment method type and connector for card
+wallet.paypal = { connector_list = "adyen" } # Mandate supported payment method type and connector for wallets
+pay_later.klarna = { connector_list = "adyen" } # Mandate supported payment method type and connector for pay_later
+bank_debit.ach = { connector_list = "gocardless" } # Mandate supported payment method type and connector for bank_debit
+bank_debit.becs = { connector_list = "gocardless" } # Mandate supported payment method type and connector for bank_debit
+bank_debit.sepa = { connector_list = "gocardless" } # Mandate supported payment method type and connector for bank_debit
# Required fields info used while listing the payment_method_data
[required_fields.pay_later] # payment_method = "pay_later"
-afterpay_clearpay = {fields = {stripe = [ # payment_method_type = afterpay_clearpay, connector = "stripe"
- # Required fields vector with its respective display name in front-end and field_type
- { required_field = "shipping.address.first_name", display_name = "first_name", field_type = "text" },
- { required_field = "shipping.address.last_name", display_name = "last_name", field_type = "text" },
- { required_field = "shipping.address.country", display_name = "country", field_type = { drop_down = { options = [ "US", "IN" ] } } },
- ] } }
+afterpay_clearpay = { fields = { stripe = [ # payment_method_type = afterpay_clearpay, connector = "stripe"
+ # Required fields vector with its respective display name in front-end and field_type
+ { required_field = "shipping.address.first_name", display_name = "first_name", field_type = "text" },
+ { required_field = "shipping.address.last_name", display_name = "last_name", field_type = "text" },
+ { required_field = "shipping.address.country", display_name = "country", field_type = { drop_down = { options = [
+ "US",
+ "IN",
+ ] } } },
+] } }
[payouts]
-payout_eligibility = true # Defaults the eligibility of a payout method to true in case connector does not provide checks for payout eligibility
+payout_eligibility = true # Defaults the eligibility of a payout method to true in case connector does not provide checks for payout eligibility
[pm_filters.adyen]
-online_banking_fpx = {country = "MY", currency = "MYR"}
-online_banking_thailand = {country = "TH", currency = "THB"}
-touch_n_go = {country = "MY", currency = "MYR"}
-atome = {country = "MY,SG", currency = "MYR,SGD"}
-swish = {country = "SE", currency = "SEK"}
-permata_bank_transfer = {country = "ID", currency = "IDR"}
-bca_bank_transfer = {country = "ID", currency = "IDR"}
-bni_va = {country = "ID", currency = "IDR"}
-bri_va = {country = "ID", currency = "IDR"}
-cimb_va = {country = "ID", currency = "IDR"}
-danamon_va = {country = "ID", currency = "IDR"}
-mandiri_va = {country = "ID", currency = "IDR"}
-alfamart = {country = "ID", currency = "IDR"}
-indomaret = {country = "ID", currency = "IDR"}
-open_banking_uk = {country = "GB", currency = "GBP"}
-oxxo = {country = "MX", currency = "MXN"}
-pay_safe_card = {country = "AT,AU,BE,BR,BE,CA,HR,CY,CZ,DK,FI,FR,GE,DE,GI,HU,IS,IE,KW,LV,IE,LI,LT,LU,MT,MX,MD,ME,NL,NZ,NO,PY,PE,PL,PT,RO,SA,RS,SK,SI,ES,SE,CH,TR,UAE,UK,US,UY", currency = "EUR,AUD,BRL,CAD,CZK,DKK,GEL,GIP,HUF,ISK,KWD,CHF,MXN,MDL,NZD,NOK,PYG,PEN,PLN,RON,SAR,RSD,SEK,TRY,AED,GBP,USD,UYU"}
-seven_eleven = {country = "JP", currency = "JPY"}
-lawson = {country = "JP", currency = "JPY"}
-mini_stop = {country = "JP", currency = "JPY"}
-family_mart = {country = "JP", currency = "JPY"}
-seicomart = {country = "JP", currency = "JPY"}
-pay_easy = {country = "JP", currency = "JPY"}
+online_banking_fpx = { country = "MY", currency = "MYR" }
+online_banking_thailand = { country = "TH", currency = "THB" }
+touch_n_go = { country = "MY", currency = "MYR" }
+atome = { country = "MY,SG", currency = "MYR,SGD" }
+swish = { country = "SE", currency = "SEK" }
+permata_bank_transfer = { country = "ID", currency = "IDR" }
+bca_bank_transfer = { country = "ID", currency = "IDR" }
+bni_va = { country = "ID", currency = "IDR" }
+bri_va = { country = "ID", currency = "IDR" }
+cimb_va = { country = "ID", currency = "IDR" }
+danamon_va = { country = "ID", currency = "IDR" }
+mandiri_va = { country = "ID", currency = "IDR" }
+alfamart = { country = "ID", currency = "IDR" }
+indomaret = { country = "ID", currency = "IDR" }
+open_banking_uk = { country = "GB", currency = "GBP" }
+oxxo = { country = "MX", currency = "MXN" }
+pay_safe_card = { country = "AT,AU,BE,BR,BE,CA,HR,CY,CZ,DK,FI,FR,GE,DE,GI,HU,IS,IE,KW,LV,IE,LI,LT,LU,MT,MX,MD,ME,NL,NZ,NO,PY,PE,PL,PT,RO,SA,RS,SK,SI,ES,SE,CH,TR,UAE,UK,US,UY", currency = "EUR,AUD,BRL,CAD,CZK,DKK,GEL,GIP,HUF,ISK,KWD,CHF,MXN,MDL,NZD,NOK,PYG,PEN,PLN,RON,SAR,RSD,SEK,TRY,AED,GBP,USD,UYU" }
+seven_eleven = { country = "JP", currency = "JPY" }
+lawson = { country = "JP", currency = "JPY" }
+mini_stop = { country = "JP", currency = "JPY" }
+family_mart = { country = "JP", currency = "JPY" }
+seicomart = { country = "JP", currency = "JPY" }
+pay_easy = { country = "JP", currency = "JPY" }
[pm_filters.zen]
credit = { not_available_flows = { capture_method = "manual" } }
@@ -415,7 +418,7 @@ debit = { currency = "USD" }
ach = { currency = "USD" }
[pm_filters.stripe]
-cashapp = {country = "US", currency = "USD"}
+cashapp = { country = "US", currency = "USD" }
[pm_filters.prophetpay]
card_redirect = { currency = "USD" }
@@ -434,10 +437,10 @@ adyen.banks = "bangkok_bank,krungsri_bank,krung_thai_bank,the_siam_commercial_ba
supported_connectors = "braintree"
[applepay_decrypt_keys]
-apple_pay_ppc = "APPLE_PAY_PAYMENT_PROCESSING_CERTIFICATE" #Payment Processing Certificate provided by Apple Pay (https://developer.apple.com/) Certificates, Identifiers & Profiles > Apple Pay Payment Processing Certificate
-apple_pay_ppc_key = "APPLE_PAY_PAYMENT_PROCESSING_CERTIFICATE_KEY" #Private key generate by Elliptic-curve prime256v1 curve
-apple_pay_merchant_cert = "APPLE_PAY_MERCHNAT_CERTIFICATE" #Merchant Certificate provided by Apple Pay (https://developer.apple.com/) Certificates, Identifiers & Profiles > Apple Pay Merchant Identity Certificate
-apple_pay_merchant_cert_key = "APPLE_PAY_MERCHNAT_CERTIFICATE_KEY" #Private key generate by RSA:2048 algorithm
+apple_pay_ppc = "APPLE_PAY_PAYMENT_PROCESSING_CERTIFICATE" #Payment Processing Certificate provided by Apple Pay (https://developer.apple.com/) Certificates, Identifiers & Profiles > Apple Pay Payment Processing Certificate
+apple_pay_ppc_key = "APPLE_PAY_PAYMENT_PROCESSING_CERTIFICATE_KEY" #Private key generate by Elliptic-curve prime256v1 curve
+apple_pay_merchant_cert = "APPLE_PAY_MERCHNAT_CERTIFICATE" #Merchant Certificate provided by Apple Pay (https://developer.apple.com/) Certificates, Identifiers & Profiles > Apple Pay Merchant Identity Certificate
+apple_pay_merchant_cert_key = "APPLE_PAY_MERCHNAT_CERTIFICATE_KEY" #Private key generate by RSA:2048 algorithm
[payment_link]
sdk_url = "http://localhost:9090/dist/HyperLoader.js"
diff --git a/connector-template/mod.rs b/connector-template/mod.rs
index 7f21962109de..e441b0e5879a 100644
--- a/connector-template/mod.rs
+++ b/connector-template/mod.rs
@@ -485,7 +485,7 @@ impl api::IncomingWebhook for {{project-name | downcase | pascal_case}} {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs
index 979214a071a9..6b9928734cef 100644
--- a/crates/api_models/src/admin.rs
+++ b/crates/api_models/src/admin.rs
@@ -455,6 +455,11 @@ pub struct PrimaryBusinessDetails {
#[derive(Clone, Debug, Deserialize, ToSchema, Serialize, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct PaymentLinkConfig {
+ #[schema(
+ max_length = 255,
+ max_length = 255,
+ example = "https://i.imgur.com/RfxPFQo.png"
+ )]
pub merchant_logo: Option,
pub color_scheme: Option,
}
diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs
index d924fb2e4f62..b479f4442ba6 100644
--- a/crates/api_models/src/payments.rs
+++ b/crates/api_models/src/payments.rs
@@ -3150,6 +3150,8 @@ pub struct PaymentLinkObject {
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
pub link_expiry: Option,
pub merchant_custom_domain_name: Option,
+ #[schema(value_type = PaymentLinkConfig)]
+ pub payment_link_config: Option,
/// Custom merchant name for payment link
pub custom_merchant_name: Option,
}
diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs
index 48b0664c16d3..8b1437fa8926 100644
--- a/crates/common_enums/src/enums.rs
+++ b/crates/common_enums/src/enums.rs
@@ -50,6 +50,7 @@ pub enum AttemptStatus {
VoidFailed,
AutoRefunded,
PartialCharged,
+ PartialChargedAndChargeable,
Unresolved,
#[default]
Pending,
@@ -68,7 +69,8 @@ impl AttemptStatus {
| Self::Voided
| Self::VoidFailed
| Self::CaptureFailed
- | Self::Failure => true,
+ | Self::Failure
+ | Self::PartialCharged => true,
Self::Started
| Self::AuthenticationFailed
| Self::AuthenticationPending
@@ -79,7 +81,7 @@ impl AttemptStatus {
| Self::CodInitiated
| Self::VoidInitiated
| Self::CaptureInitiated
- | Self::PartialCharged
+ | Self::PartialChargedAndChargeable
| Self::Unresolved
| Self::Pending
| Self::PaymentMethodAwaited
@@ -861,6 +863,7 @@ pub enum IntentStatus {
RequiresConfirmation,
RequiresCapture,
PartiallyCaptured,
+ PartiallyCapturedAndCapturable,
}
#[derive(
diff --git a/crates/common_utils/src/ext_traits.rs b/crates/common_utils/src/ext_traits.rs
index e76fe7dff5fb..d3296f989533 100644
--- a/crates/common_utils/src/ext_traits.rs
+++ b/crates/common_utils/src/ext_traits.rs
@@ -223,6 +223,7 @@ pub trait ByteSliceExt {
}
impl ByteSliceExt for [u8] {
+ #[track_caller]
fn parse_struct<'de, T>(
&'de self,
type_name: &'static str,
diff --git a/crates/diesel_models/src/payment_link.rs b/crates/diesel_models/src/payment_link.rs
index 50cc5e89cee9..264cc915b35a 100644
--- a/crates/diesel_models/src/payment_link.rs
+++ b/crates/diesel_models/src/payment_link.rs
@@ -4,7 +4,7 @@ use time::PrimitiveDateTime;
use crate::{enums as storage_enums, schema::payment_link};
-#[derive(Clone, Debug, Eq, PartialEq, Identifiable, Queryable, Serialize, Deserialize)]
+#[derive(Clone, Debug, Identifiable, Queryable, Serialize, Deserialize)]
#[diesel(table_name = payment_link)]
#[diesel(primary_key(payment_link_id))]
pub struct PaymentLink {
@@ -21,7 +21,9 @@ pub struct PaymentLink {
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
pub fulfilment_time: Option,
pub custom_merchant_name: Option,
+ pub payment_link_config: Option,
}
+
#[derive(
Clone,
Debug,
@@ -48,4 +50,5 @@ pub struct PaymentLinkNew {
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
pub fulfilment_time: Option,
pub custom_merchant_name: Option,
+ pub payment_link_config: Option,
}
diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs
index 72d5217038c1..e9db5714bed8 100644
--- a/crates/diesel_models/src/schema.rs
+++ b/crates/diesel_models/src/schema.rs
@@ -668,6 +668,7 @@ diesel::table! {
fulfilment_time -> Nullable,
#[max_length = 64]
custom_merchant_name -> Nullable,
+ payment_link_config -> Nullable,
}
}
diff --git a/crates/masking/Cargo.toml b/crates/masking/Cargo.toml
index 21d791642895..bf92e867dc6c 100644
--- a/crates/masking/Cargo.toml
+++ b/crates/masking/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
[features]
default = ["alloc", "serde", "diesel"]
alloc = ["zeroize/alloc"]
+serde = ["dep:serde", "dep:serde_json"]
[package.metadata.docs.rs]
all-features = true
@@ -19,7 +20,7 @@ rustdoc-args = ["--cfg", "docsrs"]
bytes = { version = "1", optional = true }
diesel = { version = "2.1.0", features = ["postgres", "serde_json", "time"], optional = true }
serde = { version = "1", features = ["derive"], optional = true }
-serde_json = "1.0.96"
+serde_json = { version = "1.0.96", optional = true }
subtle = "=2.4.1"
zeroize = { version = "1.6", default-features = false }
diff --git a/crates/masking/src/lib.rs b/crates/masking/src/lib.rs
index d092a1b5a8b6..cb836e188428 100644
--- a/crates/masking/src/lib.rs
+++ b/crates/masking/src/lib.rs
@@ -42,7 +42,9 @@ mod vec;
#[cfg(feature = "serde")]
mod serde;
#[cfg(feature = "serde")]
-pub use crate::serde::{masked_serialize, Deserialize, SerializableSecret, Serialize};
+pub use crate::serde::{
+ masked_serialize, Deserialize, ErasedMaskSerialize, SerializableSecret, Serialize,
+};
/// This module should be included with asterisk.
///
diff --git a/crates/masking/src/serde.rs b/crates/masking/src/serde.rs
index e57ed0301c2f..d1845ee29033 100644
--- a/crates/masking/src/serde.rs
+++ b/crates/masking/src/serde.rs
@@ -91,6 +91,31 @@ pub fn masked_serialize(value: &T) -> Result because of Rust's "object safety" rules.
+/// In particular, the trait contains generic methods which cannot be made into a trait object.
+/// In this case we remove the generic for assuming the serialization to be of 2 types only raw json or masked json
+pub trait ErasedMaskSerialize {
+ /// Masked serialization.
+ fn masked_serialize(&self) -> Result;
+ /// Normal serialization.
+ fn raw_serialize(&self) -> Result;
+}
+
+impl ErasedMaskSerialize for T {
+ fn masked_serialize(&self) -> Result {
+ masked_serialize(self)
+ }
+
+ fn raw_serialize(&self) -> Result {
+ serde_json::to_value(self)
+ }
+}
+
use pii_serializer::PIISerializer;
mod pii_serializer {
diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml
index 01595dc18cd5..25feb373b734 100644
--- a/crates/router/Cargo.toml
+++ b/crates/router/Cargo.toml
@@ -115,6 +115,7 @@ router_derive = { version = "0.1.0", path = "../router_derive" }
router_env = { version = "0.1.0", path = "../router_env", features = ["log_extra_implicit_fields", "log_custom_entries_to_extra"] }
scheduler = { version = "0.1.0", path = "../scheduler", default-features = false }
storage_impl = { version = "0.1.0", path = "../storage_impl", default-features = false }
+erased-serde = "0.3.31"
[build-dependencies]
router_env = { version = "0.1.0", path = "../router_env", default-features = false }
diff --git a/crates/router/src/compatibility/stripe/payment_intents/types.rs b/crates/router/src/compatibility/stripe/payment_intents/types.rs
index c713011b80c8..3c7d5f2918f1 100644
--- a/crates/router/src/compatibility/stripe/payment_intents/types.rs
+++ b/crates/router/src/compatibility/stripe/payment_intents/types.rs
@@ -405,7 +405,9 @@ pub enum StripePaymentStatus {
impl From for StripePaymentStatus {
fn from(item: api_enums::IntentStatus) -> Self {
match item {
- api_enums::IntentStatus::Succeeded => Self::Succeeded,
+ api_enums::IntentStatus::Succeeded | api_enums::IntentStatus::PartiallyCaptured => {
+ Self::Succeeded
+ }
api_enums::IntentStatus::Failed => Self::Canceled,
api_enums::IntentStatus::Processing => Self::Processing,
api_enums::IntentStatus::RequiresCustomerAction
@@ -413,7 +415,7 @@ impl From for StripePaymentStatus {
api_enums::IntentStatus::RequiresPaymentMethod => Self::RequiresPaymentMethod,
api_enums::IntentStatus::RequiresConfirmation => Self::RequiresConfirmation,
api_enums::IntentStatus::RequiresCapture
- | api_enums::IntentStatus::PartiallyCaptured => Self::RequiresCapture,
+ | api_enums::IntentStatus::PartiallyCapturedAndCapturable => Self::RequiresCapture,
api_enums::IntentStatus::Cancelled => Self::Canceled,
}
}
diff --git a/crates/router/src/compatibility/stripe/setup_intents/types.rs b/crates/router/src/compatibility/stripe/setup_intents/types.rs
index dde378e55925..9d3f74af8cb8 100644
--- a/crates/router/src/compatibility/stripe/setup_intents/types.rs
+++ b/crates/router/src/compatibility/stripe/setup_intents/types.rs
@@ -313,7 +313,9 @@ pub enum StripeSetupStatus {
impl From for StripeSetupStatus {
fn from(item: api_enums::IntentStatus) -> Self {
match item {
- api_enums::IntentStatus::Succeeded => Self::Succeeded,
+ api_enums::IntentStatus::Succeeded | api_enums::IntentStatus::PartiallyCaptured => {
+ Self::Succeeded
+ }
api_enums::IntentStatus::Failed => Self::Canceled,
api_enums::IntentStatus::Processing => Self::Processing,
api_enums::IntentStatus::RequiresCustomerAction => Self::RequiresAction,
@@ -321,7 +323,7 @@ impl From for StripeSetupStatus {
api_enums::IntentStatus::RequiresPaymentMethod => Self::RequiresPaymentMethod,
api_enums::IntentStatus::RequiresConfirmation => Self::RequiresConfirmation,
api_enums::IntentStatus::RequiresCapture
- | api_enums::IntentStatus::PartiallyCaptured => {
+ | api_enums::IntentStatus::PartiallyCapturedAndCapturable => {
logger::error!("Invalid status change");
Self::Canceled
}
diff --git a/crates/router/src/connector/aci.rs b/crates/router/src/connector/aci.rs
index f6389c802f9e..f51c91f441df 100644
--- a/crates/router/src/connector/aci.rs
+++ b/crates/router/src/connector/aci.rs
@@ -572,7 +572,7 @@ impl api::IncomingWebhook for Aci {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/adyen.rs b/crates/router/src/connector/adyen.rs
index ef10fbb692fd..676f15d2f564 100644
--- a/crates/router/src/connector/adyen.rs
+++ b/crates/router/src/connector/adyen.rs
@@ -1600,17 +1600,13 @@ impl api::IncomingWebhook for Adyen {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let notif = get_webhook_object_from_body(request.body)
.change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
let response: adyen::Response = notif.into();
- let res_json = serde_json::to_value(response)
- .into_report()
- .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
-
- Ok(res_json)
+ Ok(Box::new(response))
}
fn get_webhook_api_response(
diff --git a/crates/router/src/connector/airwallex.rs b/crates/router/src/connector/airwallex.rs
index 5de7fc065e80..33e3dae72871 100644
--- a/crates/router/src/connector/airwallex.rs
+++ b/crates/router/src/connector/airwallex.rs
@@ -1081,13 +1081,13 @@ impl api::IncomingWebhook for Airwallex {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let details: airwallex::AirwallexWebhookObjectResource = request
.body
.parse_struct("AirwallexWebhookObjectResource")
.change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
- Ok(details.data.object)
+ Ok(Box::new(details.data.object))
}
fn get_dispute_details(
diff --git a/crates/router/src/connector/airwallex/transformers.rs b/crates/router/src/connector/airwallex/transformers.rs
index 031a8276bb0d..457b8d075487 100644
--- a/crates/router/src/connector/airwallex/transformers.rs
+++ b/crates/router/src/connector/airwallex/transformers.rs
@@ -824,7 +824,8 @@ pub enum AirwallexDisputeStage {
#[derive(Debug, Deserialize)]
pub struct AirwallexWebhookDataResource {
- pub object: serde_json::Value,
+ // Should this be a secret by default since it represents webhook payload
+ pub object: Secret,
}
#[derive(Debug, Deserialize)]
diff --git a/crates/router/src/connector/authorizedotnet.rs b/crates/router/src/connector/authorizedotnet.rs
index 7c3c234daecf..f3cdf0415b91 100644
--- a/crates/router/src/connector/authorizedotnet.rs
+++ b/crates/router/src/connector/authorizedotnet.rs
@@ -875,17 +875,15 @@ impl api::IncomingWebhook for Authorizedotnet {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let payload: authorizedotnet::AuthorizedotnetWebhookObjectId = request
.body
.parse_struct("AuthorizedotnetWebhookObjectId")
.change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
- let sync_payload = serde_json::to_value(
+
+ Ok(Box::new(
authorizedotnet::AuthorizedotnetSyncResponse::try_from(payload)?,
- )
- .into_report()
- .change_context(errors::ConnectorError::ResponseHandlingFailed)?;
- Ok(sync_payload)
+ ))
}
}
diff --git a/crates/router/src/connector/bambora.rs b/crates/router/src/connector/bambora.rs
index 802be26408df..ff6fdcb46769 100644
--- a/crates/router/src/connector/bambora.rs
+++ b/crates/router/src/connector/bambora.rs
@@ -685,7 +685,7 @@ impl api::IncomingWebhook for Bambora {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/bankofamerica.rs b/crates/router/src/connector/bankofamerica.rs
index 51a1d722dc51..b6e19fa0d296 100644
--- a/crates/router/src/connector/bankofamerica.rs
+++ b/crates/router/src/connector/bankofamerica.rs
@@ -812,7 +812,7 @@ impl api::IncomingWebhook for Bankofamerica {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/bankofamerica/transformers.rs b/crates/router/src/connector/bankofamerica/transformers.rs
index 20b2af48b168..a6fa8652b27d 100644
--- a/crates/router/src/connector/bankofamerica/transformers.rs
+++ b/crates/router/src/connector/bankofamerica/transformers.rs
@@ -273,7 +273,8 @@ pub enum BankofamericaPaymentStatus {
impl ForeignFrom<(BankofamericaPaymentStatus, bool)> for enums::AttemptStatus {
fn foreign_from((status, auto_capture): (BankofamericaPaymentStatus, bool)) -> Self {
match status {
- BankofamericaPaymentStatus::Authorized => {
+ BankofamericaPaymentStatus::Authorized
+ | BankofamericaPaymentStatus::AuthorizedPendingReview => {
if auto_capture {
// Because BankOfAmerica will return Payment Status as Authorized even in AutoCapture Payment
Self::Pending
@@ -281,7 +282,6 @@ impl ForeignFrom<(BankofamericaPaymentStatus, bool)> for enums::AttemptStatus {
Self::Authorized
}
}
- BankofamericaPaymentStatus::AuthorizedPendingReview => Self::Authorized,
BankofamericaPaymentStatus::Succeeded | BankofamericaPaymentStatus::Transmitted => {
Self::Charged
}
@@ -321,7 +321,7 @@ pub struct BankOfAmericaErrorInformationResponse {
#[derive(Debug, Deserialize)]
pub struct BankOfAmericaErrorInformation {
reason: Option,
- message: String,
+ message: Option,
}
impl
@@ -369,7 +369,10 @@ impl
BankOfAmericaPaymentsResponse::ErrorInformation(error_response) => Ok(Self {
response: Err(types::ErrorResponse {
code: consts::NO_ERROR_CODE.to_string(),
- message: error_response.error_information.message,
+ message: error_response
+ .error_information
+ .message
+ .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
reason: error_response.error_information.reason,
status_code: item.http_code,
attempt_status: None,
@@ -422,7 +425,10 @@ impl
BankOfAmericaPaymentsResponse::ErrorInformation(error_response) => Ok(Self {
response: Err(types::ErrorResponse {
code: consts::NO_ERROR_CODE.to_string(),
- message: error_response.error_information.message,
+ message: error_response
+ .error_information
+ .message
+ .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
reason: error_response.error_information.reason,
status_code: item.http_code,
attempt_status: None,
@@ -475,7 +481,10 @@ impl
BankOfAmericaPaymentsResponse::ErrorInformation(error_response) => Ok(Self {
response: Err(types::ErrorResponse {
code: consts::NO_ERROR_CODE.to_string(),
- message: error_response.error_information.message,
+ message: error_response
+ .error_information
+ .message
+ .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
reason: error_response.error_information.reason,
status_code: item.http_code,
attempt_status: None,
diff --git a/crates/router/src/connector/bitpay.rs b/crates/router/src/connector/bitpay.rs
index dc4571b75746..856d0a9ec9d7 100644
--- a/crates/router/src/connector/bitpay.rs
+++ b/crates/router/src/connector/bitpay.rs
@@ -23,7 +23,7 @@ use crate::{
api::{self, ConnectorCommon, ConnectorCommonExt},
ErrorResponse, Response,
},
- utils::{self, BytesExt, Encode},
+ utils::{self, BytesExt},
};
#[derive(Debug, Clone)]
@@ -393,12 +393,11 @@ impl api::IncomingWebhook for Bitpay {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let notif: BitpayWebhookDetails = request
.body
.parse_struct("BitpayWebhookDetails")
.change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
- Encode::::encode_to_value(¬if)
- .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)
+ Ok(Box::new(notif))
}
}
diff --git a/crates/router/src/connector/bluesnap.rs b/crates/router/src/connector/bluesnap.rs
index 7bd2ce052538..d1aa1fa25ee6 100644
--- a/crates/router/src/connector/bluesnap.rs
+++ b/crates/router/src/connector/bluesnap.rs
@@ -1119,15 +1119,13 @@ impl api::IncomingWebhook for Bluesnap {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let resource: bluesnap::BluesnapWebhookObjectResource =
serde_urlencoded::from_bytes(request.body)
.into_report()
.change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
- let res_json = serde_json::Value::try_from(resource)?;
-
- Ok(res_json)
+ Ok(Box::new(resource))
}
}
diff --git a/crates/router/src/connector/boku.rs b/crates/router/src/connector/boku.rs
index 7c2c1af0986b..87e8fd0eb96a 100644
--- a/crates/router/src/connector/boku.rs
+++ b/crates/router/src/connector/boku.rs
@@ -627,7 +627,7 @@ impl api::IncomingWebhook for Boku {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/braintree.rs b/crates/router/src/connector/braintree.rs
index 6f5b13890367..99f6b9955d57 100644
--- a/crates/router/src/connector/braintree.rs
+++ b/crates/router/src/connector/braintree.rs
@@ -1418,17 +1418,13 @@ impl api::IncomingWebhook for Braintree {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let notif = get_webhook_object_from_body(request.body)
.change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
let response = decode_webhook_payload(notif.bt_payload.replace('\n', "").as_bytes())?;
- let res_json = serde_json::to_value(response)
- .into_report()
- .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
-
- Ok(res_json)
+ Ok(Box::new(response))
}
fn get_webhook_api_response(
diff --git a/crates/router/src/connector/cashtocode.rs b/crates/router/src/connector/cashtocode.rs
index 12a52e485396..a8d7d6d80504 100644
--- a/crates/router/src/connector/cashtocode.rs
+++ b/crates/router/src/connector/cashtocode.rs
@@ -391,16 +391,13 @@ impl api::IncomingWebhook for Cashtocode {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let webhook: transformers::CashtocodeIncomingWebhook = request
.body
.parse_struct("CashtocodeIncomingWebhook")
.change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
- let res_json =
- utils::Encode::::encode_to_value(&webhook)
- .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
- Ok(res_json)
+ Ok(Box::new(webhook))
}
fn get_webhook_api_response(
diff --git a/crates/router/src/connector/checkout.rs b/crates/router/src/connector/checkout.rs
index f24c08233ed7..ca2556544f90 100644
--- a/crates/router/src/connector/checkout.rs
+++ b/crates/router/src/connector/checkout.rs
@@ -1261,7 +1261,7 @@ impl api::IncomingWebhook for Checkout {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let event_type_data: checkout::CheckoutWebhookEventTypeBody = request
.body
.parse_struct("CheckoutWebhookBody")
@@ -1281,7 +1281,10 @@ impl api::IncomingWebhook for Checkout {
utils::Encode::::encode_to_value(&payment_response)
.change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?
};
- Ok(resource_object)
+ // Ideally this should be a strict type that has type information
+ // PII information is likely being logged here when this response will be logged.
+
+ Ok(Box::new(resource_object))
}
fn get_dispute_details(
diff --git a/crates/router/src/connector/coinbase.rs b/crates/router/src/connector/coinbase.rs
index 5704ea15b005..9c0a06a52c90 100644
--- a/crates/router/src/connector/coinbase.rs
+++ b/crates/router/src/connector/coinbase.rs
@@ -426,12 +426,12 @@ impl api::IncomingWebhook for Coinbase {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let notif: CoinbaseWebhookDetails = request
.body
.parse_struct("CoinbaseWebhookDetails")
.change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
- Encode::::encode_to_value(¬if.event)
- .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)
+
+ Ok(Box::new(notif.event))
}
}
diff --git a/crates/router/src/connector/cryptopay.rs b/crates/router/src/connector/cryptopay.rs
index d2d8fa0f1ec2..417a36145b92 100644
--- a/crates/router/src/connector/cryptopay.rs
+++ b/crates/router/src/connector/cryptopay.rs
@@ -455,13 +455,13 @@ impl api::IncomingWebhook for Cryptopay {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let notif: CryptopayWebhookDetails =
request
.body
.parse_struct("CryptopayWebhookDetails")
.change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
- Encode::::encode_to_value(¬if)
- .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)
+
+ Ok(Box::new(notif))
}
}
diff --git a/crates/router/src/connector/cybersource.rs b/crates/router/src/connector/cybersource.rs
index ee6e93aebbd0..f69701f73958 100644
--- a/crates/router/src/connector/cybersource.rs
+++ b/crates/router/src/connector/cybersource.rs
@@ -805,7 +805,7 @@ impl api::IncomingWebhook for Cybersource {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/dlocal.rs b/crates/router/src/connector/dlocal.rs
index 64d3e6f1c12f..4ae3a292fdae 100644
--- a/crates/router/src/connector/dlocal.rs
+++ b/crates/router/src/connector/dlocal.rs
@@ -674,7 +674,7 @@ impl api::IncomingWebhook for Dlocal {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/dummyconnector.rs b/crates/router/src/connector/dummyconnector.rs
index b501936b8713..9edcd957ff09 100644
--- a/crates/router/src/connector/dummyconnector.rs
+++ b/crates/router/src/connector/dummyconnector.rs
@@ -579,7 +579,7 @@ impl api::IncomingWebhook for DummyConnector {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/fiserv.rs b/crates/router/src/connector/fiserv.rs
index 093f71b3da14..2bdb7177d941 100644
--- a/crates/router/src/connector/fiserv.rs
+++ b/crates/router/src/connector/fiserv.rs
@@ -787,7 +787,7 @@ impl api::IncomingWebhook for Fiserv {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/forte.rs b/crates/router/src/connector/forte.rs
index 40448c01fabf..3aa7cee32878 100644
--- a/crates/router/src/connector/forte.rs
+++ b/crates/router/src/connector/forte.rs
@@ -669,7 +669,7 @@ impl api::IncomingWebhook for Forte {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/globalpay.rs b/crates/router/src/connector/globalpay.rs
index cfa1349633b2..26494d349b88 100644
--- a/crates/router/src/connector/globalpay.rs
+++ b/crates/router/src/connector/globalpay.rs
@@ -932,14 +932,15 @@ impl api::IncomingWebhook for Globalpay {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let details = std::str::from_utf8(request.body)
.into_report()
.change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
- let res_json = serde_json::from_str(details)
- .into_report()
- .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
- Ok(res_json)
+ Ok(Box::new(
+ serde_json::from_str(details)
+ .into_report()
+ .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?,
+ ))
}
}
diff --git a/crates/router/src/connector/globepay.rs b/crates/router/src/connector/globepay.rs
index 547bf66fb7d5..9ebea6087f42 100644
--- a/crates/router/src/connector/globepay.rs
+++ b/crates/router/src/connector/globepay.rs
@@ -508,7 +508,7 @@ impl api::IncomingWebhook for Globepay {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/gocardless.rs b/crates/router/src/connector/gocardless.rs
index 1a6ac8441652..d25357121b66 100644
--- a/crates/router/src/connector/gocardless.rs
+++ b/crates/router/src/connector/gocardless.rs
@@ -843,7 +843,7 @@ impl api::IncomingWebhook for Gocardless {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let details: gocardless::GocardlessWebhookEvent = request
.body
.parse_struct("GocardlessWebhookEvent")
@@ -851,19 +851,14 @@ impl api::IncomingWebhook for Gocardless {
let first_event = details
.events
.first()
- .ok_or_else(|| errors::ConnectorError::WebhookReferenceIdNotFound)?;
+ .ok_or_else(|| errors::ConnectorError::WebhookReferenceIdNotFound)?
+ .clone();
match first_event.resource_type {
- transformers::WebhookResourceType::Payments => serde_json::to_value(
- gocardless::GocardlessPaymentsResponse::try_from(first_event)?,
- )
- .into_report()
- .change_context(errors::ConnectorError::WebhookBodyDecodingFailed),
- transformers::WebhookResourceType::Refunds => serde_json::to_value(first_event)
- .into_report()
- .change_context(errors::ConnectorError::WebhookBodyDecodingFailed),
- transformers::WebhookResourceType::Mandates => serde_json::to_value(first_event)
- .into_report()
- .change_context(errors::ConnectorError::WebhookBodyDecodingFailed),
+ transformers::WebhookResourceType::Payments => Ok(Box::new(
+ gocardless::GocardlessPaymentsResponse::try_from(&first_event)?,
+ )),
+ transformers::WebhookResourceType::Refunds
+ | transformers::WebhookResourceType::Mandates => Ok(Box::new(first_event)),
}
}
}
diff --git a/crates/router/src/connector/gocardless/transformers.rs b/crates/router/src/connector/gocardless/transformers.rs
index d3b2d244760f..72204b511518 100644
--- a/crates/router/src/connector/gocardless/transformers.rs
+++ b/crates/router/src/connector/gocardless/transformers.rs
@@ -862,14 +862,14 @@ pub struct GocardlessWebhookEvent {
pub events: Vec,
}
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct WebhookEvent {
pub resource_type: WebhookResourceType,
pub action: WebhookAction,
pub links: WebhooksLink,
}
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum WebhookResourceType {
Payments,
@@ -877,7 +877,7 @@ pub enum WebhookResourceType {
Mandates,
}
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum WebhookAction {
PaymentsAction(PaymentsAction),
@@ -885,7 +885,7 @@ pub enum WebhookAction {
MandatesAction(MandatesAction),
}
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PaymentsAction {
Created,
@@ -901,7 +901,7 @@ pub enum PaymentsAction {
ResubmissionRequired,
}
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RefundsAction {
Created,
@@ -912,7 +912,7 @@ pub enum RefundsAction {
FundsReturned,
}
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum MandatesAction {
Created,
@@ -931,7 +931,7 @@ pub enum MandatesAction {
Blocked,
}
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum WebhooksLink {
PaymentWebhooksLink(PaymentWebhooksLink),
@@ -939,17 +939,17 @@ pub enum WebhooksLink {
MandateWebhookLink(MandateWebhookLink),
}
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RefundWebhookLink {
pub refund: String,
}
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PaymentWebhooksLink {
pub payment: String,
}
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct MandateWebhookLink {
pub mandate: String,
}
diff --git a/crates/router/src/connector/helcim.rs b/crates/router/src/connector/helcim.rs
index f7089bbd41b5..a1781a92ddf5 100644
--- a/crates/router/src/connector/helcim.rs
+++ b/crates/router/src/connector/helcim.rs
@@ -771,7 +771,7 @@ impl api::IncomingWebhook for Helcim {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/iatapay.rs b/crates/router/src/connector/iatapay.rs
index 008047c1d366..ba4b95f43808 100644
--- a/crates/router/src/connector/iatapay.rs
+++ b/crates/router/src/connector/iatapay.rs
@@ -691,13 +691,13 @@ impl api::IncomingWebhook for Iatapay {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let notif: IatapayPaymentsResponse =
request
.body
.parse_struct("IatapayPaymentsResponse")
.change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
- Encode::::encode_to_value(¬if)
- .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)
+
+ Ok(Box::new(notif))
}
}
diff --git a/crates/router/src/connector/klarna.rs b/crates/router/src/connector/klarna.rs
index 3670f65a2f02..f34414e737ff 100644
--- a/crates/router/src/connector/klarna.rs
+++ b/crates/router/src/connector/klarna.rs
@@ -520,7 +520,7 @@ impl api::IncomingWebhook for Klarna {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/mollie.rs b/crates/router/src/connector/mollie.rs
index ef3eb6a3e7b3..76deb0b2be88 100644
--- a/crates/router/src/connector/mollie.rs
+++ b/crates/router/src/connector/mollie.rs
@@ -582,7 +582,7 @@ impl api::IncomingWebhook for Mollie {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/multisafepay.rs b/crates/router/src/connector/multisafepay.rs
index 9dc54e7b72e3..1f1099af0e71 100644
--- a/crates/router/src/connector/multisafepay.rs
+++ b/crates/router/src/connector/multisafepay.rs
@@ -523,7 +523,7 @@ impl api::IncomingWebhook for Multisafepay {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/nexinets.rs b/crates/router/src/connector/nexinets.rs
index f2e57792f284..a67a29d74ffe 100644
--- a/crates/router/src/connector/nexinets.rs
+++ b/crates/router/src/connector/nexinets.rs
@@ -682,7 +682,7 @@ impl api::IncomingWebhook for Nexinets {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/nmi.rs b/crates/router/src/connector/nmi.rs
index d7e9cd78bb88..eaede225d38f 100644
--- a/crates/router/src/connector/nmi.rs
+++ b/crates/router/src/connector/nmi.rs
@@ -667,7 +667,7 @@ impl api::IncomingWebhook for Nmi {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/noon.rs b/crates/router/src/connector/noon.rs
index 0ea73efd94bd..b6ed231e5b50 100644
--- a/crates/router/src/connector/noon.rs
+++ b/crates/router/src/connector/noon.rs
@@ -744,16 +744,12 @@ impl api::IncomingWebhook for Noon {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let resource: noon::NoonWebhookObject = request
.body
.parse_struct("NoonWebhookObject")
.change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
- let res_json = serde_json::to_value(noon::NoonPaymentsResponse::from(resource))
- .into_report()
- .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
-
- Ok(res_json)
+ Ok(Box::new(noon::NoonPaymentsResponse::from(resource)))
}
}
diff --git a/crates/router/src/connector/nuvei.rs b/crates/router/src/connector/nuvei.rs
index 15702829d378..7a9f3af37f0c 100644
--- a/crates/router/src/connector/nuvei.rs
+++ b/crates/router/src/connector/nuvei.rs
@@ -25,7 +25,7 @@ use crate::{
storage::enums,
ErrorResponse, Response,
},
- utils::{self as common_utils, ByteSliceExt, Encode},
+ utils::{self as common_utils, ByteSliceExt},
};
#[derive(Debug, Clone)]
@@ -963,12 +963,13 @@ impl api::IncomingWebhook for Nuvei {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let body = serde_urlencoded::from_str::(&request.query_params)
.into_report()
.change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
let payment_response = nuvei::NuveiPaymentsResponse::from(body);
- Encode::::encode_to_value(&payment_response).switch()
+
+ Ok(Box::new(payment_response))
}
}
diff --git a/crates/router/src/connector/opayo.rs b/crates/router/src/connector/opayo.rs
index cc517ca1f3b8..ba0fb2046b7c 100644
--- a/crates/router/src/connector/opayo.rs
+++ b/crates/router/src/connector/opayo.rs
@@ -533,7 +533,7 @@ impl api::IncomingWebhook for Opayo {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/opennode.rs b/crates/router/src/connector/opennode.rs
index 3151403a5534..41d1e6c3d88c 100644
--- a/crates/router/src/connector/opennode.rs
+++ b/crates/router/src/connector/opennode.rs
@@ -420,11 +420,11 @@ impl api::IncomingWebhook for Opennode {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let notif = serde_urlencoded::from_bytes::(request.body)
.into_report()
.change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
- Encode::::encode_to_value(¬if.status)
- .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)
+
+ Ok(Box::new(notif.status))
}
}
diff --git a/crates/router/src/connector/payeezy.rs b/crates/router/src/connector/payeezy.rs
index 8bb8eaa8b4c2..33a8ec65152e 100644
--- a/crates/router/src/connector/payeezy.rs
+++ b/crates/router/src/connector/payeezy.rs
@@ -585,7 +585,7 @@ impl api::IncomingWebhook for Payeezy {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/payme.rs b/crates/router/src/connector/payme.rs
index ef10c6d00878..1e67f8a9f350 100644
--- a/crates/router/src/connector/payme.rs
+++ b/crates/router/src/connector/payme.rs
@@ -1077,32 +1077,24 @@ impl api::IncomingWebhook for Payme {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let resource =
serde_urlencoded::from_bytes::(request.body)
.into_report()
.change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
- let res_json = match resource.notify_type {
+ match resource.notify_type {
transformers::NotifyType::SaleComplete
| transformers::NotifyType::SaleAuthorized
| transformers::NotifyType::SaleFailure => {
- serde_json::to_value(payme::PaymePaySaleResponse::from(resource))
- .into_report()
- .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)
- }
- transformers::NotifyType::Refund => {
- serde_json::to_value(payme::PaymeQueryTransactionResponse::from(resource))
- .into_report()
- .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)
+ Ok(Box::new(payme::PaymePaySaleResponse::from(resource)))
}
+ transformers::NotifyType::Refund => Ok(Box::new(
+ payme::PaymeQueryTransactionResponse::from(resource),
+ )),
transformers::NotifyType::SaleChargeback
- | transformers::NotifyType::SaleChargebackRefund => serde_json::to_value(resource)
- .into_report()
- .change_context(errors::ConnectorError::WebhookBodyDecodingFailed),
- }?;
-
- Ok(res_json)
+ | transformers::NotifyType::SaleChargebackRefund => Ok(Box::new(resource)),
+ }
}
fn get_dispute_details(
diff --git a/crates/router/src/connector/paypal.rs b/crates/router/src/connector/paypal.rs
index d4ab481eb9de..e514ebbed2fc 100644
--- a/crates/router/src/connector/paypal.rs
+++ b/crates/router/src/connector/paypal.rs
@@ -1189,33 +1189,24 @@ impl api::IncomingWebhook for Paypal {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let details: paypal::PaypalWebhooksBody =
request
.body
.parse_struct("PaypalWebhooksBody")
.change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
- let sync_payload = match details.resource {
- paypal::PaypalResource::PaypalCardWebhooks(resource) => serde_json::to_value(
+ Ok(match details.resource {
+ paypal::PaypalResource::PaypalCardWebhooks(resource) => Box::new(
paypal::PaypalPaymentsSyncResponse::try_from((*resource, details.event_type))?,
- )
- .into_report()
- .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?,
- paypal::PaypalResource::PaypalRedirectsWebhooks(resource) => serde_json::to_value(
+ ),
+ paypal::PaypalResource::PaypalRedirectsWebhooks(resource) => Box::new(
paypal::PaypalOrdersResponse::try_from((*resource, details.event_type))?,
- )
- .into_report()
- .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?,
- paypal::PaypalResource::PaypalRefundWebhooks(resource) => serde_json::to_value(
+ ),
+ paypal::PaypalResource::PaypalRefundWebhooks(resource) => Box::new(
paypal::RefundSyncResponse::try_from((*resource, details.event_type))?,
- )
- .into_report()
- .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?,
- paypal::PaypalResource::PaypalDisputeWebhooks(_) => serde_json::to_value(details)
- .into_report()
- .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?,
- };
- Ok(sync_payload)
+ ),
+ paypal::PaypalResource::PaypalDisputeWebhooks(_) => Box::new(details),
+ })
}
fn get_dispute_details(
diff --git a/crates/router/src/connector/payu.rs b/crates/router/src/connector/payu.rs
index 9a8d4734f837..2868b5de0523 100644
--- a/crates/router/src/connector/payu.rs
+++ b/crates/router/src/connector/payu.rs
@@ -758,7 +758,7 @@ impl api::IncomingWebhook for Payu {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/powertranz.rs b/crates/router/src/connector/powertranz.rs
index 04851dd1781a..d24fd27f1052 100644
--- a/crates/router/src/connector/powertranz.rs
+++ b/crates/router/src/connector/powertranz.rs
@@ -610,7 +610,7 @@ impl api::IncomingWebhook for Powertranz {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/prophetpay.rs b/crates/router/src/connector/prophetpay.rs
index 6765fad2653d..e5ebe6331ba2 100644
--- a/crates/router/src/connector/prophetpay.rs
+++ b/crates/router/src/connector/prophetpay.rs
@@ -706,7 +706,7 @@ impl api::IncomingWebhook for Prophetpay {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/rapyd.rs b/crates/router/src/connector/rapyd.rs
index cd8893d0d7b1..91a538f9991b 100644
--- a/crates/router/src/connector/rapyd.rs
+++ b/crates/router/src/connector/rapyd.rs
@@ -900,7 +900,7 @@ impl api::IncomingWebhook for Rapyd {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let webhook: transformers::RapydIncomingWebhook = request
.body
.parse_struct("RapydIncomingWebhook")
@@ -923,7 +923,7 @@ impl api::IncomingWebhook for Rapyd {
.change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?
}
};
- Ok(res_json)
+ Ok(Box::new(res_json))
}
fn get_dispute_details(
diff --git a/crates/router/src/connector/shift4.rs b/crates/router/src/connector/shift4.rs
index 98eb895db548..6f3a2b802014 100644
--- a/crates/router/src/connector/shift4.rs
+++ b/crates/router/src/connector/shift4.rs
@@ -815,11 +815,13 @@ impl api::IncomingWebhook for Shift4 {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let details: shift4::Shift4WebhookObjectResource = request
.body
.parse_struct("Shift4WebhookObjectResource")
.change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
- Ok(details.data)
+ // Ideally this should be a strict type that has type information
+ // PII information is likely being logged here when this response will be logged
+ Ok(Box::new(details.data))
}
}
diff --git a/crates/router/src/connector/square.rs b/crates/router/src/connector/square.rs
index 1d4d7e95dfa3..d836285755d4 100644
--- a/crates/router/src/connector/square.rs
+++ b/crates/router/src/connector/square.rs
@@ -915,24 +915,19 @@ impl api::IncomingWebhook for Square {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let details: square::SquareWebhookBody =
request
.body
.parse_struct("SquareWebhookObject")
.change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
- let reference_object = match details.data.object {
+ Ok(match details.data.object {
square::SquareWebhookObject::Payment(square_payments_response_details) => {
- serde_json::to_value(square_payments_response_details)
- .into_report()
- .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?
+ Box::new(square_payments_response_details)
}
square::SquareWebhookObject::Refund(square_refund_response_details) => {
- serde_json::to_value(square_refund_response_details)
- .into_report()
- .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?
+ Box::new(square_refund_response_details)
}
- };
- Ok(reference_object)
+ })
}
}
diff --git a/crates/router/src/connector/stax.rs b/crates/router/src/connector/stax.rs
index 0cfd2b89cd1a..024211c8caaa 100644
--- a/crates/router/src/connector/stax.rs
+++ b/crates/router/src/connector/stax.rs
@@ -886,10 +886,10 @@ impl api::IncomingWebhook for Stax {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let reference_object: serde_json::Value = serde_json::from_slice(request.body)
.into_report()
.change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
- Ok(reference_object)
+ Ok(Box::new(reference_object))
}
}
diff --git a/crates/router/src/connector/stripe.rs b/crates/router/src/connector/stripe.rs
index 3f1263657e83..ccf843ec78d6 100644
--- a/crates/router/src/connector/stripe.rs
+++ b/crates/router/src/connector/stripe.rs
@@ -2057,13 +2057,13 @@ impl api::IncomingWebhook for Stripe {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let details: stripe::WebhookEventObjectResource = request
.body
.parse_struct("WebhookEventObjectResource")
.change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
- Ok(details.data.object)
+ Ok(Box::new(details.data.object))
}
fn get_dispute_details(
&self,
diff --git a/crates/router/src/connector/trustpay.rs b/crates/router/src/connector/trustpay.rs
index 7509131afeef..65ab5a7ba58d 100644
--- a/crates/router/src/connector/trustpay.rs
+++ b/crates/router/src/connector/trustpay.rs
@@ -906,16 +906,12 @@ impl api::IncomingWebhook for Trustpay {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let details: trustpay::TrustpayWebhookResponse = request
.body
.parse_struct("TrustpayWebhookResponse")
.switch()?;
- let res_json = utils::Encode::::encode_to_value(
- &details.payment_information,
- )
- .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
- Ok(res_json)
+ Ok(Box::new(details.payment_information))
}
fn get_webhook_source_verification_algorithm(
diff --git a/crates/router/src/connector/tsys.rs b/crates/router/src/connector/tsys.rs
index 71cef4be2afd..0143f5855ade 100644
--- a/crates/router/src/connector/tsys.rs
+++ b/crates/router/src/connector/tsys.rs
@@ -625,7 +625,7 @@ impl api::IncomingWebhook for Tsys {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs
index efabbf87aeba..9c19d4eed8f6 100644
--- a/crates/router/src/connector/utils.rs
+++ b/crates/router/src/connector/utils.rs
@@ -19,7 +19,10 @@ use serde::Serializer;
use crate::{
consts,
- core::errors::{self, CustomResult},
+ core::{
+ errors::{self, CustomResult},
+ payments::PaymentData,
+ },
pii::PeekInterface,
types::{self, api, transformers::ForeignTryFrom, PaymentsCancelData, ResponseId},
utils::{OptionExt, ValueExt},
@@ -74,6 +77,49 @@ pub trait RouterData {
#[cfg(feature = "payouts")]
fn get_quote_id(&self) -> Result;
}
+
+pub trait PaymentResponseRouterData {
+ fn get_attempt_status_for_db_update(
+ &self,
+ payment_data: &PaymentData,
+ ) -> enums::AttemptStatus
+ where
+ F: Clone;
+}
+
+impl PaymentResponseRouterData
+ for types::RouterData
+where
+ Request: types::Capturable,
+{
+ fn get_attempt_status_for_db_update(
+ &self,
+ payment_data: &PaymentData,
+ ) -> enums::AttemptStatus
+ where
+ F: Clone,
+ {
+ match self.status {
+ enums::AttemptStatus::Voided => {
+ if payment_data.payment_intent.amount_captured > Some(0) {
+ enums::AttemptStatus::PartialCharged
+ } else {
+ self.status
+ }
+ }
+ enums::AttemptStatus::Charged => {
+ let captured_amount = types::Capturable::get_capture_amount(&self.request);
+ if Some(payment_data.payment_intent.amount) == captured_amount {
+ enums::AttemptStatus::Charged
+ } else {
+ enums::AttemptStatus::PartialCharged
+ }
+ }
+ _ => self.status,
+ }
+ }
+}
+
pub const SELECTED_PAYMENT_METHOD: &str = "Selected payment method";
pub fn get_unimplemented_payment_method_error_message(connector: &str) -> String {
diff --git a/crates/router/src/connector/volt.rs b/crates/router/src/connector/volt.rs
index 3697b8c8923f..43b6b3a3406d 100644
--- a/crates/router/src/connector/volt.rs
+++ b/crates/router/src/connector/volt.rs
@@ -589,7 +589,7 @@ impl api::IncomingWebhook for Volt {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/wise.rs b/crates/router/src/connector/wise.rs
index 5eba54eab4f7..865dcd5fff35 100644
--- a/crates/router/src/connector/wise.rs
+++ b/crates/router/src/connector/wise.rs
@@ -710,7 +710,7 @@ impl api::IncomingWebhook for Wise {
fn get_webhook_resource_object(
&self,
_request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
}
}
diff --git a/crates/router/src/connector/worldline.rs b/crates/router/src/connector/worldline.rs
index 7fcca08d8bfe..3d928624df8f 100644
--- a/crates/router/src/connector/worldline.rs
+++ b/crates/router/src/connector/worldline.rs
@@ -808,14 +808,16 @@ impl api::IncomingWebhook for Worldline {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let details = request
.body
.parse_struct::("WorldlineWebhookObjectId")
.change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?
.payment
.ok_or(errors::ConnectorError::WebhookResourceObjectNotFound)?;
- Ok(details)
+ // Ideally this should be a strict type that has type information
+ // PII information is likely being logged here when this response will be logged
+ Ok(Box::new(details))
}
fn get_webhook_api_response(
diff --git a/crates/router/src/connector/worldpay.rs b/crates/router/src/connector/worldpay.rs
index 60579fb5dd3e..ef01aa9a6ada 100644
--- a/crates/router/src/connector/worldpay.rs
+++ b/crates/router/src/connector/worldpay.rs
@@ -754,15 +754,12 @@ impl api::IncomingWebhook for Worldpay {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let body: WorldpayWebhookEventType = request
.body
.parse_struct("WorldpayWebhookEventType")
.change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
let psync_body = WorldpayEventResponse::try_from(body)?;
- let res_json = serde_json::to_value(psync_body)
- .into_report()
- .change_context(errors::ConnectorError::WebhookResponseEncodingFailed)?;
- Ok(res_json)
+ Ok(Box::new(psync_body))
}
}
diff --git a/crates/router/src/connector/zen.rs b/crates/router/src/connector/zen.rs
index bdbdf623f934..102d54bab427 100644
--- a/crates/router/src/connector/zen.rs
+++ b/crates/router/src/connector/zen.rs
@@ -668,11 +668,11 @@ impl api::IncomingWebhook for Zen {
fn get_webhook_resource_object(
&self,
request: &api::IncomingWebhookRequestDetails<'_>,
- ) -> CustomResult {
+ ) -> CustomResult, errors::ConnectorError> {
let reference_object: serde_json::Value = serde_json::from_slice(request.body)
.into_report()
.change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
- Ok(reference_object)
+ Ok(Box::new(reference_object))
}
fn get_webhook_api_response(
&self,
diff --git a/crates/router/src/core/locker_migration.rs b/crates/router/src/core/locker_migration.rs
index aa82b4a3a636..f036a03a2f0e 100644
--- a/crates/router/src/core/locker_migration.rs
+++ b/crates/router/src/core/locker_migration.rs
@@ -106,7 +106,7 @@ pub async fn call_to_locker(
let (_add_card_rs_resp, _is_duplicate) = cards::add_card_hs(
state,
pm_create,
- card_details,
+ &card_details,
customer_id.to_string(),
merchant_account,
api_enums::LockerChoice::Tartarus,
diff --git a/crates/router/src/core/payment_link.rs b/crates/router/src/core/payment_link.rs
index 2ea6a4d7f219..89d345b28674 100644
--- a/crates/router/src/core/payment_link.rs
+++ b/crates/router/src/core/payment_link.rs
@@ -3,7 +3,7 @@ use common_utils::{
consts::{
DEFAULT_BACKGROUND_COLOR, DEFAULT_MERCHANT_LOGO, DEFAULT_PRODUCT_IMG, DEFAULT_SDK_THEME,
},
- ext_traits::ValueExt,
+ ext_traits::{OptionExt, ValueExt},
};
use error_stack::{IntoReport, ResultExt};
use masking::{PeekInterface, Secret};
@@ -15,7 +15,6 @@ use crate::{
routes::AppState,
services,
types::{domain, storage::enums as storage_enums, transformers::ForeignFrom},
- utils::OptionExt,
};
pub async fn retrieve_payment_link(
@@ -71,16 +70,11 @@ pub async fn intiate_payment_link_flow(
.await
.to_not_found_response(errors::ApiErrorResponse::PaymentLinkNotFound)?;
- let payment_link_config = merchant_account
- .payment_link_config
- .map(|pl_config| {
- serde_json::from_value::(pl_config)
- .into_report()
- .change_context(errors::ApiErrorResponse::InvalidDataValue {
- field_name: "payment_link_config",
- })
- })
- .transpose()?;
+ let payment_link_config = if let Some(pl_config) = payment_link.payment_link_config.clone() {
+ extract_payment_link_config(Some(pl_config))?
+ } else {
+ extract_payment_link_config(merchant_account.payment_link_config.clone())?
+ };
let order_details = validate_order_details(payment_intent.order_details)?;
@@ -235,3 +229,17 @@ fn validate_order_details(
});
Ok(updated_order_details)
}
+
+fn extract_payment_link_config(
+ pl_config: Option,
+) -> Result