From 962afbd084458e9afb11a0278a8210edd9226a3d Mon Sep 17 00:00:00 2001 From: Kashif Date: Thu, 17 Oct 2024 15:51:59 +0530 Subject: [PATCH] feat(worldpay): migrate to v7 (#6109) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- api-reference-v2/openapi_spec.json | 14 +- api-reference/openapi_spec.json | 14 +- config/deployments/integration_test.toml | 6 +- config/deployments/production.toml | 6 +- config/deployments/sandbox.toml | 2 + config/development.toml | 2 + config/docker_compose.toml | 6 + crates/common_enums/src/enums.rs | 52 +- crates/common_utils/src/consts.rs | 4 + crates/common_utils/src/types.rs | 126 +++ .../connector_configs/toml/development.toml | 3 +- crates/connector_configs/toml/production.toml | 3 +- crates/connector_configs/toml/sandbox.toml | 3 +- crates/currency_conversion/src/types.rs | 12 + crates/diesel_models/src/capture.rs | 20 +- crates/diesel_models/src/payment_attempt.rs | 732 ++++++++++-------- crates/diesel_models/src/query/capture.rs | 20 + crates/diesel_models/src/refund.rs | 74 +- crates/diesel_models/src/schema.rs | 8 + crates/diesel_models/src/schema_v2.rs | 8 + crates/diesel_models/src/user/sample_data.rs | 5 +- .../src/payments/payment_attempt.rs | 26 +- .../src/router_request_types.rs | 1 + crates/kgraph_utils/src/transformers.rs | 12 + crates/router/src/connector/worldpay.rs | 143 +++- .../router/src/connector/worldpay/requests.rs | 56 +- .../router/src/connector/worldpay/response.rs | 223 +++--- .../src/connector/worldpay/transformers.rs | 147 +++- .../fraud_check/flows/transaction_flow.rs | 5 +- .../payments/operations/payment_response.rs | 35 +- .../router/src/core/payments/transformers.rs | 39 +- crates/router/src/core/payments/types.rs | 12 +- crates/router/src/core/refunds.rs | 64 +- crates/router/src/core/utils.rs | 10 +- crates/router/src/core/webhooks/incoming.rs | 1 + crates/router/src/db/address.rs | 12 +- crates/router/src/db/capture.rs | 1 + crates/router/src/db/customers.rs | 20 +- crates/router/src/db/mandate.rs | 16 +- crates/router/src/db/payment_method.rs | 20 +- crates/router/src/db/refund.rs | 48 +- crates/router/src/db/reverse_lookup.rs | 8 +- crates/router/src/services/kafka/refund.rs | 9 +- .../router/src/services/kafka/refund_event.rs | 9 +- crates/router/src/types/api.rs | 2 +- .../src/types/storage/payment_attempt.rs | 1 + crates/router/src/types/transformers.rs | 9 +- crates/router/src/utils/user/sample_data.rs | 18 +- .../router/tests/connectors/sample_auth.toml | 1 + crates/router/tests/connectors/worldpay.rs | 2 +- crates/storage_impl/src/lookup.rs | 8 +- .../src/payments/payment_attempt.rs | 77 +- .../src/payments/payment_intent.rs | 12 +- .../src/payouts/payout_attempt.rs | 16 +- crates/storage_impl/src/payouts/payouts.rs | 16 +- crates/storage_impl/src/redis/kv_store.rs | 8 +- crates/test_utils/tests/sample_auth.toml | 1 + .../cypress/e2e/configs/Payment/Commons.js | 2 +- .../cypress/e2e/PaymentUtils/Commons.js | 2 +- .../cypress/e2e/PaymentUtils/Paybox.js | 2 +- .../down.sql | 11 + .../up.sql | 11 + .../2024-08-28-081721_add_v2_columns/down.sql | 3 +- .../2024-08-28-081721_add_v2_columns/up.sql | 3 +- .../down.sql | 1 + .../up.sql | 1 + 66 files changed, 1492 insertions(+), 752 deletions(-) create mode 100644 migrations/2024-09-25-113851_increase_connector_transaction_id_length_in_payment_and_refund/down.sql create mode 100644 migrations/2024-09-25-113851_increase_connector_transaction_id_length_in_payment_and_refund/up.sql rename v2_migrations/{2024-08-28-081847_drop_v1_columns => 2024-10-08-081847_drop_v1_columns}/down.sql (98%) rename v2_migrations/{2024-08-28-081847_drop_v1_columns => 2024-10-08-081847_drop_v1_columns}/up.sql (98%) diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index 1f296a1081..1db9c98806 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -6018,6 +6018,7 @@ "description": "The three letter ISO currency code in uppercase. Eg: 'USD' for the United States Dollar.", "enum": [ "AED", + "AFN", "ALL", "AMD", "ANG", @@ -6037,10 +6038,12 @@ "BOB", "BRL", "BSD", + "BTN", "BWP", "BYN", "BZD", "CAD", + "CDF", "CHF", "CLP", "CNY", @@ -6054,6 +6057,7 @@ "DOP", "DZD", "EGP", + "ERN", "ETB", "EUR", "FJD", @@ -6075,6 +6079,8 @@ "ILS", "INR", "IQD", + "IRR", + "ISK", "JMD", "JOD", "JPY", @@ -6082,6 +6088,7 @@ "KGS", "KHR", "KMF", + "KPW", "KRW", "KWD", "KYD", @@ -6128,6 +6135,7 @@ "SAR", "SBD", "SCR", + "SDG", "SEK", "SGD", "SHP", @@ -6138,8 +6146,11 @@ "SSP", "STN", "SVC", + "SYP", "SZL", "THB", + "TJS", + "TMT", "TND", "TOP", "TRY", @@ -6161,7 +6172,8 @@ "XPF", "YER", "ZAR", - "ZMW" + "ZMW", + "ZWL" ] }, "CustomerAcceptance": { diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index 355daf66c9..28f1ec4b70 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -9300,6 +9300,7 @@ "description": "The three letter ISO currency code in uppercase. Eg: 'USD' for the United States Dollar.", "enum": [ "AED", + "AFN", "ALL", "AMD", "ANG", @@ -9319,10 +9320,12 @@ "BOB", "BRL", "BSD", + "BTN", "BWP", "BYN", "BZD", "CAD", + "CDF", "CHF", "CLP", "CNY", @@ -9336,6 +9339,7 @@ "DOP", "DZD", "EGP", + "ERN", "ETB", "EUR", "FJD", @@ -9357,6 +9361,8 @@ "ILS", "INR", "IQD", + "IRR", + "ISK", "JMD", "JOD", "JPY", @@ -9364,6 +9370,7 @@ "KGS", "KHR", "KMF", + "KPW", "KRW", "KWD", "KYD", @@ -9410,6 +9417,7 @@ "SAR", "SBD", "SCR", + "SDG", "SEK", "SGD", "SHP", @@ -9420,8 +9428,11 @@ "SSP", "STN", "SVC", + "SYP", "SZL", "THB", + "TJS", + "TMT", "TND", "TOP", "TRY", @@ -9443,7 +9454,8 @@ "XPF", "YER", "ZAR", - "ZMW" + "ZMW", + "ZWL" ] }, "CurrentBlockThreshold": { diff --git a/config/deployments/integration_test.toml b/config/deployments/integration_test.toml index 4f742a6169..dafc604815 100644 --- a/config/deployments/integration_test.toml +++ b/config/deployments/integration_test.toml @@ -323,8 +323,10 @@ upi_collect = {country = "IN", currency = "INR"} open_banking_pis = {currency = "EUR,GBP"} [pm_filters.worldpay] -apple_pay.country = "AU,CN,HK,JP,MO,MY,NZ,SG,TW,AM,AT,AZ,BY,BE,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,GL,GG,HU,IS,IE,IM,IT,KZ,JE,LV,LI,LT,LU,MT,MD,MC,ME,NL,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,UA,GB,AR,CO,CR,BR,MX,PE,BH,IL,JO,KW,PS,QA,SA,AE,CA,UM,US" -google_pay.country = "AL,DZ,AS,AO,AG,AR,AU,AT,AZ,BH,BY,BE,BR,BG,CA,CL,CO,HR,CZ,DK,DO,EG,EE,FI,FR,DE,GR,HK,HU,IN,ID,IE,IL,IT,JP,JO,KZ,KE,KW,LV,LB,LT,LU,MY,MX,NL,NZ,NO,OM,PK,PA,PE,PH,PL,PT,QA,RO,RU,SA,SG,SK,ZA,ES,LK,SE,CH,TW,TH,TR,UA,AE,GB,US,UY,VN" +debit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" } +credit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" } +google_pay = { country = "AL,DZ,AS,AO,AG,AR,AU,AT,AZ,BH,BY,BE,BR,BG,CA,CL,CO,HR,CZ,DK,DO,EG,EE,FI,FR,DE,GR,HK,HU,IN,ID,IE,IL,IT,JP,JO,KZ,KE,KW,LV,LB,LT,LU,MY,MX,NL,NZ,NO,OM,PK,PA,PE,PH,PL,PT,QA,RO,RU,SA,SG,SK,ZA,ES,LK,SE,CH,TW,TH,TR,UA,AE,GB,US,UY,VN" } +apple_pay = { country = "AU,CN,HK,JP,MO,MY,NZ,SG,TW,AM,AT,AZ,BY,BE,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,GL,GG,HU,IS,IE,IM,IT,KZ,JE,LV,LI,LT,LU,MT,MD,MC,ME,NL,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,UA,GB,AR,CO,CR,BR,MX,PE,BH,IL,JO,KW,PS,QA,SA,AE,CA,UM,US" } [pm_filters.zen] boleto = { country = "BR", currency = "BRL" } diff --git a/config/deployments/production.toml b/config/deployments/production.toml index c25b70d6ba..caf8c03056 100644 --- a/config/deployments/production.toml +++ b/config/deployments/production.toml @@ -336,8 +336,10 @@ upi_collect = {country = "IN", currency = "INR"} open_banking_pis = {currency = "EUR,GBP"} [pm_filters.worldpay] -apple_pay.country = "AU,CN,HK,JP,MO,MY,NZ,SG,TW,AM,AT,AZ,BY,BE,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,GL,GG,HU,IS,IE,IM,IT,KZ,JE,LV,LI,LT,LU,MT,MD,MC,ME,NL,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,UA,GB,AR,CO,CR,BR,MX,PE,BH,IL,JO,KW,PS,QA,SA,AE,CA,UM,US" -google_pay.country = "AL,DZ,AS,AO,AG,AR,AU,AT,AZ,BH,BY,BE,BR,BG,CA,CL,CO,HR,CZ,DK,DO,EG,EE,FI,FR,DE,GR,HK,HU,IN,ID,IE,IL,IT,JP,JO,KZ,KE,KW,LV,LB,LT,LU,MY,MX,NL,NZ,NO,OM,PK,PA,PE,PH,PL,PT,QA,RO,RU,SA,SG,SK,ZA,ES,LK,SE,CH,TW,TH,TR,UA,AE,GB,US,UY,VN" +debit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" } +credit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" } +google_pay = { country = "AL,DZ,AS,AO,AG,AR,AU,AT,AZ,BH,BY,BE,BR,BG,CA,CL,CO,HR,CZ,DK,DO,EG,EE,FI,FR,DE,GR,HK,HU,IN,ID,IE,IL,IT,JP,JO,KZ,KE,KW,LV,LB,LT,LU,MY,MX,NL,NZ,NO,OM,PK,PA,PE,PH,PL,PT,QA,RO,RU,SA,SG,SK,ZA,ES,LK,SE,CH,TW,TH,TR,UA,AE,GB,US,UY,VN" } +apple_pay = { country = "AU,CN,HK,JP,MO,MY,NZ,SG,TW,AM,AT,AZ,BY,BE,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,GL,GG,HU,IS,IE,IM,IT,KZ,JE,LV,LI,LT,LU,MT,MD,MC,ME,NL,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,UA,GB,AR,CO,CR,BR,MX,PE,BH,IL,JO,KW,PS,QA,SA,AE,CA,UM,US" } [pm_filters.zen] boleto = { country = "BR", currency = "BRL" } diff --git a/config/deployments/sandbox.toml b/config/deployments/sandbox.toml index 28f5a4e057..6cc1193ab5 100644 --- a/config/deployments/sandbox.toml +++ b/config/deployments/sandbox.toml @@ -340,6 +340,8 @@ upi_collect = {country = "IN", currency = "INR"} open_banking_pis = {currency = "EUR,GBP"} [pm_filters.worldpay] +debit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SAR,RSD,SCR,SLL,SG,ST,SBD,SOS,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,TMT,AED,UG,UA,US,UZ,VU,VE,VN,YER,CNY,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" } +credit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SAR,RSD,SCR,SLL,SG,ST,SBD,SOS,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,TMT,AED,UG,UA,US,UZ,VU,VE,VN,YER,CNY,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" } apple_pay.country = "AU,CN,HK,JP,MO,MY,NZ,SG,TW,AM,AT,AZ,BY,BE,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,GL,GG,HU,IS,IE,IM,IT,KZ,JE,LV,LI,LT,LU,MT,MD,MC,ME,NL,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,UA,GB,AR,CO,CR,BR,MX,PE,BH,IL,JO,KW,PS,QA,SA,AE,CA,UM,US" google_pay.country = "AL,DZ,AS,AO,AG,AR,AU,AT,AZ,BH,BY,BE,BR,BG,CA,CL,CO,HR,CZ,DK,DO,EG,EE,FI,FR,DE,GR,HK,HU,IN,ID,IE,IL,IT,JP,JO,KZ,KE,KW,LV,LB,LT,LU,MY,MX,NL,NZ,NO,OM,PK,PA,PE,PH,PL,PT,QA,RO,RU,SA,SG,SK,ZA,ES,LK,SE,CH,TW,TH,TR,UA,AE,GB,US,UY,VN" diff --git a/config/development.toml b/config/development.toml index 0153c6ef10..4c2f1cf718 100644 --- a/config/development.toml +++ b/config/development.toml @@ -518,6 +518,8 @@ google_pay = { currency = "CHF,DKK,EUR,GBP,NOK,PLN,SEK,USD,AUD,NZD,CAD" } paypal = { currency = "CHF,DKK,EUR,GBP,NOK,PLN,SEK,USD,AUD,NZD,CAD" } [pm_filters.worldpay] +debit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" } +credit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" } google_pay = { country = "AL,DZ,AS,AO,AG,AR,AU,AT,AZ,BH,BY,BE,BR,BG,CA,CL,CO,HR,CZ,DK,DO,EG,EE,FI,FR,DE,GR,HK,HU,IN,ID,IE,IL,IT,JP,JO,KZ,KE,KW,LV,LB,LT,LU,MY,MX,NL,NZ,NO,OM,PK,PA,PE,PH,PL,PT,QA,RO,RU,SA,SG,SK,ZA,ES,LK,SE,CH,TW,TH,TR,UA,AE,GB,US,UY,VN" } apple_pay = { country = "AU,CN,HK,JP,MO,MY,NZ,SG,TW,AM,AT,AZ,BY,BE,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,GL,GG,HU,IS,IE,IM,IT,KZ,JE,LV,LI,LT,LU,MT,MD,MC,ME,NL,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,UA,GB,AR,CO,CR,BR,MX,PE,BH,IL,JO,KW,PS,QA,SA,AE,CA,UM,US" } diff --git a/config/docker_compose.toml b/config/docker_compose.toml index 5ffe5df138..d55e722b3e 100644 --- a/config/docker_compose.toml +++ b/config/docker_compose.toml @@ -441,6 +441,12 @@ credit = { currency = "USD" } debit = { currency = "USD" } ach = { currency = "USD" } +[pm_filters.worldpay] +debit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" } +credit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" } +google_pay = { country = "AL,DZ,AS,AO,AG,AR,AU,AT,AZ,BH,BY,BE,BR,BG,CA,CL,CO,HR,CZ,DK,DO,EG,EE,FI,FR,DE,GR,HK,HU,IN,ID,IE,IL,IT,JP,JO,KZ,KE,KW,LV,LB,LT,LU,MY,MX,NL,NZ,NO,OM,PK,PA,PE,PH,PL,PT,QA,RO,RU,SA,SG,SK,ZA,ES,LK,SE,CH,TW,TH,TR,UA,AE,GB,US,UY,VN" } +apple_pay = { country = "AU,CN,HK,JP,MO,MY,NZ,SG,TW,AM,AT,AZ,BY,BE,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,GL,GG,HU,IS,IE,IM,IT,KZ,JE,LV,LI,LT,LU,MT,MD,MC,ME,NL,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,UA,GB,AR,CO,CR,BR,MX,PE,BH,IL,JO,KW,PS,QA,SA,AE,CA,UM,US" } + [bank_config.online_banking_fpx] adyen.banks = "affin_bank,agro_bank,alliance_bank,am_bank,bank_islam,bank_muamalat,bank_rakyat,bank_simpanan_nasional,cimb_bank,hong_leong_bank,hsbc_bank,kuwait_finance_house,maybank,ocbc_bank,public_bank,rhb_bank,standard_chartered_bank,uob_bank" fiuu.banks = "affin_bank,agro_bank,alliance_bank,am_bank,bank_of_china,bank_islam,bank_muamalat,bank_rakyat,bank_simpanan_nasional,cimb_bank,hong_leong_bank,hsbc_bank,kuwait_finance_house,maybank,ocbc_bank,public_bank,rhb_bank,standard_chartered_bank,uob_bank" diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index 0a87e6c19a..8306deeb25 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -558,6 +558,7 @@ pub enum CallConnectorAction { #[router_derive::diesel_enum(storage_type = "db_enum")] pub enum Currency { AED, + AFN, ALL, AMD, ANG, @@ -577,10 +578,12 @@ pub enum Currency { BOB, BRL, BSD, + BTN, BWP, BYN, BZD, CAD, + CDF, CHF, CLP, CNY, @@ -594,6 +597,7 @@ pub enum Currency { DOP, DZD, EGP, + ERN, ETB, EUR, FJD, @@ -615,6 +619,8 @@ pub enum Currency { ILS, INR, IQD, + IRR, + ISK, JMD, JOD, JPY, @@ -622,6 +628,7 @@ pub enum Currency { KGS, KHR, KMF, + KPW, KRW, KWD, KYD, @@ -668,6 +675,7 @@ pub enum Currency { SAR, SBD, SCR, + SDG, SEK, SGD, SHP, @@ -678,8 +686,11 @@ pub enum Currency { SSP, STN, SVC, + SYP, SZL, THB, + TJS, + TMT, TND, TOP, TRY, @@ -703,6 +714,7 @@ pub enum Currency { YER, ZAR, ZMW, + ZWL, } impl Currency { @@ -756,6 +768,7 @@ impl Currency { pub fn iso_4217(&self) -> &'static str { match *self { Self::AED => "784", + Self::AFN => "971", Self::ALL => "008", Self::AMD => "051", Self::ANG => "532", @@ -775,10 +788,12 @@ impl Currency { Self::BOB => "068", Self::BRL => "986", Self::BSD => "044", + Self::BTN => "064", Self::BWP => "072", Self::BYN => "933", Self::BZD => "084", Self::CAD => "124", + Self::CDF => "976", Self::CHF => "756", Self::CLP => "152", Self::COP => "170", @@ -791,6 +806,7 @@ impl Currency { Self::DOP => "214", Self::DZD => "012", Self::EGP => "818", + Self::ERN => "232", Self::ETB => "230", Self::EUR => "978", Self::FJD => "242", @@ -812,6 +828,8 @@ impl Currency { Self::ILS => "376", Self::INR => "356", Self::IQD => "368", + Self::IRR => "364", + Self::ISK => "352", Self::JMD => "388", Self::JOD => "400", Self::JPY => "392", @@ -819,6 +837,7 @@ impl Currency { Self::KGS => "417", Self::KHR => "116", Self::KMF => "174", + Self::KPW => "408", Self::KRW => "410", Self::KWD => "414", Self::KYD => "136", @@ -866,6 +885,7 @@ impl Currency { Self::SAR => "682", Self::SBD => "090", Self::SCR => "690", + Self::SDG => "938", Self::SEK => "752", Self::SGD => "702", Self::SHP => "654", @@ -876,8 +896,11 @@ impl Currency { Self::SSP => "728", Self::STN => "930", Self::SVC => "222", + Self::SYP => "760", Self::SZL => "748", Self::THB => "764", + Self::TJS => "972", + Self::TMT => "934", Self::TND => "788", Self::TOP => "776", Self::TRY => "949", @@ -900,6 +923,7 @@ impl Currency { Self::YER => "886", Self::ZAR => "710", Self::ZMW => "967", + Self::ZWL => "932", } } @@ -909,6 +933,7 @@ impl Currency { | Self::CLP | Self::DJF | Self::GNF + | Self::IRR | Self::JPY | Self::KMF | Self::KRW @@ -922,6 +947,7 @@ impl Currency { | Self::XOF | Self::XPF => true, Self::AED + | Self::AFN | Self::ALL | Self::AMD | Self::ANG @@ -940,10 +966,12 @@ impl Currency { | Self::BOB | Self::BRL | Self::BSD + | Self::BTN | Self::BWP | Self::BYN | Self::BZD | Self::CAD + | Self::CDF | Self::CHF | Self::CNY | Self::COP @@ -955,6 +983,7 @@ impl Currency { | Self::DOP | Self::DZD | Self::EGP + | Self::ERN | Self::ETB | Self::EUR | Self::FJD @@ -975,11 +1004,13 @@ impl Currency { | Self::ILS | Self::INR | Self::IQD + | Self::ISK | Self::JMD | Self::JOD | Self::KES | Self::KGS | Self::KHR + | Self::KPW | Self::KWD | Self::KYD | Self::KZT @@ -1022,6 +1053,7 @@ impl Currency { | Self::SAR | Self::SBD | Self::SCR + | Self::SDG | Self::SEK | Self::SGD | Self::SHP @@ -1032,8 +1064,11 @@ impl Currency { | Self::SSP | Self::STN | Self::SVC + | Self::SYP | Self::SZL | Self::THB + | Self::TJS + | Self::TMT | Self::TND | Self::TOP | Self::TRY @@ -1049,7 +1084,8 @@ impl Currency { | Self::XCD | Self::YER | Self::ZAR - | Self::ZMW => false, + | Self::ZMW + | Self::ZWL => false, } } @@ -1059,6 +1095,7 @@ impl Currency { true } Self::AED + | Self::AFN | Self::ALL | Self::AMD | Self::AOA @@ -1077,10 +1114,12 @@ impl Currency { | Self::BOB | Self::BRL | Self::BSD + | Self::BTN | Self::BWP | Self::BYN | Self::BZD | Self::CAD + | Self::CDF | Self::CHF | Self::CLP | Self::CNY @@ -1094,6 +1133,7 @@ impl Currency { | Self::DOP | Self::DZD | Self::EGP + | Self::ERN | Self::ETB | Self::EUR | Self::FJD @@ -1114,12 +1154,15 @@ impl Currency { | Self::IDR | Self::ILS | Self::INR + | Self::IRR + | Self::ISK | Self::JMD | Self::JPY | Self::KES | Self::KGS | Self::KHR | Self::KMF + | Self::KPW | Self::KRW | Self::KYD | Self::KZT @@ -1163,6 +1206,7 @@ impl Currency { | Self::SAR | Self::SBD | Self::SCR + | Self::SDG | Self::SEK | Self::SGD | Self::SHP @@ -1173,8 +1217,11 @@ impl Currency { | Self::SSP | Self::STN | Self::SVC + | Self::SYP | Self::SZL | Self::THB + | Self::TJS + | Self::TMT | Self::TOP | Self::TRY | Self::TTD @@ -1195,7 +1242,8 @@ impl Currency { | Self::XOF | Self::YER | Self::ZAR - | Self::ZMW => false, + | Self::ZMW + | Self::ZWL => false, } } diff --git a/crates/common_utils/src/consts.rs b/crates/common_utils/src/consts.rs index 00ffb614bb..21e5866aea 100644 --- a/crates/common_utils/src/consts.rs +++ b/crates/common_utils/src/consts.rs @@ -154,3 +154,7 @@ pub const MAX_DESCRIPTION_LENGTH: u16 = 255; pub const MAX_STATEMENT_DESCRIPTOR_LENGTH: u16 = 22; /// Payout flow identifier used for performing GSM operations pub const PAYOUT_FLOW_STR: &str = "payout_flow"; + +/// The number of bytes allocated for the hashed connector transaction ID. +/// Total number of characters equals CONNECTOR_TRANSACTION_ID_HASH_BYTES times 2. +pub const CONNECTOR_TRANSACTION_ID_HASH_BYTES: usize = 25; diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index e11ddbf7a3..a1c9b4c00c 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -1272,3 +1272,129 @@ where self.0.to_sql(out) } } + +/// Domain type for connector_transaction_id +/// Maximum length for connector's transaction_id can be 128 characters in HS DB. +/// In case connector's use an identifier whose length exceeds 128 characters, +/// the hash value of such identifiers will be stored as connector_transaction_id. +/// The actual connector's identifier will be stored in a separate column - +/// connector_transaction_data or something with a similar name. +#[derive(Debug, Clone, PartialEq, Eq, serde::Deserialize, serde::Serialize, AsExpression)] +#[diesel(sql_type = sql_types::Text)] +pub enum ConnectorTransactionId { + /// Actual transaction identifier + TxnId(String), + /// Hashed value of the transaction identifier + HashedData(String), +} + +impl ConnectorTransactionId { + /// Implementation for retrieving the inner identifier + pub fn get_id(&self) -> &String { + match self { + Self::TxnId(id) | Self::HashedData(id) => id, + } + } + + /// Implementation for forming ConnectorTransactionId and an optional string to be used for connector_transaction_id and connector_transaction_data + pub fn form_id_and_data(src: String) -> (Self, Option) { + let txn_id = Self::from(src.clone()); + match txn_id { + Self::TxnId(_) => (txn_id, None), + Self::HashedData(_) => (txn_id, Some(src)), + } + } + + /// Implementation for retrieving + pub fn get_txn_id<'a>( + &'a self, + txn_data: Option<&'a String>, + ) -> Result<&'a String, error_stack::Report> { + match (self, txn_data) { + (Self::TxnId(id), _) => Ok(id), + (Self::HashedData(_), Some(id)) => Ok(id), + (Self::HashedData(id), None) => Err(report!(ValidationError::InvalidValue { + message: "connector_transaction_data is empty for HashedData variant".to_string(), + }) + .attach_printable(format!( + "connector_transaction_data is empty for connector_transaction_id {}", + id + ))), + } + } +} + +impl From for ConnectorTransactionId { + fn from(src: String) -> Self { + // ID already hashed + if src.starts_with("hs_hash_") { + Self::HashedData(src) + // Hash connector's transaction ID + } else if src.len() > 128 { + let mut hasher = blake3::Hasher::new(); + let mut output = [0u8; consts::CONNECTOR_TRANSACTION_ID_HASH_BYTES]; + hasher.update(src.as_bytes()); + hasher.finalize_xof().fill(&mut output); + let hash = hex::encode(output); + Self::HashedData(format!("hs_hash_{}", hash)) + // Default + } else { + Self::TxnId(src) + } + } +} + +impl Queryable for ConnectorTransactionId +where + DB: Backend, + Self: FromSql, +{ + type Row = Self; + + fn build(row: Self::Row) -> deserialize::Result { + Ok(row) + } +} + +impl FromSql for ConnectorTransactionId +where + DB: Backend, + String: FromSql, +{ + fn from_sql(bytes: DB::RawValue<'_>) -> deserialize::Result { + let val = String::from_sql(bytes)?; + Ok(Self::from(val)) + } +} + +impl ToSql for ConnectorTransactionId +where + DB: Backend, + String: ToSql, +{ + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> diesel::serialize::Result { + match self { + Self::HashedData(id) | Self::TxnId(id) => id.to_sql(out), + } + } +} + +/// Trait for fetching actual or hashed transaction IDs +pub trait ConnectorTransactionIdTrait { + /// Returns an optional connector transaction ID + fn get_optional_connector_transaction_id(&self) -> Option<&String> { + None + } + /// Returns a connector transaction ID + fn get_connector_transaction_id(&self) -> &String { + self.get_optional_connector_transaction_id() + .unwrap_or_else(|| { + static EMPTY_STRING: String = String::new(); + &EMPTY_STRING + }) + } + /// Returns an optional connector refund ID + fn get_optional_connector_refund_id(&self) -> Option<&String> { + self.get_optional_connector_transaction_id() + } +} diff --git a/crates/connector_configs/toml/development.toml b/crates/connector_configs/toml/development.toml index e20054c59b..56c19637e5 100644 --- a/crates/connector_configs/toml/development.toml +++ b/crates/connector_configs/toml/development.toml @@ -3410,9 +3410,10 @@ merchant_secret="Source verification key" payment_method_type = "google_pay" [[worldpay.wallet]] payment_method_type = "apple_pay" -[worldpay.connector_auth.BodyKey] +[worldpay.connector_auth.SignatureKey] api_key="Username" key1="Password" +api_secret="Merchant Identifier" [worldpay.connector_webhook_details] merchant_secret="Source verification key" diff --git a/crates/connector_configs/toml/production.toml b/crates/connector_configs/toml/production.toml index e840b0ed55..c8005087a1 100644 --- a/crates/connector_configs/toml/production.toml +++ b/crates/connector_configs/toml/production.toml @@ -2469,9 +2469,10 @@ merchant_secret="Source verification key" payment_method_type = "google_pay" [[worldpay.wallet]] payment_method_type = "apple_pay" -[worldpay.connector_auth.BodyKey] +[worldpay.connector_auth.SignatureKey] api_key="Username" key1="Password" +api_secret="Merchant Identifier" [[worldpay.metadata.apple_pay]] name="certificate" diff --git a/crates/connector_configs/toml/sandbox.toml b/crates/connector_configs/toml/sandbox.toml index c694d59195..a1d81f2723 100644 --- a/crates/connector_configs/toml/sandbox.toml +++ b/crates/connector_configs/toml/sandbox.toml @@ -3400,9 +3400,10 @@ merchant_secret="Source verification key" payment_method_type = "google_pay" [[worldpay.wallet]] payment_method_type = "apple_pay" -[worldpay.connector_auth.BodyKey] +[worldpay.connector_auth.SignatureKey] api_key="Username" key1="Password" +api_secret="Merchant Identifier" [worldpay.connector_webhook_details] merchant_secret="Source verification key" diff --git a/crates/currency_conversion/src/types.rs b/crates/currency_conversion/src/types.rs index a84520dca0..2001495b2d 100644 --- a/crates/currency_conversion/src/types.rs +++ b/crates/currency_conversion/src/types.rs @@ -78,6 +78,7 @@ impl ExchangeRates { pub fn currency_match(currency: Currency) -> &'static iso::Currency { match currency { Currency::AED => iso::AED, + Currency::AFN => iso::AFN, Currency::ALL => iso::ALL, Currency::AMD => iso::AMD, Currency::ANG => iso::ANG, @@ -97,10 +98,12 @@ pub fn currency_match(currency: Currency) -> &'static iso::Currency { Currency::BOB => iso::BOB, Currency::BRL => iso::BRL, Currency::BSD => iso::BSD, + Currency::BTN => iso::BTN, Currency::BWP => iso::BWP, Currency::BYN => iso::BYN, Currency::BZD => iso::BZD, Currency::CAD => iso::CAD, + Currency::CDF => iso::CDF, Currency::CHF => iso::CHF, Currency::CLP => iso::CLP, Currency::CNY => iso::CNY, @@ -114,6 +117,7 @@ pub fn currency_match(currency: Currency) -> &'static iso::Currency { Currency::DOP => iso::DOP, Currency::DZD => iso::DZD, Currency::EGP => iso::EGP, + Currency::ERN => iso::ERN, Currency::ETB => iso::ETB, Currency::EUR => iso::EUR, Currency::FJD => iso::FJD, @@ -135,6 +139,8 @@ pub fn currency_match(currency: Currency) -> &'static iso::Currency { Currency::ILS => iso::ILS, Currency::INR => iso::INR, Currency::IQD => iso::IQD, + Currency::IRR => iso::IRR, + Currency::ISK => iso::ISK, Currency::JMD => iso::JMD, Currency::JOD => iso::JOD, Currency::JPY => iso::JPY, @@ -142,6 +148,7 @@ pub fn currency_match(currency: Currency) -> &'static iso::Currency { Currency::KGS => iso::KGS, Currency::KHR => iso::KHR, Currency::KMF => iso::KMF, + Currency::KPW => iso::KPW, Currency::KRW => iso::KRW, Currency::KWD => iso::KWD, Currency::KYD => iso::KYD, @@ -188,6 +195,7 @@ pub fn currency_match(currency: Currency) -> &'static iso::Currency { Currency::SAR => iso::SAR, Currency::SBD => iso::SBD, Currency::SCR => iso::SCR, + Currency::SDG => iso::SDG, Currency::SEK => iso::SEK, Currency::SGD => iso::SGD, Currency::SHP => iso::SHP, @@ -198,9 +206,12 @@ pub fn currency_match(currency: Currency) -> &'static iso::Currency { Currency::SSP => iso::SSP, Currency::STN => iso::STN, Currency::SVC => iso::SVC, + Currency::SYP => iso::SYP, Currency::SZL => iso::SZL, Currency::THB => iso::THB, + Currency::TJS => iso::TJS, Currency::TND => iso::TND, + Currency::TMT => iso::TMT, Currency::TOP => iso::TOP, Currency::TTD => iso::TTD, Currency::TRY => iso::TRY, @@ -222,5 +233,6 @@ pub fn currency_match(currency: Currency) -> &'static iso::Currency { Currency::YER => iso::YER, Currency::ZAR => iso::ZAR, Currency::ZMW => iso::ZMW, + Currency::ZWL => iso::ZWL, } } diff --git a/crates/diesel_models/src/capture.rs b/crates/diesel_models/src/capture.rs index 0b0b86222e..d6272c3406 100644 --- a/crates/diesel_models/src/capture.rs +++ b/crates/diesel_models/src/capture.rs @@ -1,4 +1,4 @@ -use common_utils::types::MinorUnit; +use common_utils::types::{ConnectorTransactionId, MinorUnit}; use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable}; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; @@ -6,7 +6,7 @@ use time::PrimitiveDateTime; use crate::{enums as storage_enums, schema::captures}; #[derive( - Clone, Debug, Eq, PartialEq, Identifiable, Queryable, Selectable, Serialize, Deserialize, Hash, + Clone, Debug, Eq, PartialEq, Identifiable, Queryable, Selectable, Serialize, Deserialize, )] #[diesel(table_name = captures, primary_key(capture_id), check_for_backend(diesel::pg::Pg))] pub struct Capture { @@ -26,10 +26,11 @@ pub struct Capture { #[serde(with = "common_utils::custom_serde::iso8601")] pub modified_at: PrimitiveDateTime, pub authorized_attempt_id: String, - pub connector_capture_id: Option, + pub connector_capture_id: Option, pub capture_sequence: i16, // reference to the capture at connector side pub connector_response_reference_id: Option, + pub connector_capture_data: Option, } #[derive(Clone, Debug, Insertable, router_derive::DebugAsDisplay, Serialize, Deserialize)] @@ -51,17 +52,19 @@ pub struct CaptureNew { #[serde(with = "common_utils::custom_serde::iso8601")] pub modified_at: PrimitiveDateTime, pub authorized_attempt_id: String, - pub connector_capture_id: Option, + pub connector_capture_id: Option, pub capture_sequence: i16, pub connector_response_reference_id: Option, + pub connector_capture_data: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] pub enum CaptureUpdate { ResponseUpdate { status: storage_enums::CaptureStatus, - connector_capture_id: Option, + connector_capture_id: Option, connector_response_reference_id: Option, + connector_capture_data: Option, }, ErrorUpdate { status: storage_enums::CaptureStatus, @@ -79,8 +82,9 @@ pub struct CaptureUpdateInternal { pub error_code: Option, pub error_reason: Option, pub modified_at: Option, - pub connector_capture_id: Option, + pub connector_capture_id: Option, pub connector_response_reference_id: Option, + pub connector_capture_data: Option, } impl CaptureUpdate { @@ -93,6 +97,7 @@ impl CaptureUpdate { modified_at: _, connector_capture_id, connector_response_reference_id, + connector_capture_data, } = self.into(); Capture { status: status.unwrap_or(source.status), @@ -103,6 +108,7 @@ impl CaptureUpdate { connector_capture_id: connector_capture_id.or(source.connector_capture_id), connector_response_reference_id: connector_response_reference_id .or(source.connector_response_reference_id), + connector_capture_data: connector_capture_data.or(source.connector_capture_data), ..source } } @@ -116,11 +122,13 @@ impl From for CaptureUpdateInternal { status, connector_capture_id: connector_transaction_id, connector_response_reference_id, + connector_capture_data, } => Self { status: Some(status), connector_capture_id: connector_transaction_id, modified_at: now, connector_response_reference_id, + connector_capture_data, ..Self::default() }, CaptureUpdate::ErrorUpdate { diff --git a/crates/diesel_models/src/payment_attempt.rs b/crates/diesel_models/src/payment_attempt.rs index 20551c2754..277061c78a 100644 --- a/crates/diesel_models/src/payment_attempt.rs +++ b/crates/diesel_models/src/payment_attempt.rs @@ -1,4 +1,7 @@ -use common_utils::{id_type, pii, types::MinorUnit}; +use common_utils::{ + id_type, pii, + types::{ConnectorTransactionId, ConnectorTransactionIdTrait, MinorUnit}, +}; use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable}; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; @@ -63,12 +66,13 @@ pub struct PaymentAttempt { pub organization_id: id_type::OrganizationId, pub card_network: Option, pub payment_method_type_v2: Option, - pub connector_payment_id: Option, + pub connector_payment_id: Option, pub payment_method_subtype: Option, pub routing_result: Option, pub authentication_applied: Option, pub external_reference_id: Option, pub tax_on_surcharge: Option, + pub connector_payment_data: Option, pub id: String, pub shipping_cost: Option, pub order_tax_amount: Option, @@ -94,7 +98,7 @@ pub struct PaymentAttempt { pub tax_amount: Option, pub payment_method_id: Option, pub payment_method: Option, - pub connector_transaction_id: Option, + pub connector_transaction_id: Option, pub capture_method: Option, #[serde(default, with = "common_utils::custom_serde::iso8601::option")] pub capture_on: Option, @@ -148,6 +152,47 @@ pub struct PaymentAttempt { pub card_network: Option, pub shipping_cost: Option, pub order_tax_amount: Option, + pub connector_transaction_data: Option, +} + +#[cfg(feature = "v1")] +impl ConnectorTransactionIdTrait for PaymentAttempt { + fn get_optional_connector_transaction_id(&self) -> Option<&String> { + match self + .connector_transaction_id + .as_ref() + .map(|txn_id| txn_id.get_txn_id(self.connector_transaction_data.as_ref())) + .transpose() + { + Ok(txn_id) => txn_id, + + // In case hashed data is missing from DB, use the hashed ID as connector transaction ID + Err(_) => self + .connector_transaction_id + .as_ref() + .map(|txn_id| txn_id.get_id()), + } + } +} + +#[cfg(feature = "v2")] +impl ConnectorTransactionIdTrait for PaymentAttempt { + fn get_optional_connector_transaction_id(&self) -> Option<&String> { + match self + .connector_payment_id + .as_ref() + .map(|txn_id| txn_id.get_txn_id(self.connector_payment_data.as_ref())) + .transpose() + { + Ok(txn_id) => txn_id, + + // In case hashed data is missing from DB, use the hashed ID as connector payment ID + Err(_) => self + .connector_payment_id + .as_ref() + .map(|txn_id| txn_id.get_id()), + } + } } #[derive(Clone, Debug, Eq, PartialEq, Queryable, Serialize, Deserialize)] @@ -711,6 +756,7 @@ pub struct PaymentAttemptUpdateInternal { client_version: Option, customer_acceptance: Option, card_network: Option, + connector_payment_data: Option, } #[cfg(feature = "v1")] @@ -721,7 +767,7 @@ pub struct PaymentAttemptUpdateInternal { pub net_amount: Option, pub currency: Option, pub status: Option, - pub connector_transaction_id: Option, + pub connector_transaction_id: Option, pub amount_to_capture: Option, pub connector: Option>, pub authentication_type: Option, @@ -766,6 +812,7 @@ pub struct PaymentAttemptUpdateInternal { pub card_network: Option, pub shipping_cost: Option, pub order_tax_amount: Option, + pub connector_transaction_data: Option, } #[cfg(feature = "v2")] @@ -954,6 +1001,7 @@ impl PaymentAttemptUpdate { card_network, shipping_cost, order_tax_amount, + connector_transaction_data, } = PaymentAttemptUpdateInternal::from(self).populate_derived_fields(&source); PaymentAttempt { amount: amount.unwrap_or(source.amount), @@ -1009,6 +1057,8 @@ impl PaymentAttemptUpdate { card_network: card_network.or(source.card_network), shipping_cost: shipping_cost.or(source.shipping_cost), order_tax_amount: order_tax_amount.or(source.order_tax_amount), + connector_transaction_data: connector_transaction_data + .or(source.connector_transaction_data), ..source } } @@ -2003,6 +2053,7 @@ impl From for PaymentAttemptUpdateInternal { card_network: None, shipping_cost: None, order_tax_amount: None, + connector_transaction_data: None, }, PaymentAttemptUpdate::AuthenticationTypeUpdate { authentication_type, @@ -2057,6 +2108,7 @@ impl From for PaymentAttemptUpdateInternal { card_network: None, shipping_cost: None, order_tax_amount: None, + connector_transaction_data: None, }, PaymentAttemptUpdate::ConfirmUpdate { amount, @@ -2141,6 +2193,7 @@ impl From for PaymentAttemptUpdateInternal { card_network: None, shipping_cost, order_tax_amount, + connector_transaction_data: None, }, PaymentAttemptUpdate::VoidUpdate { status, @@ -2196,6 +2249,7 @@ impl From for PaymentAttemptUpdateInternal { card_network: None, shipping_cost: None, order_tax_amount: None, + connector_transaction_data: None, }, PaymentAttemptUpdate::RejectUpdate { status, @@ -2252,6 +2306,7 @@ impl From for PaymentAttemptUpdateInternal { card_network: None, shipping_cost: None, order_tax_amount: None, + connector_transaction_data: None, }, PaymentAttemptUpdate::BlocklistUpdate { status, @@ -2308,6 +2363,7 @@ impl From for PaymentAttemptUpdateInternal { card_network: None, shipping_cost: None, order_tax_amount: None, + connector_transaction_data: None, }, PaymentAttemptUpdate::PaymentMethodDetailsUpdate { payment_method_id, @@ -2362,6 +2418,7 @@ impl From for PaymentAttemptUpdateInternal { card_network: None, shipping_cost: None, order_tax_amount: None, + connector_transaction_data: None, }, PaymentAttemptUpdate::ResponseUpdate { status, @@ -2384,57 +2441,65 @@ impl From for PaymentAttemptUpdateInternal { unified_message, payment_method_data, charge_id, - } => Self { - status: Some(status), - connector: connector.map(Some), - connector_transaction_id, - authentication_type, - payment_method_id, - modified_at: common_utils::date_time::now(), - mandate_id, - connector_metadata, - error_code, - error_message, - payment_token, - error_reason, - connector_response_reference_id, - amount_capturable, - updated_by, - authentication_data, - encoded_data, - unified_code, - unified_message, - payment_method_data, - charge_id, - amount: None, - net_amount: None, - currency: None, - amount_to_capture: None, - payment_method: None, - cancellation_reason: None, - browser_info: None, - payment_method_type: None, - payment_experience: None, - business_sub_label: None, - straight_through_algorithm: None, - preprocessing_step_id: None, - capture_method: None, - multiple_capture_count: None, - surcharge_amount: None, - tax_amount: None, - merchant_connector_id: None, - external_three_ds_authentication_attempted: None, - authentication_connector: None, - authentication_id: None, - fingerprint_id: None, - payment_method_billing_address_id: None, - client_source: None, - client_version: None, - customer_acceptance: None, - card_network: None, - shipping_cost: None, - order_tax_amount: None, - }, + } => { + let (connector_transaction_id, connector_transaction_data) = + connector_transaction_id + .map(ConnectorTransactionId::form_id_and_data) + .map(|(txn_id, txn_data)| (Some(txn_id), txn_data)) + .unwrap_or((None, None)); + Self { + status: Some(status), + connector: connector.map(Some), + connector_transaction_id, + authentication_type, + payment_method_id, + modified_at: common_utils::date_time::now(), + mandate_id, + connector_metadata, + error_code, + error_message, + payment_token, + error_reason, + connector_response_reference_id, + amount_capturable, + updated_by, + authentication_data, + encoded_data, + unified_code, + unified_message, + payment_method_data, + charge_id, + connector_transaction_data, + amount: None, + net_amount: None, + currency: None, + amount_to_capture: None, + payment_method: None, + cancellation_reason: None, + browser_info: None, + payment_method_type: None, + payment_experience: None, + business_sub_label: None, + straight_through_algorithm: None, + preprocessing_step_id: None, + capture_method: None, + multiple_capture_count: None, + surcharge_amount: None, + tax_amount: None, + merchant_connector_id: None, + external_three_ds_authentication_attempted: None, + authentication_connector: None, + authentication_id: None, + fingerprint_id: None, + payment_method_billing_address_id: None, + client_source: None, + client_version: None, + customer_acceptance: None, + card_network: None, + shipping_cost: None, + order_tax_amount: None, + } + } PaymentAttemptUpdate::ErrorUpdate { connector, status, @@ -2448,57 +2513,65 @@ impl From for PaymentAttemptUpdateInternal { connector_transaction_id, payment_method_data, authentication_type, - } => Self { - connector: connector.map(Some), - status: Some(status), - error_message, - error_code, - modified_at: common_utils::date_time::now(), - error_reason, - amount_capturable, - updated_by, - unified_code, - unified_message, - connector_transaction_id, - payment_method_data, - authentication_type, - amount: None, - net_amount: None, - currency: None, - amount_to_capture: None, - payment_method: None, - payment_method_id: None, - cancellation_reason: None, - mandate_id: None, - browser_info: None, - payment_token: None, - connector_metadata: None, - payment_method_type: None, - payment_experience: None, - business_sub_label: None, - straight_through_algorithm: None, - preprocessing_step_id: None, - capture_method: None, - connector_response_reference_id: None, - multiple_capture_count: None, - surcharge_amount: None, - tax_amount: None, - merchant_connector_id: None, - authentication_data: None, - encoded_data: None, - external_three_ds_authentication_attempted: None, - authentication_connector: None, - authentication_id: None, - fingerprint_id: None, - payment_method_billing_address_id: None, - charge_id: None, - client_source: None, - client_version: None, - customer_acceptance: None, - card_network: None, - shipping_cost: None, - order_tax_amount: None, - }, + } => { + let (connector_transaction_id, connector_transaction_data) = + connector_transaction_id + .map(ConnectorTransactionId::form_id_and_data) + .map(|(txn_id, txn_data)| (Some(txn_id), txn_data)) + .unwrap_or((None, None)); + Self { + connector: connector.map(Some), + status: Some(status), + error_message, + error_code, + modified_at: common_utils::date_time::now(), + error_reason, + amount_capturable, + updated_by, + unified_code, + unified_message, + connector_transaction_id, + payment_method_data, + authentication_type, + connector_transaction_data, + amount: None, + net_amount: None, + currency: None, + amount_to_capture: None, + payment_method: None, + payment_method_id: None, + cancellation_reason: None, + mandate_id: None, + browser_info: None, + payment_token: None, + connector_metadata: None, + payment_method_type: None, + payment_experience: None, + business_sub_label: None, + straight_through_algorithm: None, + preprocessing_step_id: None, + capture_method: None, + connector_response_reference_id: None, + multiple_capture_count: None, + surcharge_amount: None, + tax_amount: None, + merchant_connector_id: None, + authentication_data: None, + encoded_data: None, + external_three_ds_authentication_attempted: None, + authentication_connector: None, + authentication_id: None, + fingerprint_id: None, + payment_method_billing_address_id: None, + charge_id: None, + client_source: None, + client_version: None, + customer_acceptance: None, + card_network: None, + shipping_cost: None, + order_tax_amount: None, + } + } PaymentAttemptUpdate::StatusUpdate { status, updated_by } => Self { status: Some(status), modified_at: common_utils::date_time::now(), @@ -2549,6 +2622,7 @@ impl From for PaymentAttemptUpdateInternal { card_network: None, shipping_cost: None, order_tax_amount: None, + connector_transaction_data: None, }, PaymentAttemptUpdate::UpdateTrackers { payment_token, @@ -2609,6 +2683,7 @@ impl From for PaymentAttemptUpdateInternal { card_network: None, shipping_cost: None, order_tax_amount: None, + connector_transaction_data: None, }, PaymentAttemptUpdate::UnresolvedResponseUpdate { status, @@ -2620,57 +2695,65 @@ impl From for PaymentAttemptUpdateInternal { error_reason, connector_response_reference_id, updated_by, - } => Self { - status: Some(status), - connector: connector.map(Some), - connector_transaction_id, - payment_method_id, - modified_at: common_utils::date_time::now(), - error_code, - error_message, - error_reason, - connector_response_reference_id, - updated_by, - amount: None, - net_amount: None, - currency: None, - amount_to_capture: None, - authentication_type: None, - payment_method: None, - cancellation_reason: None, - mandate_id: None, - browser_info: None, - payment_token: None, - connector_metadata: None, - payment_method_data: None, - payment_method_type: None, - payment_experience: None, - business_sub_label: None, - straight_through_algorithm: None, - preprocessing_step_id: None, - capture_method: None, - multiple_capture_count: None, - surcharge_amount: None, - tax_amount: None, - amount_capturable: None, - merchant_connector_id: None, - authentication_data: None, - encoded_data: None, - unified_code: None, - unified_message: None, - external_three_ds_authentication_attempted: None, - authentication_connector: None, - authentication_id: None, - fingerprint_id: None, - payment_method_billing_address_id: None, - charge_id: None, - client_source: None, - client_version: None, - customer_acceptance: None, - card_network: None, - shipping_cost: None, - order_tax_amount: None, - }, + } => { + let (connector_transaction_id, connector_transaction_data) = + connector_transaction_id + .map(ConnectorTransactionId::form_id_and_data) + .map(|(txn_id, txn_data)| (Some(txn_id), txn_data)) + .unwrap_or((None, None)); + Self { + status: Some(status), + connector: connector.map(Some), + connector_transaction_id, + payment_method_id, + modified_at: common_utils::date_time::now(), + error_code, + error_message, + error_reason, + connector_response_reference_id, + updated_by, + connector_transaction_data, + amount: None, + net_amount: None, + currency: None, + amount_to_capture: None, + authentication_type: None, + payment_method: None, + cancellation_reason: None, + mandate_id: None, + browser_info: None, + payment_token: None, + connector_metadata: None, + payment_method_data: None, + payment_method_type: None, + payment_experience: None, + business_sub_label: None, + straight_through_algorithm: None, + preprocessing_step_id: None, + capture_method: None, + multiple_capture_count: None, + surcharge_amount: None, + tax_amount: None, + amount_capturable: None, + merchant_connector_id: None, + authentication_data: None, + encoded_data: None, + unified_code: None, + unified_message: None, + external_three_ds_authentication_attempted: None, + authentication_connector: None, + authentication_id: None, + fingerprint_id: None, + payment_method_billing_address_id: None, + charge_id: None, + client_source: None, + client_version: None, + customer_acceptance: None, + card_network: None, + shipping_cost: None, + order_tax_amount: None, + } + } PaymentAttemptUpdate::PreprocessingUpdate { status, payment_method_id, @@ -2679,57 +2762,65 @@ impl From for PaymentAttemptUpdateInternal { connector_transaction_id, connector_response_reference_id, updated_by, - } => Self { - status: Some(status), - payment_method_id, - modified_at: common_utils::date_time::now(), - connector_metadata, - preprocessing_step_id, - connector_transaction_id, - connector_response_reference_id, - updated_by, - amount: None, - net_amount: None, - currency: None, - amount_to_capture: None, - connector: None, - authentication_type: None, - payment_method: None, - error_message: None, - cancellation_reason: None, - mandate_id: None, - browser_info: None, - payment_token: None, - error_code: None, - payment_method_data: None, - payment_method_type: None, - payment_experience: None, - business_sub_label: None, - straight_through_algorithm: None, - error_reason: None, - capture_method: None, - multiple_capture_count: None, - surcharge_amount: None, - tax_amount: None, - amount_capturable: None, - merchant_connector_id: None, - authentication_data: None, - encoded_data: None, - unified_code: None, - unified_message: None, - external_three_ds_authentication_attempted: None, - authentication_connector: None, - authentication_id: None, - fingerprint_id: None, - payment_method_billing_address_id: None, - charge_id: None, - client_source: None, - client_version: None, - customer_acceptance: None, - card_network: None, - shipping_cost: None, - order_tax_amount: None, - }, + } => { + let (connector_transaction_id, connector_transaction_data) = + connector_transaction_id + .map(ConnectorTransactionId::form_id_and_data) + .map(|(txn_id, txn_data)| (Some(txn_id), txn_data)) + .unwrap_or((None, None)); + Self { + status: Some(status), + payment_method_id, + modified_at: common_utils::date_time::now(), + connector_metadata, + preprocessing_step_id, + connector_transaction_id, + connector_response_reference_id, + updated_by, + connector_transaction_data, + amount: None, + net_amount: None, + currency: None, + amount_to_capture: None, + connector: None, + authentication_type: None, + payment_method: None, + error_message: None, + cancellation_reason: None, + mandate_id: None, + browser_info: None, + payment_token: None, + error_code: None, + payment_method_data: None, + payment_method_type: None, + payment_experience: None, + business_sub_label: None, + straight_through_algorithm: None, + error_reason: None, + capture_method: None, + multiple_capture_count: None, + surcharge_amount: None, + tax_amount: None, + amount_capturable: None, + merchant_connector_id: None, + authentication_data: None, + encoded_data: None, + unified_code: None, + unified_message: None, + external_three_ds_authentication_attempted: None, + authentication_connector: None, + authentication_id: None, + fingerprint_id: None, + payment_method_billing_address_id: None, + charge_id: None, + client_source: None, + client_version: None, + customer_acceptance: None, + card_network: None, + shipping_cost: None, + order_tax_amount: None, + } + } PaymentAttemptUpdate::CaptureUpdate { multiple_capture_count, updated_by, @@ -2784,6 +2875,7 @@ impl From for PaymentAttemptUpdateInternal { card_network: None, shipping_cost: None, order_tax_amount: None, + connector_transaction_data: None, }, PaymentAttemptUpdate::AmountToCaptureUpdate { status, @@ -2839,6 +2931,7 @@ impl From for PaymentAttemptUpdateInternal { card_network: None, shipping_cost: None, order_tax_amount: None, + connector_transaction_data: None, }, PaymentAttemptUpdate::ConnectorResponse { authentication_data, @@ -2847,57 +2940,65 @@ impl From for PaymentAttemptUpdateInternal { connector, updated_by, charge_id, - } => Self { - authentication_data, - encoded_data, - connector_transaction_id, - connector: connector.map(Some), - modified_at: common_utils::date_time::now(), - updated_by, - charge_id, - amount: None, - net_amount: None, - currency: None, - status: None, - amount_to_capture: None, - authentication_type: None, - payment_method: None, - error_message: None, - payment_method_id: None, - cancellation_reason: None, - mandate_id: None, - browser_info: None, - payment_token: None, - error_code: None, - connector_metadata: None, - payment_method_data: None, - payment_method_type: None, - payment_experience: None, - business_sub_label: None, - straight_through_algorithm: None, - preprocessing_step_id: None, - error_reason: None, - capture_method: None, - connector_response_reference_id: None, - multiple_capture_count: None, - surcharge_amount: None, - tax_amount: None, - amount_capturable: None, - merchant_connector_id: None, - unified_code: None, - unified_message: None, - external_three_ds_authentication_attempted: None, - authentication_connector: None, - authentication_id: None, - fingerprint_id: None, - payment_method_billing_address_id: None, - client_source: None, - client_version: None, - customer_acceptance: None, - card_network: None, - shipping_cost: None, - order_tax_amount: None, - }, + } => { + let (connector_transaction_id, connector_transaction_data) = + connector_transaction_id + .map(ConnectorTransactionId::form_id_and_data) + .map(|(txn_id, txn_data)| (Some(txn_id), txn_data)) + .unwrap_or((None, None)); + Self { + authentication_data, + encoded_data, + connector_transaction_id, + connector: connector.map(Some), + modified_at: common_utils::date_time::now(), + updated_by, + charge_id, + connector_transaction_data, + amount: None, + net_amount: None, + currency: None, + status: None, + amount_to_capture: None, + authentication_type: None, + payment_method: None, + error_message: None, + payment_method_id: None, + cancellation_reason: None, + mandate_id: None, + browser_info: None, + payment_token: None, + error_code: None, + connector_metadata: None, + payment_method_data: None, + payment_method_type: None, + payment_experience: None, + business_sub_label: None, + straight_through_algorithm: None, + preprocessing_step_id: None, + error_reason: None, + capture_method: None, + connector_response_reference_id: None, + multiple_capture_count: None, + surcharge_amount: None, + tax_amount: None, + amount_capturable: None, + merchant_connector_id: None, + unified_code: None, + unified_message: None, + external_three_ds_authentication_attempted: None, + authentication_connector: None, + authentication_id: None, + fingerprint_id: None, + payment_method_billing_address_id: None, + client_source: None, + client_version: None, + customer_acceptance: None, + card_network: None, + shipping_cost: None, + order_tax_amount: None, + } + } PaymentAttemptUpdate::IncrementalAuthorizationAmountUpdate { amount, amount_capturable, @@ -2951,6 +3052,7 @@ impl From for PaymentAttemptUpdateInternal { card_network: None, shipping_cost: None, order_tax_amount: None, + connector_transaction_data: None, }, PaymentAttemptUpdate::AuthenticationUpdate { status, @@ -3008,6 +3110,7 @@ impl From for PaymentAttemptUpdateInternal { card_network: None, shipping_cost: None, order_tax_amount: None, + connector_transaction_data: None, }, PaymentAttemptUpdate::ManualUpdate { status, @@ -3018,57 +3121,65 @@ impl From for PaymentAttemptUpdateInternal { unified_code, unified_message, connector_transaction_id, - } => Self { - status, - error_code: error_code.map(Some), - modified_at: common_utils::date_time::now(), - error_message: error_message.map(Some), - error_reason: error_reason.map(Some), - updated_by, - unified_code: unified_code.map(Some), - unified_message: unified_message.map(Some), - amount: None, - net_amount: None, - currency: None, - connector_transaction_id, - amount_to_capture: None, - connector: None, - authentication_type: None, - payment_method: None, - payment_method_id: None, - cancellation_reason: None, - mandate_id: None, - browser_info: None, - payment_token: None, - connector_metadata: None, - payment_method_data: None, - payment_method_type: None, - payment_experience: None, - business_sub_label: None, - straight_through_algorithm: None, - preprocessing_step_id: None, - capture_method: None, - connector_response_reference_id: None, - multiple_capture_count: None, - surcharge_amount: None, - tax_amount: None, - amount_capturable: None, - merchant_connector_id: None, - authentication_data: None, - encoded_data: None, - external_three_ds_authentication_attempted: None, - authentication_connector: None, - authentication_id: None, - fingerprint_id: None, - payment_method_billing_address_id: None, - charge_id: None, - client_source: None, - client_version: None, - customer_acceptance: None, - card_network: None, - shipping_cost: None, - order_tax_amount: None, - }, + } => { + let (connector_transaction_id, connector_transaction_data) = + connector_transaction_id + .map(ConnectorTransactionId::form_id_and_data) + .map(|(txn_id, txn_data)| (Some(txn_id), txn_data)) + .unwrap_or((None, None)); + Self { + status, + error_code: error_code.map(Some), + modified_at: common_utils::date_time::now(), + error_message: error_message.map(Some), + error_reason: error_reason.map(Some), + updated_by, + unified_code: unified_code.map(Some), + unified_message: unified_message.map(Some), + connector_transaction_id, + connector_transaction_data, + amount: None, + net_amount: None, + currency: None, + amount_to_capture: None, + connector: None, + authentication_type: None, + payment_method: None, + payment_method_id: None, + cancellation_reason: None, + mandate_id: None, + browser_info: None, + payment_token: None, + connector_metadata: None, + payment_method_data: None, + payment_method_type: None, + payment_experience: None, + business_sub_label: None, + straight_through_algorithm: None, + preprocessing_step_id: None, + capture_method: None, + connector_response_reference_id: None, + multiple_capture_count: None, + surcharge_amount: None, + tax_amount: None, + amount_capturable: None, + merchant_connector_id: None, + authentication_data: None, + encoded_data: None, + external_three_ds_authentication_attempted: None, + authentication_connector: None, + authentication_id: None, + fingerprint_id: None, + payment_method_billing_address_id: None, + charge_id: None, + client_source: None, + client_version: None, + customer_acceptance: None, + card_network: None, + shipping_cost: None, + order_tax_amount: None, + } + } PaymentAttemptUpdate::PostSessionTokensUpdate { updated_by, connector_metadata, @@ -3122,6 +3233,7 @@ impl From for PaymentAttemptUpdateInternal { card_network: None, shipping_cost: None, order_tax_amount: None, + connector_transaction_data: None, }, } } diff --git a/crates/diesel_models/src/query/capture.rs b/crates/diesel_models/src/query/capture.rs index e194dc9f64..7a32e41096 100644 --- a/crates/diesel_models/src/query/capture.rs +++ b/crates/diesel_models/src/query/capture.rs @@ -1,3 +1,4 @@ +use common_utils::types::ConnectorTransactionIdTrait; use diesel::{associations::HasTable, BoolExpressionMethods, ExpressionMethods}; use super::generics; @@ -67,3 +68,22 @@ impl Capture { .await } } + +impl ConnectorTransactionIdTrait for Capture { + fn get_optional_connector_transaction_id(&self) -> Option<&String> { + match self + .connector_capture_id + .as_ref() + .map(|capture_id| capture_id.get_txn_id(self.connector_capture_data.as_ref())) + .transpose() + { + Ok(capture_id) => capture_id, + + // In case hashed data is missing from DB, use the hashed ID as connector transaction ID + Err(_) => self + .connector_capture_id + .as_ref() + .map(|txn_id| txn_id.get_id()), + } + } +} diff --git a/crates/diesel_models/src/refund.rs b/crates/diesel_models/src/refund.rs index 42b0ffa620..9e850bc9f1 100644 --- a/crates/diesel_models/src/refund.rs +++ b/crates/diesel_models/src/refund.rs @@ -1,6 +1,6 @@ use common_utils::{ pii, - types::{ChargeRefunds, MinorUnit}, + types::{ChargeRefunds, ConnectorTransactionId, ConnectorTransactionIdTrait, MinorUnit}, }; use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable}; use serde::{Deserialize, Serialize}; @@ -25,9 +25,9 @@ pub struct Refund { pub refund_id: String, //merchant_reference id pub payment_id: common_utils::id_type::PaymentId, pub merchant_id: common_utils::id_type::MerchantId, - pub connector_transaction_id: String, + pub connector_transaction_id: ConnectorTransactionId, pub connector: String, - pub connector_refund_id: Option, + pub connector_refund_id: Option, pub external_reference_id: Option, pub refund_type: storage_enums::RefundType, pub total_amount: MinorUnit, @@ -51,6 +51,8 @@ pub struct Refund { pub merchant_connector_id: Option, pub charges: Option, pub organization_id: common_utils::id_type::OrganizationId, + pub connector_refund_data: Option, + pub connector_transaction_data: Option, } #[derive( @@ -71,9 +73,9 @@ pub struct RefundNew { pub merchant_id: common_utils::id_type::MerchantId, pub internal_reference_id: String, pub external_reference_id: Option, - pub connector_transaction_id: String, + pub connector_transaction_id: ConnectorTransactionId, pub connector: String, - pub connector_refund_id: Option, + pub connector_refund_id: Option, pub refund_type: storage_enums::RefundType, pub total_amount: MinorUnit, pub currency: storage_enums::Currency, @@ -94,17 +96,20 @@ pub struct RefundNew { pub merchant_connector_id: Option, pub charges: Option, pub organization_id: common_utils::id_type::OrganizationId, + pub connector_refund_data: Option, + pub connector_transaction_data: Option, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub enum RefundUpdate { Update { - connector_refund_id: String, + connector_refund_id: ConnectorTransactionId, refund_status: storage_enums::RefundStatus, sent_to_gateway: bool, refund_error_message: Option, refund_arn: String, updated_by: String, + connector_refund_data: Option, }, MetadataAndReasonUpdate { metadata: Option, @@ -112,17 +117,19 @@ pub enum RefundUpdate { updated_by: String, }, StatusUpdate { - connector_refund_id: Option, + connector_refund_id: Option, sent_to_gateway: bool, refund_status: storage_enums::RefundStatus, updated_by: String, + connector_refund_data: Option, }, ErrorUpdate { refund_status: Option, refund_error_message: Option, refund_error_code: Option, updated_by: String, - connector_refund_id: Option, + connector_refund_id: Option, + connector_refund_data: Option, }, ManualUpdate { refund_status: Option, @@ -135,7 +142,7 @@ pub enum RefundUpdate { #[derive(Clone, Debug, AsChangeset, router_derive::DebugAsDisplay)] #[diesel(table_name = refund)] pub struct RefundUpdateInternal { - connector_refund_id: Option, + connector_refund_id: Option, refund_status: Option, sent_to_gateway: Option, refund_error_message: Option, @@ -145,6 +152,7 @@ pub struct RefundUpdateInternal { refund_error_code: Option, updated_by: String, modified_at: PrimitiveDateTime, + connector_refund_data: Option, } impl RefundUpdateInternal { @@ -160,6 +168,7 @@ impl RefundUpdateInternal { refund_error_code: self.refund_error_code, updated_by: self.updated_by, modified_at: self.modified_at, + connector_refund_data: self.connector_refund_data, ..source } } @@ -175,6 +184,7 @@ impl From for RefundUpdateInternal { refund_error_message, refund_arn, updated_by, + connector_refund_data, } => Self { connector_refund_id: Some(connector_refund_id), refund_status: Some(refund_status), @@ -182,6 +192,7 @@ impl From for RefundUpdateInternal { refund_error_message, refund_arn: Some(refund_arn), updated_by, + connector_refund_data, metadata: None, refund_reason: None, refund_error_code: None, @@ -202,17 +213,20 @@ impl From for RefundUpdateInternal { refund_arn: None, refund_error_code: None, modified_at: common_utils::date_time::now(), + connector_refund_data: None, }, RefundUpdate::StatusUpdate { connector_refund_id, sent_to_gateway, refund_status, updated_by, + connector_refund_data, } => Self { connector_refund_id, sent_to_gateway: Some(sent_to_gateway), refund_status: Some(refund_status), updated_by, + connector_refund_data, refund_error_message: None, refund_arn: None, metadata: None, @@ -226,12 +240,14 @@ impl From for RefundUpdateInternal { refund_error_code, updated_by, connector_refund_id, + connector_refund_data, } => Self { refund_status, refund_error_message, refund_error_code, updated_by, connector_refund_id, + connector_refund_data, sent_to_gateway: None, refund_arn: None, metadata: None, @@ -254,6 +270,7 @@ impl From for RefundUpdateInternal { metadata: None, refund_reason: None, modified_at: common_utils::date_time::now(), + connector_refund_data: None, }, } } @@ -272,6 +289,7 @@ impl RefundUpdate { refund_error_code, updated_by, modified_at: _, + connector_refund_data, } = self.into(); Refund { connector_refund_id: connector_refund_id.or(source.connector_refund_id), @@ -284,6 +302,7 @@ impl RefundUpdate { refund_reason: refund_reason.or(source.refund_reason), updated_by, modified_at: common_utils::date_time::now(), + connector_refund_data: connector_refund_data.or(source.connector_refund_data), ..source } } @@ -292,9 +311,10 @@ impl RefundUpdate { #[derive(Debug, Eq, PartialEq, Deserialize, Serialize)] pub struct RefundCoreWorkflow { pub refund_internal_reference_id: String, - pub connector_transaction_id: String, + pub connector_transaction_id: ConnectorTransactionId, pub merchant_id: common_utils::id_type::MerchantId, pub payment_id: common_utils::id_type::PaymentId, + pub connector_transaction_data: Option, } impl common_utils::events::ApiEventMetric for Refund { @@ -306,6 +326,37 @@ impl common_utils::events::ApiEventMetric for Refund { } } +impl ConnectorTransactionIdTrait for Refund { + fn get_optional_connector_refund_id(&self) -> Option<&String> { + match self + .connector_refund_id + .as_ref() + .map(|refund_id| refund_id.get_txn_id(self.connector_refund_data.as_ref())) + .transpose() + { + Ok(refund_id) => refund_id, + + // In case hashed data is missing from DB, use the hashed ID as connector transaction ID + Err(_) => self + .connector_refund_id + .as_ref() + .map(|txn_id| txn_id.get_id()), + } + } + + fn get_connector_transaction_id(&self) -> &String { + match self + .connector_transaction_id + .get_txn_id(self.connector_transaction_data.as_ref()) + { + Ok(txn_id) => txn_id, + + // In case hashed data is missing from DB, use the hashed ID as connector transaction ID + Err(_) => self.connector_transaction_id.get_id(), + } + } +} + mod tests { #[test] fn test_backwards_compatibility() { @@ -336,7 +387,8 @@ mod tests { "profile_id": null, "updated_by": "admin", "merchant_connector_id": null, - "charges": null + "charges": null, + "connector_transaction_data": null }"#; let deserialized = serde_json::from_str::(serialized_refund); diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs index a9e0b54260..5cd2abd359 100644 --- a/crates/diesel_models/src/schema.rs +++ b/crates/diesel_models/src/schema.rs @@ -248,6 +248,8 @@ diesel::table! { capture_sequence -> Int2, #[max_length = 128] connector_response_reference_id -> Nullable, + #[max_length = 512] + connector_capture_data -> Nullable, } } @@ -846,6 +848,8 @@ diesel::table! { card_network -> Nullable, shipping_cost -> Nullable, order_tax_amount -> Nullable, + #[max_length = 512] + connector_transaction_data -> Nullable, } } @@ -1183,6 +1187,10 @@ diesel::table! { charges -> Nullable, #[max_length = 32] organization_id -> Varchar, + #[max_length = 512] + connector_refund_data -> Nullable, + #[max_length = 512] + connector_transaction_data -> Nullable, } } diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs index 9d1a47e4e0..d662603981 100644 --- a/crates/diesel_models/src/schema_v2.rs +++ b/crates/diesel_models/src/schema_v2.rs @@ -255,6 +255,8 @@ diesel::table! { capture_sequence -> Int2, #[max_length = 128] connector_response_reference_id -> Nullable, + #[max_length = 512] + connector_capture_data -> Nullable, } } @@ -813,6 +815,8 @@ diesel::table! { #[max_length = 128] external_reference_id -> Nullable, tax_on_surcharge -> Nullable, + #[max_length = 512] + connector_payment_data -> Nullable, #[max_length = 64] id -> Varchar, shipping_cost -> Nullable, @@ -1130,6 +1134,10 @@ diesel::table! { charges -> Nullable, #[max_length = 32] organization_id -> Varchar, + #[max_length = 512] + connector_refund_data -> Nullable, + #[max_length = 512] + connector_transaction_data -> Nullable, } } diff --git a/crates/diesel_models/src/user/sample_data.rs b/crates/diesel_models/src/user/sample_data.rs index a354e4a02a..db30d02bd7 100644 --- a/crates/diesel_models/src/user/sample_data.rs +++ b/crates/diesel_models/src/user/sample_data.rs @@ -2,7 +2,7 @@ use common_enums::{ AttemptStatus, AuthenticationType, CaptureMethod, Currency, PaymentExperience, PaymentMethod, PaymentMethodType, }; -use common_utils::types::MinorUnit; +use common_utils::types::{ConnectorTransactionId, MinorUnit}; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; @@ -179,7 +179,7 @@ pub struct PaymentAttemptBatchNew { pub mandate_details: Option, pub error_reason: Option, pub connector_response_reference_id: Option, - pub connector_transaction_id: Option, + pub connector_transaction_id: Option, pub multiple_capture_count: Option, pub amount_capturable: MinorUnit, pub updated_by: String, @@ -203,6 +203,7 @@ pub struct PaymentAttemptBatchNew { pub organization_id: common_utils::id_type::OrganizationId, pub shipping_cost: Option, pub order_tax_amount: Option, + pub connector_transaction_data: Option, } #[cfg(feature = "v1")] diff --git a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs index ea65cfff8b..691037c282 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs @@ -6,7 +6,7 @@ use common_utils::{ id_type, pii, types::{ keymanager::{self, KeyManagerState}, - MinorUnit, + ConnectorTransactionId, ConnectorTransactionIdTrait, MinorUnit, }, }; use diesel_models::{ @@ -1211,6 +1211,11 @@ impl behaviour::Conversion for PaymentAttempt { .and_then(|card| card.get("card_network")) .and_then(|network| network.as_str()) .map(|network| network.to_string()); + let (connector_transaction_id, connector_transaction_data) = self + .connector_transaction_id + .map(ConnectorTransactionId::form_id_and_data) + .map(|(txn_id, txn_data)| (Some(txn_id), txn_data)) + .unwrap_or((None, None)); Ok(DieselPaymentAttempt { payment_id: self.payment_id, merchant_id: self.merchant_id, @@ -1226,7 +1231,7 @@ impl behaviour::Conversion for PaymentAttempt { tax_amount: self.net_amount.get_tax_on_surcharge(), payment_method_id: self.payment_method_id, payment_method: self.payment_method, - connector_transaction_id: self.connector_transaction_id, + connector_transaction_id, capture_method: self.capture_method, capture_on: self.capture_on, confirm: self.confirm, @@ -1273,6 +1278,7 @@ impl behaviour::Conversion for PaymentAttempt { profile_id: self.profile_id, organization_id: self.organization_id, card_network, + connector_transaction_data, order_tax_amount: self.net_amount.get_order_tax_amount(), shipping_cost: self.net_amount.get_shipping_cost(), }) @@ -1288,6 +1294,9 @@ impl behaviour::Conversion for PaymentAttempt { Self: Sized, { async { + let connector_transaction_id = storage_model + .get_optional_connector_transaction_id() + .cloned(); Ok::>(Self { payment_id: storage_model.payment_id, merchant_id: storage_model.merchant_id, @@ -1307,7 +1316,7 @@ impl behaviour::Conversion for PaymentAttempt { offer_amount: storage_model.offer_amount, payment_method_id: storage_model.payment_method_id, payment_method: storage_model.payment_method, - connector_transaction_id: storage_model.connector_transaction_id, + connector_transaction_id, capture_method: storage_model.capture_method, capture_on: storage_model.capture_on, confirm: storage_model.confirm, @@ -1510,6 +1519,11 @@ impl behaviour::Conversion for PaymentAttempt { connector, } = self; + let (connector_payment_id, connector_payment_data) = connector_payment_id + .map(ConnectorTransactionId::form_id_and_data) + .map(|(txn_id, txn_data)| (Some(txn_id), txn_data)) + .unwrap_or((None, None)); + Ok(DieselPaymentAttempt { payment_id, merchant_id, @@ -1565,6 +1579,7 @@ impl behaviour::Conversion for PaymentAttempt { authentication_applied, external_reference_id, connector, + connector_payment_data, }) } @@ -1578,6 +1593,9 @@ impl behaviour::Conversion for PaymentAttempt { Self: Sized, { async { + let connector_payment_id = storage_model + .get_optional_connector_transaction_id() + .cloned(); Ok::>(Self { payment_id: storage_model.payment_id, merchant_id: storage_model.merchant_id, @@ -1589,7 +1607,7 @@ impl behaviour::Conversion for PaymentAttempt { surcharge_amount: storage_model.surcharge_amount, payment_method_id: storage_model.payment_method_id, payment_method_type: storage_model.payment_method_type_v2, - connector_payment_id: storage_model.connector_payment_id, + connector_payment_id, confirm: storage_model.confirm, authentication_type: storage_model.authentication_type, created_at: storage_model.created_at, diff --git a/crates/hyperswitch_domain_models/src/router_request_types.rs b/crates/hyperswitch_domain_models/src/router_request_types.rs index 704387ad46..fb4c0fd080 100644 --- a/crates/hyperswitch_domain_models/src/router_request_types.rs +++ b/crates/hyperswitch_domain_models/src/router_request_types.rs @@ -118,6 +118,7 @@ pub struct PaymentsCaptureData { pub browser_info: Option, pub metadata: Option, // This metadata is used to store the metadata shared during the payment intent request. + pub capture_method: Option, // New amount for amount frame work pub minor_payment_amount: MinorUnit, diff --git a/crates/kgraph_utils/src/transformers.rs b/crates/kgraph_utils/src/transformers.rs index 1a340aa91d..3aaeb0586d 100644 --- a/crates/kgraph_utils/src/transformers.rs +++ b/crates/kgraph_utils/src/transformers.rs @@ -334,6 +334,7 @@ impl IntoDirValue for api_enums::Currency { fn into_dir_value(self) -> Result { match self { Self::AED => Ok(dirval!(PaymentCurrency = AED)), + Self::AFN => Ok(dirval!(PaymentCurrency = AFN)), Self::ALL => Ok(dirval!(PaymentCurrency = ALL)), Self::AMD => Ok(dirval!(PaymentCurrency = AMD)), Self::ANG => Ok(dirval!(PaymentCurrency = ANG)), @@ -353,10 +354,12 @@ impl IntoDirValue for api_enums::Currency { Self::BOB => Ok(dirval!(PaymentCurrency = BOB)), Self::BRL => Ok(dirval!(PaymentCurrency = BRL)), Self::BSD => Ok(dirval!(PaymentCurrency = BSD)), + Self::BTN => Ok(dirval!(PaymentCurrency = BTN)), Self::BWP => Ok(dirval!(PaymentCurrency = BWP)), Self::BYN => Ok(dirval!(PaymentCurrency = BYN)), Self::BZD => Ok(dirval!(PaymentCurrency = BZD)), Self::CAD => Ok(dirval!(PaymentCurrency = CAD)), + Self::CDF => Ok(dirval!(PaymentCurrency = CDF)), Self::CHF => Ok(dirval!(PaymentCurrency = CHF)), Self::CLP => Ok(dirval!(PaymentCurrency = CLP)), Self::CNY => Ok(dirval!(PaymentCurrency = CNY)), @@ -370,6 +373,7 @@ impl IntoDirValue for api_enums::Currency { Self::DOP => Ok(dirval!(PaymentCurrency = DOP)), Self::DZD => Ok(dirval!(PaymentCurrency = DZD)), Self::EGP => Ok(dirval!(PaymentCurrency = EGP)), + Self::ERN => Ok(dirval!(PaymentCurrency = ERN)), Self::ETB => Ok(dirval!(PaymentCurrency = ETB)), Self::EUR => Ok(dirval!(PaymentCurrency = EUR)), Self::FJD => Ok(dirval!(PaymentCurrency = FJD)), @@ -391,6 +395,8 @@ impl IntoDirValue for api_enums::Currency { Self::ILS => Ok(dirval!(PaymentCurrency = ILS)), Self::INR => Ok(dirval!(PaymentCurrency = INR)), Self::IQD => Ok(dirval!(PaymentCurrency = IQD)), + Self::IRR => Ok(dirval!(PaymentCurrency = IRR)), + Self::ISK => Ok(dirval!(PaymentCurrency = ISK)), Self::JMD => Ok(dirval!(PaymentCurrency = JMD)), Self::JOD => Ok(dirval!(PaymentCurrency = JOD)), Self::JPY => Ok(dirval!(PaymentCurrency = JPY)), @@ -398,6 +404,7 @@ impl IntoDirValue for api_enums::Currency { Self::KGS => Ok(dirval!(PaymentCurrency = KGS)), Self::KHR => Ok(dirval!(PaymentCurrency = KHR)), Self::KMF => Ok(dirval!(PaymentCurrency = KMF)), + Self::KPW => Ok(dirval!(PaymentCurrency = KPW)), Self::KRW => Ok(dirval!(PaymentCurrency = KRW)), Self::KWD => Ok(dirval!(PaymentCurrency = KWD)), Self::KYD => Ok(dirval!(PaymentCurrency = KYD)), @@ -444,6 +451,7 @@ impl IntoDirValue for api_enums::Currency { Self::SAR => Ok(dirval!(PaymentCurrency = SAR)), Self::SBD => Ok(dirval!(PaymentCurrency = SBD)), Self::SCR => Ok(dirval!(PaymentCurrency = SCR)), + Self::SDG => Ok(dirval!(PaymentCurrency = SDG)), Self::SEK => Ok(dirval!(PaymentCurrency = SEK)), Self::SGD => Ok(dirval!(PaymentCurrency = SGD)), Self::SHP => Ok(dirval!(PaymentCurrency = SHP)), @@ -454,8 +462,11 @@ impl IntoDirValue for api_enums::Currency { Self::SSP => Ok(dirval!(PaymentCurrency = SSP)), Self::STN => Ok(dirval!(PaymentCurrency = STN)), Self::SVC => Ok(dirval!(PaymentCurrency = SVC)), + Self::SYP => Ok(dirval!(PaymentCurrency = SYP)), Self::SZL => Ok(dirval!(PaymentCurrency = SZL)), Self::THB => Ok(dirval!(PaymentCurrency = THB)), + Self::TJS => Ok(dirval!(PaymentCurrency = TJS)), + Self::TMT => Ok(dirval!(PaymentCurrency = TMT)), Self::TND => Ok(dirval!(PaymentCurrency = TND)), Self::TOP => Ok(dirval!(PaymentCurrency = TOP)), Self::TRY => Ok(dirval!(PaymentCurrency = TRY)), @@ -478,6 +489,7 @@ impl IntoDirValue for api_enums::Currency { Self::YER => Ok(dirval!(PaymentCurrency = YER)), Self::ZAR => Ok(dirval!(PaymentCurrency = ZAR)), Self::ZMW => Ok(dirval!(PaymentCurrency = ZMW)), + Self::ZWL => Ok(dirval!(PaymentCurrency = ZWL)), } } } diff --git a/crates/router/src/connector/worldpay.rs b/crates/router/src/connector/worldpay.rs index 33c9393ced..b5469f12c1 100644 --- a/crates/router/src/connector/worldpay.rs +++ b/crates/router/src/connector/worldpay.rs @@ -2,9 +2,12 @@ mod requests; mod response; pub mod transformers; -use std::fmt::Debug; - -use common_utils::{crypto, ext_traits::ByteSliceExt, request::RequestContent}; +use common_utils::{ + crypto, + ext_traits::ByteSliceExt, + request::RequestContent, + types::{AmountConvertor, MinorUnit, MinorUnitForConnector}, +}; use diesel_models::enums; use error_stack::ResultExt; use transformers as worldpay; @@ -30,8 +33,18 @@ use crate::{ utils::BytesExt, }; -#[derive(Debug, Clone)] -pub struct Worldpay; +#[derive(Clone)] +pub struct Worldpay { + amount_converter: &'static (dyn AmountConvertor + Sync), +} + +impl Worldpay { + pub const fn new() -> &'static Self { + &Self { + amount_converter: &MinorUnitForConnector, + } + } +} impl ConnectorCommonExt for Worldpay where @@ -42,10 +55,16 @@ where req: &types::RouterData, _connectors: &settings::Connectors, ) -> CustomResult)>, errors::ConnectorError> { - let mut headers = vec![( - headers::CONTENT_TYPE.to_string(), - self.get_content_type().to_string().into(), - )]; + let mut headers = vec![ + ( + headers::ACCEPT.to_string(), + self.get_content_type().to_string().into(), + ), + ( + headers::CONTENT_TYPE.to_string(), + self.get_content_type().to_string().into(), + ), + ]; let mut api_key = self.get_auth_header(&req.connector_auth_type)?; headers.append(&mut api_key); Ok(headers) @@ -62,7 +81,7 @@ impl ConnectorCommon for Worldpay { } fn common_get_content_type(&self) -> &'static str { - "application/vnd.worldpay.payments-v6+json" + "application/vnd.worldpay.payments-v7+json" } fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { @@ -86,10 +105,13 @@ impl ConnectorCommon for Worldpay { res: Response, event_builder: Option<&mut ConnectorEvent>, ) -> CustomResult { - let response: WorldpayErrorResponse = res - .response - .parse_struct("WorldpayErrorResponse") - .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + let response = if !res.response.is_empty() { + res.response + .parse_struct("WorldpayErrorResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)? + } else { + WorldpayErrorResponse::default(res.status_code) + }; event_builder.map(|i| i.set_error_response_body(&response)); router_env::logger::info!(connector_response=?response); @@ -183,9 +205,8 @@ impl ConnectorIntegration CustomResult { let connector_payment_id = req.request.connector_transaction_id.clone(); Ok(format!( - "{}payments/settlements/{}", + "{}payments/authorizations/cancellations/{connector_payment_id}", self.base_url(connectors), - connector_payment_id )) } @@ -328,8 +349,22 @@ impl ConnectorIntegration attempt_status, + _ => enums::AttemptStatus::from(&worldpay_status), + }; + Ok(types::PaymentsSyncRouterData { - status: enums::AttemptStatus::from(response.last_event), + status, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: data.request.connector_transaction_id.clone(), redirection_data: None, @@ -361,6 +396,33 @@ impl ConnectorIntegration CustomResult { + let connector_payment_id = req.request.connector_transaction_id.clone(); + Ok(format!( + "{}payments/settlements/partials/{}", + self.base_url(connectors), + connector_payment_id + )) + } + + fn get_request_body( + &self, + req: &types::PaymentsCaptureRouterData, + _connectors: &settings::Connectors, + ) -> CustomResult { + let amount_to_capture = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_amount_to_capture, + req.request.currency, + )?; + let connector_req = WorldpayPartialRequest::try_from((req, amount_to_capture))?; + Ok(RequestContent::Json(Box::new(connector_req))) + } + fn build_request( &self, req: &types::PaymentsCaptureRouterData, @@ -374,6 +436,9 @@ impl ConnectorIntegration CustomResult { - let connector_payment_id = req.request.connector_transaction_id.clone(); - Ok(format!( - "{}payments/settlements/{}", - self.base_url(connectors), - connector_payment_id - )) - } - fn get_error_response( &self, res: Response, @@ -463,7 +515,7 @@ impl ConnectorIntegration CustomResult { Ok(format!( - "{}payments/authorizations", + "{}cardPayments/customerInitiatedTransactions", self.base_url(connectors) )) } @@ -476,10 +528,13 @@ impl ConnectorIntegration CustomResult { - let connector_req = WorldpayRefundRequest::try_from(req)?; + let amount_to_refund = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_refund_amount, + req.request.currency, + )?; + let connector_req = WorldpayPartialRequest::try_from((req, amount_to_refund))?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -613,7 +673,7 @@ impl ConnectorIntegration { - Ok(api::IncomingWebhookEvent::PaymentIntentSuccess) + EventType::Authorized => { + Ok(api::IncomingWebhookEvent::PaymentIntentAuthorizationSuccess) } - EventType::Error | EventType::Expired => { + EventType::SentForSettlement => Ok(api::IncomingWebhookEvent::PaymentIntentProcessing), + EventType::Settled => Ok(api::IncomingWebhookEvent::PaymentIntentSuccess), + EventType::Error | EventType::Expired | EventType::SettlementFailed => { Ok(api::IncomingWebhookEvent::PaymentIntentFailure) } EventType::Unknown - | EventType::Authorized + | EventType::SentForAuthorization | EventType::Cancelled | EventType::Refused | EventType::Refunded | EventType::SentForRefund - | EventType::CaptureFailed | EventType::RefundFailed => Ok(api::IncomingWebhookEvent::EventNotSupported), } } diff --git a/crates/router/src/connector/worldpay/requests.rs b/crates/router/src/connector/worldpay/requests.rs index 5fb5d75d94..301ae64946 100644 --- a/crates/router/src/connector/worldpay/requests.rs +++ b/crates/router/src/connector/worldpay/requests.rs @@ -4,29 +4,28 @@ use serde::{Deserialize, Serialize}; #[serde(rename_all = "camelCase")] pub struct BillingAddress { #[serde(skip_serializing_if = "Option::is_none")] - pub city: Option, + pub address1: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub address2: Option>, - pub postal_code: Secret, - #[serde(skip_serializing_if = "Option::is_none")] - pub state: Option, #[serde(skip_serializing_if = "Option::is_none")] pub address3: Option>, - pub country_code: common_enums::CountryAlpha2, #[serde(skip_serializing_if = "Option::is_none")] - pub address1: Option>, + pub city: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub state: Option>, + pub postal_code: Secret, + pub country_code: common_enums::CountryAlpha2, } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub struct WorldpayPaymentsRequest { - #[serde(skip_serializing_if = "Option::is_none")] - pub channel: Option, + pub transaction_reference: String, + pub merchant: Merchant, pub instruction: Instruction, + pub channel: Channel, #[serde(skip_serializing_if = "Option::is_none")] pub customer: Option, - pub merchant: Merchant, - pub transaction_reference: String, } #[derive( @@ -35,6 +34,7 @@ pub struct WorldpayPaymentsRequest { #[serde(rename_all = "camelCase")] pub enum Channel { #[default] + Ecom, Moto, } @@ -101,11 +101,18 @@ pub struct NetworkToken { #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Instruction { + pub request_auto_settlement: RequestAutoSettlement, + pub narrative: InstructionNarrative, + pub value: PaymentValue, + pub payment_instrument: PaymentInstrument, #[serde(skip_serializing_if = "Option::is_none")] pub debt_repayment: Option, - pub value: PaymentValue, - pub narrative: InstructionNarrative, - pub payment_instrument: PaymentInstrument, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RequestAutoSettlement { + pub enabled: bool, } #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] @@ -143,16 +150,15 @@ pub enum PaymentType { #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct CardPayment { - #[serde(skip_serializing_if = "Option::is_none")] - pub billing_address: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub card_holder_name: Option>, - pub card_expiry_date: CardExpiryDate, - #[serde(skip_serializing_if = "Option::is_none")] - pub cvc: Option>, #[serde(rename = "type")] pub payment_type: PaymentType, pub card_number: cards::CardNumber, + pub expiry_date: ExpiryDate, + #[serde(skip_serializing_if = "Option::is_none")] + pub card_holder_name: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub billing_address: Option, + pub cvc: Secret, } #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] @@ -174,7 +180,7 @@ pub struct WalletPayment { } #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] -pub struct CardExpiryDate { +pub struct ExpiryDate { pub month: Secret, pub year: Secret, } @@ -182,13 +188,13 @@ pub struct CardExpiryDate { #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] pub struct PaymentValue { pub amount: i64, - pub currency: String, + pub currency: api_models::enums::Currency, } #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Merchant { - pub entity: String, + pub entity: Secret, #[serde(skip_serializing_if = "Option::is_none")] pub mcc: Option, #[serde(skip_serializing_if = "Option::is_none")] @@ -220,7 +226,7 @@ pub struct SubMerchant { } #[derive(Default, Debug, Serialize)] -pub struct WorldpayRefundRequest { +pub struct WorldpayPartialRequest { pub value: PaymentValue, pub reference: String, } diff --git a/crates/router/src/connector/worldpay/response.rs b/crates/router/src/connector/worldpay/response.rs index 14ccbc1fac..dbd596e2e2 100644 --- a/crates/router/src/connector/worldpay/response.rs +++ b/crates/router/src/connector/worldpay/response.rs @@ -1,33 +1,43 @@ use masking::Secret; use serde::{Deserialize, Serialize}; +use super::requests::*; use crate::{core::errors, types, types::transformers::ForeignTryFrom}; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct WorldpayPaymentsResponse { - #[serde(skip_serializing_if = "Option::is_none")] - pub exemption: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub issuer: Option, - pub outcome: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub description: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub payment_instrument: Option, + pub outcome: Option, /// Any risk factors which have been identified for the authorization. This section will not appear if no risks are identified. #[serde(skip_serializing_if = "Option::is_none")] pub risk_factors: Option>, #[serde(skip_serializing_if = "Option::is_none")] + pub issuer: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub scheme: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub payment_instrument: Option, #[serde(rename = "_links", skip_serializing_if = "Option::is_none")] pub links: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub enum Outcome { +pub enum PaymentOutcome { + #[serde(alias = "authorized", alias = "Authorized")] Authorized, Refused, + #[serde(alias = "Sent for Settlement")] + SentForSettlement, + #[serde(alias = "Sent for Refund")] + SentForRefund, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub enum RefundOutcome { + #[serde(alias = "Sent for Refund")] + SentForRefund, } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -41,31 +51,57 @@ pub struct WorldpayEventResponse { #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub enum EventType { + SentForAuthorization, + #[serde(alias = "Authorized")] Authorized, - Cancelled, - Charged, - SentForRefund, - RefundFailed, - Refused, - Refunded, - Error, + #[serde(alias = "Sent for Settlement")] SentForSettlement, + Settled, + SettlementFailed, + Cancelled, + Error, Expired, - CaptureFailed, + Refused, + #[serde(alias = "Sent for Refund")] + SentForRefund, + Refunded, + RefundFailed, #[serde(other)] Unknown, } -#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] -pub struct Exemption { - pub result: String, - pub reason: String, -} - #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] pub struct PaymentLinks { - #[serde(rename = "payments:events", skip_serializing_if = "Option::is_none")] + #[serde( + rename = "cardPayments:events", + skip_serializing_if = "Option::is_none" + )] pub events: Option, + #[serde( + rename = "cardPayments:settle", + skip_serializing_if = "Option::is_none" + )] + pub settle_event: Option, + #[serde( + rename = "cardPayments:partialSettle", + skip_serializing_if = "Option::is_none" + )] + pub partial_settle_event: Option, + #[serde( + rename = "cardPayments:refund", + skip_serializing_if = "Option::is_none" + )] + pub refund_event: Option, + #[serde( + rename = "cardPayments:partialRefund", + skip_serializing_if = "Option::is_none" + )] + pub partial_refund_event: Option, + #[serde( + rename = "cardPayments:reverse", + skip_serializing_if = "Option::is_none" + )] + pub reverse_event: Option, } #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] @@ -116,12 +152,6 @@ impl ForeignTryFrom> for types::ResponseId { } } -impl Exemption { - pub fn new(result: String, reason: String) -> Self { - Self { result, reason } - } -} - #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Issuer { @@ -137,103 +167,32 @@ impl Issuer { } #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct PaymentsResPaymentInstrument { #[serde(rename = "type", skip_serializing_if = "Option::is_none")] - pub risk_type: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub card: Option, + pub payment_instrument_type: Option, + pub card_bin: Option, + pub last_four: Option, + pub category: Option, + pub expiry_date: Option, + pub card_brand: Option, + pub funding_type: Option, + pub issuer_name: Option, + pub payment_account_reference: Option, } impl PaymentsResPaymentInstrument { pub fn new() -> Self { Self { - risk_type: None, - card: None, - } - } -} - -#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct PaymentInstrumentCard { - #[serde(skip_serializing_if = "Option::is_none")] - pub number: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub issuer: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub payment_account_reference: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub country_code: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub funding_type: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub brand: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub expiry_date: Option, -} - -impl PaymentInstrumentCard { - pub fn new() -> Self { - Self { - number: None, - issuer: None, - payment_account_reference: None, - country_code: None, - funding_type: None, - brand: None, + payment_instrument_type: None, + card_bin: None, + last_four: None, + category: None, expiry_date: None, - } - } -} - -#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct PaymentInstrumentCardExpiryDate { - #[serde(skip_serializing_if = "Option::is_none")] - pub month: Option>, - #[serde(skip_serializing_if = "Option::is_none")] - pub year: Option>, -} - -impl PaymentInstrumentCardExpiryDate { - pub fn new() -> Self { - Self { - month: None, - year: None, - } - } -} - -#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct PaymentInstrumentCardIssuer { - #[serde(skip_serializing_if = "Option::is_none")] - pub name: Option, -} - -impl PaymentInstrumentCardIssuer { - pub fn new() -> Self { - Self { name: None } - } -} - -#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct PaymentInstrumentCardNumber { - #[serde(skip_serializing_if = "Option::is_none")] - pub bin: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub last4_digits: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub dpan: Option, -} - -impl PaymentInstrumentCardNumber { - pub fn new() -> Self { - Self { - bin: None, - last4_digits: None, - dpan: None, + card_brand: None, + funding_type: None, + issuer_name: None, + payment_account_reference: None, } } } @@ -282,15 +241,12 @@ pub enum Detail { #[derive( Clone, Copy, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, )] +#[serde(rename_all = "camelCase")] pub enum Risk { #[default] - #[serde(rename = "not_checked")] NotChecked, - #[serde(rename = "not_matched")] NotMatched, - #[serde(rename = "not_supplied")] NotSupplied, - #[serde(rename = "verificationFailed")] VerificationFailed, } @@ -305,7 +261,7 @@ impl PaymentsResponseScheme { } } -#[derive(Default, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct WorldpayErrorResponse { pub error_name: String, @@ -313,6 +269,23 @@ pub struct WorldpayErrorResponse { pub validation_errors: Option, } +impl WorldpayErrorResponse { + pub fn default(status_code: u16) -> Self { + match status_code { + code @ 404 => Self { + error_name: format!("{} Not found", code), + message: "Resource not found".to_string(), + validation_errors: None, + }, + code => Self { + error_name: code.to_string(), + message: "Unknown error".to_string(), + validation_errors: None, + }, + } + } +} + #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct WorldpayWebhookTransactionId { diff --git a/crates/router/src/connector/worldpay/transformers.rs b/crates/router/src/connector/worldpay/transformers.rs index dca6f82adc..c5398b83a8 100644 --- a/crates/router/src/connector/worldpay/transformers.rs +++ b/crates/router/src/connector/worldpay/transformers.rs @@ -1,6 +1,9 @@ +use api_models::payments::Address; use base64::Engine; -use common_utils::errors::CustomResult; +use common_utils::{errors::CustomResult, ext_traits::OptionExt, types::MinorUnit}; use diesel_models::enums; +use error_stack::ResultExt; +use hyperswitch_connectors::utils::RouterData; use masking::{PeekInterface, Secret}; use serde::Serialize; @@ -23,36 +26,61 @@ impl TryFrom<( &types::api::CurrencyUnit, types::storage::enums::Currency, - i64, + MinorUnit, T, )> for WorldpayRouterData { type Error = error_stack::Report; fn try_from( - (_currency_unit, _currency, amount, item): ( + (_currency_unit, _currency, minor_amount, item): ( &types::api::CurrencyUnit, types::storage::enums::Currency, - i64, + MinorUnit, T, ), ) -> Result { Ok(Self { - amount, + amount: minor_amount.get_amount_as_i64(), router_data: item, }) } } fn fetch_payment_instrument( payment_method: domain::PaymentMethodData, + billing_address: Option<&Address>, ) -> CustomResult { match payment_method { domain::PaymentMethodData::Card(card) => Ok(PaymentInstrument::Card(CardPayment { - card_expiry_date: CardExpiryDate { + payment_type: PaymentType::Card, + expiry_date: ExpiryDate { month: utils::CardData::get_expiry_month_as_i8(&card)?, year: utils::CardData::get_expiry_year_as_i32(&card)?, }, card_number: card.card_number, - ..CardPayment::default() + cvc: card.card_cvc, + card_holder_name: card.nick_name, + billing_address: if let Some(address) = + billing_address.and_then(|addr| addr.address.clone()) + { + Some(BillingAddress { + address1: address.line1, + address2: address.line2, + address3: address.line3, + city: address.city, + state: address.state, + postal_code: address.zip.get_required_value("zip").change_context( + errors::ConnectorError::MissingRequiredField { field_name: "zip" }, + )?, + country_code: address + .country + .get_required_value("country_code") + .change_context(errors::ConnectorError::MissingRequiredField { + field_name: "country_code", + })?, + }) + } else { + None + }, })), domain::PaymentMethodData::Wallet(wallet) => match wallet { domain::WalletData::GooglePay(data) => { @@ -122,7 +150,7 @@ fn fetch_payment_instrument( } impl - TryFrom< + TryFrom<( &WorldpayRouterData< &types::RouterData< types::api::payments::Authorize, @@ -130,24 +158,33 @@ impl PaymentsResponseData, >, >, - > for WorldpayPaymentsRequest + &Secret, + )> for WorldpayPaymentsRequest { type Error = error_stack::Report; fn try_from( - item: &WorldpayRouterData< - &types::RouterData< - types::api::payments::Authorize, - PaymentsAuthorizeData, - PaymentsResponseData, + req: ( + &WorldpayRouterData< + &types::RouterData< + types::api::payments::Authorize, + PaymentsAuthorizeData, + PaymentsResponseData, + >, >, - >, + &Secret, + ), ) -> Result { + let (item, entity_id) = req; Ok(Self { instruction: Instruction { + request_auto_settlement: RequestAutoSettlement { + enabled: item.router_data.request.capture_method + == Some(enums::CaptureMethod::Automatic), + }, value: PaymentValue { amount: item.amount, - currency: item.router_data.request.currency.to_string(), + currency: item.router_data.request.currency, }, narrative: InstructionNarrative { line1: item @@ -159,19 +196,16 @@ impl }, payment_instrument: fetch_payment_instrument( item.router_data.request.payment_method_data.clone(), + item.router_data.get_optional_billing(), )?, debt_repayment: None, }, merchant: Merchant { - entity: item - .router_data - .connector_request_reference_id - .clone() - .replace('_', "-"), + entity: entity_id.clone(), ..Default::default() }, transaction_reference: item.router_data.connector_request_reference_id.clone(), - channel: None, + channel: Channel::Ecom, customer: None, }) } @@ -179,17 +213,32 @@ impl pub struct WorldpayAuthType { pub(super) api_key: Secret, + pub(super) entity_id: Secret, } impl TryFrom<&types::ConnectorAuthType> for WorldpayAuthType { type Error = error_stack::Report; fn try_from(auth_type: &types::ConnectorAuthType) -> Result { match auth_type { + // TODO: Remove this later, kept purely for backwards compatibility types::ConnectorAuthType::BodyKey { api_key, key1 } => { let auth_key = format!("{}:{}", key1.peek(), api_key.peek()); let auth_header = format!("Basic {}", consts::BASE64_ENGINE.encode(auth_key)); Ok(Self { api_key: Secret::new(auth_header), + entity_id: Secret::new("default".to_string()), + }) + } + types::ConnectorAuthType::SignatureKey { + api_key, + key1, + api_secret, + } => { + let auth_key = format!("{}:{}", key1.peek(), api_key.peek()); + let auth_header = format!("Basic {}", consts::BASE64_ENGINE.encode(auth_key)); + Ok(Self { + api_key: Secret::new(auth_header), + entity_id: api_secret.clone(), }) } _ => Err(errors::ConnectorError::FailedToObtainAuthType)?, @@ -197,22 +246,25 @@ impl TryFrom<&types::ConnectorAuthType> for WorldpayAuthType { } } -impl From for enums::AttemptStatus { - fn from(item: Outcome) -> Self { +impl From for enums::AttemptStatus { + fn from(item: PaymentOutcome) -> Self { match item { - Outcome::Authorized => Self::Authorized, - Outcome::Refused => Self::Failure, + PaymentOutcome::Authorized => Self::Authorized, + PaymentOutcome::Refused => Self::Failure, + PaymentOutcome::SentForSettlement => Self::CaptureInitiated, + PaymentOutcome::SentForRefund => Self::AutoRefunded, } } } -impl From for enums::AttemptStatus { - fn from(value: EventType) -> Self { +impl From<&EventType> for enums::AttemptStatus { + fn from(value: &EventType) -> Self { match value { + EventType::SentForAuthorization => Self::Authorizing, + EventType::SentForSettlement => Self::CaptureInitiated, + EventType::Settled => Self::Charged, EventType::Authorized => Self::Authorized, - EventType::CaptureFailed => Self::CaptureFailed, - EventType::Refused => Self::Failure, - EventType::Charged | EventType::SentForSettlement => Self::Charged, + EventType::Refused | EventType::SettlementFailed => Self::Failure, EventType::Cancelled | EventType::SentForRefund | EventType::RefundFailed @@ -227,17 +279,17 @@ impl From for enums::AttemptStatus { impl From for enums::RefundStatus { fn from(value: EventType) -> Self { match value { - EventType::Refunded => Self::Success, + EventType::Refunded | EventType::SentForRefund => Self::Success, EventType::RefundFailed => Self::Failure, EventType::Authorized | EventType::Cancelled - | EventType::Charged - | EventType::SentForRefund + | EventType::Settled | EventType::Refused | EventType::Error | EventType::SentForSettlement + | EventType::SentForAuthorization + | EventType::SettlementFailed | EventType::Expired - | EventType::CaptureFailed | EventType::Unknown => Self::Pending, } } @@ -273,14 +325,29 @@ impl TryFrom> } } -impl TryFrom<&types::RefundsRouterData> for WorldpayRefundRequest { +impl TryFrom<(&types::PaymentsCaptureRouterData, MinorUnit)> for WorldpayPartialRequest { type Error = error_stack::Report; - fn try_from(item: &types::RefundsRouterData) -> Result { + fn try_from(req: (&types::PaymentsCaptureRouterData, MinorUnit)) -> Result { + let (item, amount) = req; Ok(Self { - reference: item.request.connector_transaction_id.clone(), + reference: item.payment_id.clone().replace("_", "-"), value: PaymentValue { - amount: item.request.refund_amount, - currency: item.request.currency.to_string(), + amount: amount.get_amount_as_i64(), + currency: item.request.currency, + }, + }) + } +} + +impl TryFrom<(&types::RefundsRouterData, MinorUnit)> for WorldpayPartialRequest { + type Error = error_stack::Report; + fn try_from(req: (&types::RefundsRouterData, MinorUnit)) -> Result { + let (item, amount) = req; + Ok(Self { + reference: item.request.refund_id.clone().replace("_", "-"), + value: PaymentValue { + amount: amount.get_amount_as_i64(), + currency: item.request.currency, }, }) } diff --git a/crates/router/src/core/fraud_check/flows/transaction_flow.rs b/crates/router/src/core/fraud_check/flows/transaction_flow.rs index 6b25be7318..68db6423e0 100644 --- a/crates/router/src/core/fraud_check/flows/transaction_flow.rs +++ b/crates/router/src/core/fraud_check/flows/transaction_flow.rs @@ -106,7 +106,10 @@ impl payment_method, error_code: self.payment_attempt.error_code.clone(), error_message: self.payment_attempt.error_message.clone(), - connector_transaction_id: self.payment_attempt.connector_transaction_id.clone(), + connector_transaction_id: self + .payment_attempt + .get_connector_payment_id() + .map(ToString::to_string), connector: self.payment_attempt.connector.clone(), }, // self.order_details response: Ok(FraudCheckResponseData::TransactionResponse { diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 58f591e5c1..6ead052302 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -6,7 +6,7 @@ use async_trait::async_trait; use common_enums::{AuthorizationStatus, SessionUpdateStatus}; use common_utils::{ ext_traits::{AsyncExt, Encode}, - types::{keymanager::KeyManagerState, MinorUnit}, + types::{keymanager::KeyManagerState, ConnectorTransactionId, MinorUnit}, }; use error_stack::{report, ResultExt}; use futures::FutureExt; @@ -1406,6 +1406,7 @@ async fn payment_response_update_tracker( } => { let connector_transaction_id = match pre_processing_id.to_owned() { types::PreprocessingResponseId::PreProcessingId(_) => None, + types::PreprocessingResponseId::ConnectorTransactionId( connector_txn_id, ) => Some(connector_txn_id), @@ -1452,8 +1453,8 @@ async fn payment_response_update_tracker( ); let connector_transaction_id = match resource_id { types::ResponseId::NoResponseId => None, - types::ResponseId::ConnectorTransactionId(id) - | types::ResponseId::EncodedData(id) => Some(id), + types::ResponseId::ConnectorTransactionId(ref id) + | types::ResponseId::EncodedData(ref id) => Some(id), }; let encoded_data = payment_data.payment_attempt.encoded_data.clone(); @@ -1502,12 +1503,23 @@ async fn payment_response_update_tracker( .multiple_capture_data { Some(multiple_capture_data) => { + let (connector_capture_id, connector_capture_data) = + match resource_id { + types::ResponseId::NoResponseId => (None, None), + types::ResponseId::ConnectorTransactionId(id) + | types::ResponseId::EncodedData(id) => { + let (txn_id, txn_data) = + ConnectorTransactionId::form_id_and_data(id); + (Some(txn_id), txn_data) + } + }; let capture_update = storage::CaptureUpdate::ResponseUpdate { status: enums::CaptureStatus::foreign_try_from( router_data.status, )?, - connector_capture_id: connector_transaction_id.clone(), + connector_capture_id: connector_capture_id.clone(), connector_response_reference_id, + connector_capture_data: connector_capture_data.clone(), }; let capture_update_list = vec![( multiple_capture_data.get_latest_capture().clone(), @@ -1525,7 +1537,7 @@ async fn payment_response_update_tracker( Some(storage::PaymentAttemptUpdate::ResponseUpdate { status: updated_attempt_status, connector: None, - connector_transaction_id: connector_transaction_id.clone(), + connector_transaction_id: connector_transaction_id.cloned(), authentication_type: auth_update, amount_capturable: router_data .request @@ -1878,7 +1890,11 @@ async fn payment_response_update_tracker( &add_attributes([ ( "connector", - payment_data.payment_attempt.connector.unwrap_or_default(), + payment_data + .payment_attempt + .connector + .clone() + .unwrap_or_default(), ), ( "merchant_id", @@ -1892,12 +1908,15 @@ async fn payment_response_update_tracker( ); Err(error_stack::Report::new( errors::ApiErrorResponse::IntegrityCheckFailed { + connector_transaction_id: payment_data + .payment_attempt + .get_connector_payment_id() + .map(ToString::to_string), reason: payment_data .payment_attempt .error_message .unwrap_or_default(), field_names: err.field_names, - connector_transaction_id: payment_data.payment_attempt.connector_transaction_id, }, )) } @@ -2021,7 +2040,7 @@ fn response_to_capture_update( let mut unmapped_captures = vec![]; for (connector_capture_id, capture_sync_response) in response_list { let capture = - multiple_capture_data.get_capture_by_connector_capture_id(connector_capture_id); + multiple_capture_data.get_capture_by_connector_capture_id(&connector_capture_id); if let Some(capture) = capture { capture_update_list.push(( capture.clone(), diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 63847b65f5..36586fdb15 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -9,7 +9,7 @@ use common_utils::{ consts::X_HS_LATENCY, fp_utils, pii::Email, - types::{AmountConvertor, MinorUnit, StringMajorUnitForConnector}, + types::{self as common_utils_type, AmountConvertor, MinorUnit, StringMajorUnitForConnector}, }; use diesel_models::ephemeral_key; use error_stack::{report, ResultExt}; @@ -204,8 +204,8 @@ where let resource_id = match payment_data .payment_attempt - .connector_transaction_id - .clone() + .get_connector_payment_id() + .map(ToString::to_string) { Some(id) => types::ResponseId::ConnectorTransactionId(id), None => types::ResponseId::NoResponseId, @@ -1236,6 +1236,10 @@ where }) }); + let connector_transaction_id = payment_attempt + .get_connector_payment_id() + .map(ToString::to_string); + let payments_response = api::PaymentsResponse { payment_id: payment_intent.payment_id, merchant_id: payment_intent.merchant_id, @@ -1304,7 +1308,7 @@ where connector_request_reference_id_config, &merchant_id, ), - connector_transaction_id: payment_attempt.connector_transaction_id, + connector_transaction_id, frm_message, metadata: payment_intent.metadata, connector_metadata: payment_intent.connector_metadata, @@ -1469,6 +1473,7 @@ pub fn wait_screen_next_steps_check( #[cfg(feature = "v1")] impl ForeignFrom<(storage::PaymentIntent, storage::PaymentAttempt)> for api::PaymentsResponse { fn foreign_from((pi, pa): (storage::PaymentIntent, storage::PaymentAttempt)) -> Self { + let connector_transaction_id = pa.get_connector_payment_id().map(ToString::to_string); Self { payment_id: pi.payment_id, merchant_id: pi.merchant_id, @@ -1491,7 +1496,7 @@ impl ForeignFrom<(storage::PaymentIntent, storage::PaymentAttempt)> for api::Pay setup_future_usage: pi.setup_future_usage, capture_method: pa.capture_method, authentication_type: pa.authentication_type, - connector_transaction_id: pa.connector_transaction_id, + connector_transaction_id, attempt_count: pi.attempt_count, profile_id: pi.profile_id, merchant_connector_id: pa.merchant_connector_id, @@ -2056,6 +2061,7 @@ impl TryFrom> for types::PaymentsCaptureD })?; let amount = payment_data.payment_attempt.get_total_amount(); Ok(Self { + capture_method: payment_data.get_capture_method(), amount_to_capture: amount_to_capture.get_amount_as_i64(), // This should be removed once we start moving to connector module minor_amount_to_capture: amount_to_capture, currency: payment_data.currency, @@ -2405,14 +2411,21 @@ impl ForeignTryFrom for storage::CaptureUpdate { connector_response_reference_id, .. } => { - let connector_capture_id = match resource_id { - types::ResponseId::ConnectorTransactionId(id) => Some(id), - types::ResponseId::EncodedData(_) | types::ResponseId::NoResponseId => None, + let (connector_capture_id, connector_capture_data) = match resource_id { + types::ResponseId::EncodedData(_) | types::ResponseId::NoResponseId => { + (None, None) + } + types::ResponseId::ConnectorTransactionId(id) => { + let (txn_id, txn_data) = + common_utils_type::ConnectorTransactionId::form_id_and_data(id); + (Some(txn_id), txn_data) + } }; Ok(Self::ResponseUpdate { status: enums::CaptureStatus::foreign_try_from(status)?, connector_capture_id, connector_response_reference_id, + connector_capture_data, }) } types::CaptureSyncResponse::Error { @@ -2479,7 +2492,10 @@ impl TryFrom> for types::CompleteAuthoriz browser_info, email: payment_data.email, payment_method_data: payment_data.payment_method_data.map(From::from), - connector_transaction_id: payment_data.payment_attempt.connector_transaction_id, + connector_transaction_id: payment_data + .payment_attempt + .get_connector_payment_id() + .map(ToString::to_string), redirect_response, connector_meta: payment_data.payment_attempt.connector_metadata, complete_authorize_url, @@ -2578,7 +2594,10 @@ impl TryFrom> for types::PaymentsPreProce complete_authorize_url, browser_info, surcharge_details: payment_data.surcharge_details, - connector_transaction_id: payment_data.payment_attempt.connector_transaction_id, + connector_transaction_id: payment_data + .payment_attempt + .get_connector_payment_id() + .map(ToString::to_string), redirect_response: None, mandate_id: payment_data.mandate_id, related_transaction_id: None, diff --git a/crates/router/src/core/payments/types.rs b/crates/router/src/core/payments/types.rs index 3034b74db4..1a7e204767 100644 --- a/crates/router/src/core/payments/types.rs +++ b/crates/router/src/core/payments/types.rs @@ -4,7 +4,7 @@ use api_models::payment_methods::SurchargeDetailsResponse; use common_utils::{ errors::CustomResult, ext_traits::{Encode, OptionExt}, - types as common_types, + types::{self as common_types, ConnectorTransactionIdTrait}, }; use error_stack::ResultExt; use hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt; @@ -162,11 +162,13 @@ impl MultipleCaptureData { } pub fn get_capture_by_connector_capture_id( &self, - connector_capture_id: String, + connector_capture_id: &String, ) -> Option<&storage::Capture> { self.all_captures .iter() - .find(|(_, capture)| capture.connector_capture_id == Some(connector_capture_id.clone())) + .find(|(_, capture)| { + capture.get_optional_connector_transaction_id() == Some(connector_capture_id) + }) .map(|(_, capture)| capture) } pub fn get_latest_capture(&self) -> &storage::Capture { @@ -176,14 +178,14 @@ impl MultipleCaptureData { let pending_connector_capture_ids = self .get_pending_captures() .into_iter() - .filter_map(|capture| capture.connector_capture_id.clone()) + .filter_map(|capture| capture.get_optional_connector_transaction_id().cloned()) .collect(); pending_connector_capture_ids } pub fn get_pending_captures_without_connector_capture_id(&self) -> Vec<&storage::Capture> { self.get_pending_captures() .into_iter() - .filter(|capture| capture.connector_capture_id.is_none()) + .filter(|capture| capture.get_optional_connector_transaction_id().is_none()) .collect() } } diff --git a/crates/router/src/core/refunds.rs b/crates/router/src/core/refunds.rs index cf0374fe82..86211770e0 100644 --- a/crates/router/src/core/refunds.rs +++ b/crates/router/src/core/refunds.rs @@ -8,7 +8,7 @@ use std::collections::HashMap; use api_models::admin::MerchantConnectorInfo; use common_utils::{ ext_traits::{AsyncExt, ValueExt}, - types::MinorUnit, + types::{ConnectorTransactionId, ConnectorTransactionIdTrait, MinorUnit}, }; use diesel_models::process_tracker::business_status; use error_stack::{report, ResultExt}; @@ -235,6 +235,7 @@ pub async fn trigger_refund_to_gateway( refund_error_code: Some("NOT_IMPLEMENTED".to_string()), updated_by: storage_scheme.to_string(), connector_refund_id: None, + connector_refund_data: None, }) } errors::ConnectorError::NotSupported { message, connector } => { @@ -246,6 +247,7 @@ pub async fn trigger_refund_to_gateway( refund_error_code: Some("NOT_SUPPORTED".to_string()), updated_by: storage_scheme.to_string(), connector_refund_id: None, + connector_refund_data: None, }) } _ => None, @@ -287,12 +289,18 @@ pub async fn trigger_refund_to_gateway( refund_error_code: Some(err.code), updated_by: storage_scheme.to_string(), connector_refund_id: None, + connector_refund_data: None, }, Ok(response) => { // match on connector integrity checks match router_data_res.integrity_check.clone() { Err(err) => { - let refund_connector_transaction_id = err.connector_transaction_id; + let (refund_connector_transaction_id, connector_refund_data) = + err.connector_transaction_id.map_or((None, None), |txn_id| { + let (refund_id, refund_data) = + ConnectorTransactionId::form_id_and_data(txn_id); + (Some(refund_id), refund_data) + }); metrics::INTEGRITY_CHECK_FAILED.add( &metrics::CONTEXT, 1, @@ -313,6 +321,7 @@ pub async fn trigger_refund_to_gateway( refund_error_code: Some("IE".to_string()), updated_by: storage_scheme.to_string(), connector_refund_id: refund_connector_transaction_id, + connector_refund_data, } } Ok(()) => { @@ -323,13 +332,16 @@ pub async fn trigger_refund_to_gateway( &add_attributes([("connector", connector.connector_name.to_string())]), ) } + let (connector_refund_id, connector_refund_data) = + ConnectorTransactionId::form_id_and_data(response.connector_refund_id); storage::RefundUpdate::Update { - connector_refund_id: response.connector_refund_id, + connector_refund_id, refund_status: response.refund_status, sent_to_gateway: true, refund_error_message: None, refund_arn: "".to_string(), updated_by: storage_scheme.to_string(), + connector_refund_data, } } } @@ -424,7 +436,7 @@ pub async fn refund_retrieve_core( let payment_attempt = db .find_payment_attempt_by_connector_transaction_id_payment_id_merchant_id( - &refund.connector_transaction_id, + refund.get_connector_transaction_id(), payment_id, merchant_id, merchant_account.storage_scheme, @@ -591,6 +603,7 @@ pub async fn sync_refund_with_gateway( refund_error_code: Some(error_message.code), updated_by: storage_scheme.to_string(), connector_refund_id: None, + connector_refund_data: None, } } Ok(response) => match router_data_res.integrity_check.clone() { @@ -606,7 +619,13 @@ pub async fn sync_refund_with_gateway( ), ]), ); - let refund_connector_transaction_id = err.connector_transaction_id; + let (refund_connector_transaction_id, connector_refund_data) = err + .connector_transaction_id + .map_or((None, None), |refund_id| { + let (refund_id, refund_data) = + ConnectorTransactionId::form_id_and_data(refund_id); + (Some(refund_id), refund_data) + }); storage::RefundUpdate::ErrorUpdate { refund_status: Some(enums::RefundStatus::ManualReview), refund_error_message: Some(format!( @@ -616,16 +635,22 @@ pub async fn sync_refund_with_gateway( refund_error_code: Some("IE".to_string()), updated_by: storage_scheme.to_string(), connector_refund_id: refund_connector_transaction_id, + connector_refund_data, + } + } + Ok(()) => { + let (connector_refund_id, connector_refund_data) = + ConnectorTransactionId::form_id_and_data(response.connector_refund_id); + storage::RefundUpdate::Update { + connector_refund_id, + refund_status: response.refund_status, + sent_to_gateway: true, + refund_error_message: None, + refund_arn: "".to_string(), + updated_by: storage_scheme.to_string(), + connector_refund_data, } } - Ok(()) => storage::RefundUpdate::Update { - connector_refund_id: response.connector_refund_id, - refund_status: response.refund_status, - sent_to_gateway: true, - refund_error_message: None, - refund_arn: "".to_string(), - updated_by: storage_scheme.to_string(), - }, }, }; @@ -752,7 +777,7 @@ pub async fn validate_and_create_refund( .attach_printable("invalid merchant_id in request")) })?; - let connecter_transaction_id = payment_attempt.clone().connector_transaction_id.ok_or_else(|| { + let connector_transaction_id = payment_attempt.clone().connector_transaction_id.ok_or_else(|| { report!(errors::ApiErrorResponse::InternalServerError) .attach_printable("Transaction in invalid. Missing field \"connector_transaction_id\" in payment_attempt.") })?; @@ -760,7 +785,7 @@ pub async fn validate_and_create_refund( let all_refunds = db .find_refund_by_merchant_id_connector_transaction_id( merchant_account.get_id(), - &connecter_transaction_id, + &connector_transaction_id, merchant_account.storage_scheme, ) .await @@ -800,13 +825,15 @@ pub async fn validate_and_create_refund( .clone() .ok_or(errors::ApiErrorResponse::InternalServerError) .attach_printable("No connector populated in payment attempt")?; + let (connector_transaction_id, connector_transaction_data) = + ConnectorTransactionId::form_id_and_data(connector_transaction_id); let refund_create_req = storage::RefundNew { refund_id: refund_id.to_string(), internal_reference_id: utils::generate_id(consts::ID_LENGTH, "refid"), external_reference_id: Some(refund_id.clone()), payment_id: req.payment_id, merchant_id: merchant_account.get_id().clone(), - connector_transaction_id: connecter_transaction_id.to_string(), + connector_transaction_id, connector, refund_type: req.refund_type.unwrap_or_default().foreign_into(), total_amount: payment_attempt.get_total_amount(), @@ -827,6 +854,8 @@ pub async fn validate_and_create_refund( refund_arn: None, updated_by: Default::default(), organization_id: merchant_account.organization_id.clone(), + connector_refund_data: None, + connector_transaction_data, }; let refund = match db @@ -1402,7 +1431,7 @@ pub async fn trigger_refund_execute_workflow( let payment_attempt = db .find_payment_attempt_by_connector_transaction_id_payment_id_merchant_id( - &refund.connector_transaction_id, + refund.get_connector_transaction_id(), &refund_core.payment_id, &refund.merchant_id, merchant_account.storage_scheme, @@ -1506,6 +1535,7 @@ pub fn refund_to_refund_core_workflow_model( connector_transaction_id: refund.connector_transaction_id.clone(), merchant_id: refund.merchant_id.clone(), payment_id: refund.payment_id.clone(), + connector_transaction_data: refund.connector_transaction_data.clone(), } } diff --git a/crates/router/src/core/utils.rs b/crates/router/src/core/utils.rs index ae8b7c15a7..a6a9c36bfd 100644 --- a/crates/router/src/core/utils.rs +++ b/crates/router/src/core/utils.rs @@ -12,7 +12,7 @@ use common_utils::{crypto::Encryptable, pii::Email}; use common_utils::{ errors::CustomResult, ext_traits::AsyncExt, - types::{keymanager::KeyManagerState, MinorUnit}, + types::{keymanager::KeyManagerState, ConnectorTransactionIdTrait, MinorUnit}, }; use error_stack::{report, ResultExt}; use hyperswitch_domain_models::{ @@ -325,6 +325,8 @@ pub async fn construct_refund_router_data<'a, F>( field_name: "browser_info", })?; + let connector_refund_id = refund.get_optional_connector_refund_id().cloned(); + let router_data = types::RouterData { flow: PhantomData, merchant_id: merchant_account.get_id().clone(), @@ -349,7 +351,7 @@ pub async fn construct_refund_router_data<'a, F>( minor_amount_captured: payment_intent.amount_captured, request: types::RefundsData { refund_id: refund.refund_id.clone(), - connector_transaction_id: refund.connector_transaction_id.clone(), + connector_transaction_id: refund.get_connector_transaction_id().clone(), refund_amount: refund.refund_amount.get_amount_as_i64(), minor_refund_amount: refund.refund_amount, currency, @@ -358,14 +360,14 @@ pub async fn construct_refund_router_data<'a, F>( webhook_url, connector_metadata: payment_attempt.connector_metadata.clone(), reason: refund.refund_reason.clone(), - connector_refund_id: refund.connector_refund_id.clone(), + connector_refund_id: connector_refund_id.clone(), browser_info, charges, integrity_object: None, }, response: Ok(types::RefundsResponseData { - connector_refund_id: refund.connector_refund_id.clone().unwrap_or_default(), + connector_refund_id: connector_refund_id.unwrap_or_default(), refund_status: refund.refund_status, }), access_token: None, diff --git a/crates/router/src/core/webhooks/incoming.rs b/crates/router/src/core/webhooks/incoming.rs index af531984a1..3942c39566 100644 --- a/crates/router/src/core/webhooks/incoming.rs +++ b/crates/router/src/core/webhooks/incoming.rs @@ -814,6 +814,7 @@ async fn refunds_incoming_webhook_flow( .change_context(errors::ApiErrorResponse::WebhookProcessingFailure) .attach_printable("failed refund status mapping from event type")?, updated_by: merchant_account.storage_scheme.to_string(), + connector_refund_data: None, }; db.update_refund( refund.to_owned(), diff --git a/crates/router/src/db/address.rs b/crates/router/src/db/address.rs index 335110248a..3a8750feff 100644 --- a/crates/router/src/db/address.rs +++ b/crates/router/src/db/address.rs @@ -391,11 +391,11 @@ mod storage { let field = format!("add_{}", address_id); Box::pin(db_utils::try_redis_get_else_try_database_get( async { - kv_wrapper( + Box::pin(kv_wrapper( self, KvOperation::::HGet(&field), key, - ) + )) .await? .try_into_hget() }, @@ -502,14 +502,14 @@ mod storage { }, }; - kv_wrapper::<(), _, _>( + Box::pin(kv_wrapper::<(), _, _>( self, KvOperation::Hset::( (&field, redis_value), redis_entry, ), key, - ) + )) .await .change_context(errors::StorageError::KVError)? .try_into_hset() @@ -601,7 +601,7 @@ mod storage { }, }; - match kv_wrapper::( + match Box::pin(kv_wrapper::( self, KvOperation::HSetNx::( &field, @@ -609,7 +609,7 @@ mod storage { redis_entry, ), key, - ) + )) .await .change_context(errors::StorageError::KVError)? .try_into_hsetnx() diff --git a/crates/router/src/db/capture.rs b/crates/router/src/db/capture.rs index 16b18a873d..cbc27f918d 100644 --- a/crates/router/src/db/capture.rs +++ b/crates/router/src/db/capture.rs @@ -198,6 +198,7 @@ impl CaptureInterface for MockDb { capture_sequence: capture.capture_sequence, connector_capture_id: capture.connector_capture_id, connector_response_reference_id: capture.connector_response_reference_id, + connector_capture_data: capture.connector_capture_data, }; captures.push(capture.clone()); Ok(capture) diff --git a/crates/router/src/db/customers.rs b/crates/router/src/db/customers.rs index 9cd044f69e..5020c238e4 100644 --- a/crates/router/src/db/customers.rs +++ b/crates/router/src/db/customers.rs @@ -219,11 +219,11 @@ mod storage { Box::pin(db_utils::try_redis_get_else_try_database_get( // check for ValueNotFound async { - kv_wrapper( + Box::pin(kv_wrapper( self, KvOperation::::HGet(&field), key, - ) + )) .await? .try_into_hget() .map(Some) @@ -293,11 +293,11 @@ mod storage { Box::pin(db_utils::try_redis_get_else_try_database_get( // check for ValueNotFound async { - kv_wrapper( + Box::pin(kv_wrapper( self, KvOperation::::HGet(&field), key, - ) + )) .await? .try_into_hget() .map(Some) @@ -453,14 +453,14 @@ mod storage { }, }; - kv_wrapper::<(), _, _>( + Box::pin(kv_wrapper::<(), _, _>( self, KvOperation::Hset::( (&field, redis_value), redis_entry, ), key, - ) + )) .await .change_context(errors::StorageError::KVError)? .try_into_hset() @@ -584,11 +584,11 @@ mod storage { let field = format!("cust_{}", customer_id.get_string_repr()); Box::pin(db_utils::try_redis_get_else_try_database_get( async { - kv_wrapper( + Box::pin(kv_wrapper( self, KvOperation::::HGet(&field), key, - ) + )) .await? .try_into_hget() }, @@ -773,7 +773,7 @@ mod storage { }; let storage_customer = new_customer.into(); - match kv_wrapper::( + match Box::pin(kv_wrapper::( self, KvOperation::HSetNx::( &field, @@ -781,7 +781,7 @@ mod storage { redis_entry, ), key, - ) + )) .await .change_context(errors::StorageError::KVError)? .try_into_hsetnx() diff --git a/crates/router/src/db/mandate.rs b/crates/router/src/db/mandate.rs index 40e5f88614..95733805b4 100644 --- a/crates/router/src/db/mandate.rs +++ b/crates/router/src/db/mandate.rs @@ -114,11 +114,11 @@ mod storage { Box::pin(db_utils::try_redis_get_else_try_database_get( async { - kv_wrapper( + Box::pin(kv_wrapper( self, KvOperation::::HGet(&field), key, - ) + )) .await? .try_into_hget() }, @@ -172,11 +172,11 @@ mod storage { Box::pin(db_utils::try_redis_get_else_try_database_get( async { - kv_wrapper( + Box::pin(kv_wrapper( self, KvOperation::::HGet(&lookup.sk_id), key, - ) + )) .await? .try_into_hget() }, @@ -281,14 +281,14 @@ mod storage { }, }; - kv_wrapper::<(), _, _>( + Box::pin(kv_wrapper::<(), _, _>( self, KvOperation::::Hset( (&field, redis_value), redis_entry, ), key, - ) + )) .await .map_err(|err| err.to_redis_failed_response(&key_str))? .try_into_hset() @@ -369,7 +369,7 @@ mod storage { .await?; } - match kv_wrapper::( + match Box::pin(kv_wrapper::( self, KvOperation::::HSetNx( &field, @@ -377,7 +377,7 @@ mod storage { redis_entry, ), key, - ) + )) .await .map_err(|err| err.to_redis_failed_response(&key_str))? .try_into_hsetnx() diff --git a/crates/router/src/db/payment_method.rs b/crates/router/src/db/payment_method.rs index 6e05207679..e75fb940a3 100644 --- a/crates/router/src/db/payment_method.rs +++ b/crates/router/src/db/payment_method.rs @@ -210,13 +210,13 @@ mod storage { Box::pin(db_utils::try_redis_get_else_try_database_get( async { - kv_wrapper( + Box::pin(kv_wrapper( self, KvOperation::::HGet( &lookup.sk_id, ), key, - ) + )) .await? .try_into_hget() }, @@ -348,13 +348,13 @@ mod storage { Box::pin(db_utils::try_redis_get_else_try_database_get( async { - kv_wrapper( + Box::pin(kv_wrapper( self, KvOperation::::HGet( &lookup.sk_id, ), key, - ) + )) .await? .try_into_hget() }, @@ -500,7 +500,7 @@ mod storage { }, }; - match kv_wrapper::( + match Box::pin(kv_wrapper::( self, KvOperation::::HSetNx( &field, @@ -508,7 +508,7 @@ mod storage { redis_entry, ), key, - ) + )) .await .map_err(|err| err.to_redis_failed_response(&key_str))? .try_into_hsetnx() @@ -597,14 +597,14 @@ mod storage { }, }; - kv_wrapper::<(), _, _>( + Box::pin(kv_wrapper::<(), _, _>( self, KvOperation::::Hset( (&field, redis_value), redis_entry, ), key, - ) + )) .await .map_err(|err| err.to_redis_failed_response(&key_str))? .try_into_hset() @@ -743,11 +743,11 @@ mod storage { let pattern = "payment_method_id_*"; let redis_fut = async { - let kv_result = kv_wrapper::( + let kv_result = Box::pin(kv_wrapper::( self, KvOperation::::Scan(pattern), key, - ) + )) .await? .try_into_scan(); kv_result.map(|payment_methods| { diff --git a/crates/router/src/db/refund.rs b/crates/router/src/db/refund.rs index cf092ad410..41cb3cef5c 100644 --- a/crates/router/src/db/refund.rs +++ b/crates/router/src/db/refund.rs @@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet}; #[cfg(feature = "olap")] -use common_utils::types::MinorUnit; +use common_utils::types::{ConnectorTransactionIdTrait, MinorUnit}; use diesel_models::{errors::DatabaseError, refund::RefundUpdateInternal}; use hyperswitch_domain_models::refunds; @@ -298,7 +298,9 @@ mod storage { #[cfg(feature = "kv_store")] mod storage { - use common_utils::{ext_traits::Encode, fallback_reverse_lookup_not_found}; + use common_utils::{ + ext_traits::Encode, fallback_reverse_lookup_not_found, types::ConnectorTransactionIdTrait, + }; use error_stack::{report, ResultExt}; use hyperswitch_domain_models::refunds; use redis_interface::HsetnxReply; @@ -359,11 +361,11 @@ mod storage { }; Box::pin(db_utils::try_redis_get_else_try_database_get( async { - kv_wrapper( + Box::pin(kv_wrapper( self, KvOperation::::HGet(&lookup.sk_id), key, - ) + )) .await? .try_into_hget() }, @@ -432,6 +434,8 @@ mod storage { merchant_connector_id: new.merchant_connector_id.clone(), charges: new.charges.clone(), organization_id: new.organization_id.clone(), + connector_refund_data: new.connector_refund_data.clone(), + connector_transaction_data: new.connector_transaction_data.clone(), }; let field = format!( @@ -470,7 +474,8 @@ mod storage { updated_by: storage_scheme.to_string(), }, ]; - if let Some(connector_refund_id) = created_refund.to_owned().connector_refund_id + if let Some(connector_refund_id) = + created_refund.to_owned().get_optional_connector_refund_id() { reverse_lookups.push(storage_types::ReverseLookupNew { sk_id: field.clone(), @@ -491,7 +496,7 @@ mod storage { futures::future::try_join_all(rev_look).await?; - match kv_wrapper::( + match Box::pin(kv_wrapper::( self, KvOperation::::HSetNx( &field, @@ -499,7 +504,7 @@ mod storage { redis_entry, ), key, - ) + )) .await .map_err(|err| err.to_redis_failed_response(&key_str))? .try_into_hsetnx() @@ -560,11 +565,11 @@ mod storage { Box::pin(db_utils::try_redis_get_else_try_database_get( async { - kv_wrapper( + Box::pin(kv_wrapper( self, KvOperation::::Scan(&pattern), key, - ) + )) .await? .try_into_scan() }, @@ -619,14 +624,14 @@ mod storage { }, }; - kv_wrapper::<(), _, _>( + Box::pin(kv_wrapper::<(), _, _>( self, KvOperation::Hset::( (&field, redis_value), redis_entry, ), key, - ) + )) .await .map_err(|err| err.to_redis_failed_response(&key_str))? .try_into_hset() @@ -672,11 +677,11 @@ mod storage { }; Box::pin(db_utils::try_redis_get_else_try_database_get( async { - kv_wrapper( + Box::pin(kv_wrapper( self, KvOperation::::HGet(&lookup.sk_id), key, - ) + )) .await? .try_into_hget() }, @@ -730,11 +735,11 @@ mod storage { }; Box::pin(db_utils::try_redis_get_else_try_database_get( async { - kv_wrapper( + Box::pin(kv_wrapper( self, KvOperation::::HGet(&lookup.sk_id), key, - ) + )) .await? .try_into_hget() }, @@ -777,11 +782,11 @@ mod storage { }; Box::pin(db_utils::try_redis_get_else_try_database_get( async { - kv_wrapper( + Box::pin(kv_wrapper( self, KvOperation::::Scan("pa_*_ref_*"), key, - ) + )) .await? .try_into_scan() }, @@ -921,6 +926,8 @@ impl RefundInterface for MockDb { merchant_connector_id: new.merchant_connector_id, charges: new.charges, organization_id: new.organization_id, + connector_refund_data: new.connector_refund_data, + connector_transaction_data: new.connector_transaction_data, }; refunds.push(refund.clone()); Ok(refund) @@ -937,7 +944,7 @@ impl RefundInterface for MockDb { .iter() .take_while(|refund| { refund.merchant_id == *merchant_id - && refund.connector_transaction_id == connector_transaction_id + && refund.get_connector_transaction_id() == connector_transaction_id }) .cloned() .collect::>()) @@ -995,7 +1002,10 @@ impl RefundInterface for MockDb { .iter() .find(|refund| { refund.merchant_id == *merchant_id - && refund.connector_refund_id == Some(connector_refund_id.to_string()) + && refund + .get_optional_connector_refund_id() + .map(|refund_id| refund_id.as_str()) + == Some(connector_refund_id) && refund.connector == connector }) .cloned() diff --git a/crates/router/src/db/reverse_lookup.rs b/crates/router/src/db/reverse_lookup.rs index d51ed5ed38..06bd84675b 100644 --- a/crates/router/src/db/reverse_lookup.rs +++ b/crates/router/src/db/reverse_lookup.rs @@ -120,7 +120,7 @@ mod storage { }, }; - match kv_wrapper::( + match Box::pin(kv_wrapper::( self, KvOperation::SetNx(&created_rev_lookup, redis_entry), PartitionKey::CombinationKey { @@ -129,7 +129,7 @@ mod storage { &created_rev_lookup.lookup_id ), }, - ) + )) .await .map_err(|err| err.to_redis_failed_response(&created_rev_lookup.lookup_id))? .try_into_setnx() @@ -168,13 +168,13 @@ mod storage { enums::MerchantStorageScheme::PostgresOnly => database_call().await, enums::MerchantStorageScheme::RedisKv => { let redis_fut = async { - kv_wrapper( + Box::pin(kv_wrapper( self, KvOperation::::Get, PartitionKey::CombinationKey { combination: &format!("reverse_lookup_{id}"), }, - ) + )) .await? .try_into_get() }; diff --git a/crates/router/src/services/kafka/refund.rs b/crates/router/src/services/kafka/refund.rs index c4fb4a43dd..7eff6f881b 100644 --- a/crates/router/src/services/kafka/refund.rs +++ b/crates/router/src/services/kafka/refund.rs @@ -1,4 +1,7 @@ -use common_utils::{id_type, types::MinorUnit}; +use common_utils::{ + id_type, + types::{ConnectorTransactionIdTrait, MinorUnit}, +}; use diesel_models::{enums as storage_enums, refund::Refund}; use time::OffsetDateTime; @@ -39,9 +42,9 @@ impl<'a> KafkaRefund<'a> { refund_id: &refund.refund_id, payment_id: &refund.payment_id, merchant_id: &refund.merchant_id, - connector_transaction_id: &refund.connector_transaction_id, + connector_transaction_id: refund.get_connector_transaction_id(), connector: &refund.connector, - connector_refund_id: refund.connector_refund_id.as_ref(), + connector_refund_id: refund.get_optional_connector_refund_id(), external_reference_id: refund.external_reference_id.as_ref(), refund_type: &refund.refund_type, total_amount: &refund.total_amount, diff --git a/crates/router/src/services/kafka/refund_event.rs b/crates/router/src/services/kafka/refund_event.rs index f2150020c9..8f9f77878a 100644 --- a/crates/router/src/services/kafka/refund_event.rs +++ b/crates/router/src/services/kafka/refund_event.rs @@ -1,4 +1,7 @@ -use common_utils::{id_type, types::MinorUnit}; +use common_utils::{ + id_type, + types::{ConnectorTransactionIdTrait, MinorUnit}, +}; use diesel_models::{enums as storage_enums, refund::Refund}; use time::OffsetDateTime; @@ -40,9 +43,9 @@ impl<'a> KafkaRefundEvent<'a> { refund_id: &refund.refund_id, payment_id: &refund.payment_id, merchant_id: &refund.merchant_id, - connector_transaction_id: &refund.connector_transaction_id, + connector_transaction_id: refund.get_connector_transaction_id(), connector: &refund.connector, - connector_refund_id: refund.connector_refund_id.as_ref(), + connector_refund_id: refund.get_optional_connector_refund_id(), external_reference_id: refund.external_reference_id.as_ref(), refund_type: &refund.refund_type, total_amount: &refund.total_amount, diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index e115558995..37387a01da 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -482,7 +482,7 @@ impl ConnectorData { Ok(ConnectorEnum::Old(Box::new(&connector::Worldline))) } enums::Connector::Worldpay => { - Ok(ConnectorEnum::Old(Box::new(&connector::Worldpay))) + Ok(ConnectorEnum::Old(Box::new(connector::Worldpay::new()))) } enums::Connector::Mifinity => { Ok(ConnectorEnum::Old(Box::new(connector::Mifinity::new()))) diff --git a/crates/router/src/types/storage/payment_attempt.rs b/crates/router/src/types/storage/payment_attempt.rs index 88d9b433ec..40335d5f2a 100644 --- a/crates/router/src/types/storage/payment_attempt.rs +++ b/crates/router/src/types/storage/payment_attempt.rs @@ -63,6 +63,7 @@ impl PaymentAttemptExt for PaymentAttempt { capture_sequence, connector_capture_id: None, connector_response_reference_id: None, + connector_capture_data: None, }) } diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index 4d753b59bc..2146ab3427 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -10,6 +10,7 @@ use common_utils::{ ext_traits::{Encode, StringExt, ValueExt}, fp_utils::when, pii, + types::ConnectorTransactionIdTrait, }; use diesel_models::enums as storage_enums; use error_stack::{report, ResultExt}; @@ -1292,6 +1293,9 @@ impl ForeignTryFrom #[cfg(feature = "v1")] impl ForeignFrom for payments::PaymentAttemptResponse { fn foreign_from(payment_attempt: storage::PaymentAttempt) -> Self { + let connector_transaction_id = payment_attempt + .get_connector_payment_id() + .map(ToString::to_string); Self { attempt_id: payment_attempt.attempt_id, status: payment_attempt.status, @@ -1300,7 +1304,7 @@ impl ForeignFrom for payments::PaymentAttemptResponse { connector: payment_attempt.connector, error_message: payment_attempt.error_reason, payment_method: payment_attempt.payment_method, - connector_transaction_id: payment_attempt.connector_transaction_id, + connector_transaction_id, capture_method: payment_attempt.capture_method, authentication_type: payment_attempt.authentication_type, created_at: payment_attempt.created_at, @@ -1323,6 +1327,7 @@ impl ForeignFrom for payments::PaymentAttemptResponse { impl ForeignFrom for payments::CaptureResponse { fn foreign_from(capture: storage::Capture) -> Self { + let connector_capture_id = capture.get_optional_connector_transaction_id().cloned(); Self { capture_id: capture.capture_id, status: capture.status, @@ -1330,7 +1335,7 @@ impl ForeignFrom for payments::CaptureResponse { currency: capture.currency, connector: capture.connector, authorized_attempt_id: capture.authorized_attempt_id, - connector_capture_id: capture.connector_capture_id, + connector_capture_id, capture_sequence: capture.capture_sequence, error_message: capture.error_message, error_code: capture.error_code, diff --git a/crates/router/src/utils/user/sample_data.rs b/crates/router/src/utils/user/sample_data.rs index 1f7d75fba8..122989a82c 100644 --- a/crates/router/src/utils/user/sample_data.rs +++ b/crates/router/src/utils/user/sample_data.rs @@ -2,7 +2,10 @@ use api_models::{ enums::Connector::{DummyConnector4, DummyConnector7}, user::sample_data::SampleDataRequest, }; -use common_utils::{id_type, types::MinorUnit}; +use common_utils::{ + id_type, + types::{ConnectorTransactionId, MinorUnit}, +}; use diesel_models::{user::sample_data::PaymentAttemptBatchNew, RefundNew}; use error_stack::ResultExt; use hyperswitch_domain_models::payments::PaymentIntent; @@ -253,10 +256,12 @@ pub async fn generate_sample_data( tax_details: None, skip_external_tax_calculation: None, }; + let (connector_transaction_id, connector_transaction_data) = + ConnectorTransactionId::form_id_and_data(attempt_id.clone()); let payment_attempt = PaymentAttemptBatchNew { attempt_id: attempt_id.clone(), payment_id: payment_id.clone(), - connector_transaction_id: Some(attempt_id.clone()), + connector_transaction_id: Some(connector_transaction_id), merchant_id: merchant_id.clone(), status: match is_failed_payment { true => common_enums::AttemptStatus::Failure, @@ -333,18 +338,21 @@ pub async fn generate_sample_data( organization_id: org_id.clone(), shipping_cost: None, order_tax_amount: None, + connector_transaction_data, }; let refund = if refunds_count < number_of_refunds && !is_failed_payment { refunds_count += 1; + let (connector_transaction_id, connector_transaction_data) = + ConnectorTransactionId::form_id_and_data(attempt_id.clone()); Some(RefundNew { refund_id: common_utils::generate_id_with_default_len("test"), internal_reference_id: common_utils::generate_id_with_default_len("test"), external_reference_id: None, payment_id: payment_id.clone(), - attempt_id: attempt_id.clone(), + attempt_id, merchant_id: merchant_id.clone(), - connector_transaction_id: attempt_id.clone(), + connector_transaction_id, connector_refund_id: None, description: Some("This is a sample refund".to_string()), created_at, @@ -369,6 +377,8 @@ pub async fn generate_sample_data( merchant_connector_id: payment_attempt.merchant_connector_id.clone(), charges: None, organization_id: org_id.clone(), + connector_refund_data: None, + connector_transaction_data, }) } else { None diff --git a/crates/router/tests/connectors/sample_auth.toml b/crates/router/tests/connectors/sample_auth.toml index f61770a5bd..2b20ed4cf1 100644 --- a/crates/router/tests/connectors/sample_auth.toml +++ b/crates/router/tests/connectors/sample_auth.toml @@ -30,6 +30,7 @@ api_key = "Bearer MyApiKey" [worldpay] api_key = "api_key" key1 = "key1" +api_secret = "Merchant Identifier" [payu] api_key = "Bearer MyApiKey" diff --git a/crates/router/tests/connectors/worldpay.rs b/crates/router/tests/connectors/worldpay.rs index d4f6e167ff..451aa398eb 100644 --- a/crates/router/tests/connectors/worldpay.rs +++ b/crates/router/tests/connectors/worldpay.rs @@ -20,7 +20,7 @@ impl utils::Connector for Worldpay { fn get_data(&self) -> types::api::ConnectorData { use router::connector::Worldpay; utils::construct_connector_data_old( - Box::new(&Worldpay), + Box::new(Worldpay::new()), types::Connector::Worldpay, types::api::GetToken::Connector, None, diff --git a/crates/storage_impl/src/lookup.rs b/crates/storage_impl/src/lookup.rs index 943ef1f36f..54377e4526 100644 --- a/crates/storage_impl/src/lookup.rs +++ b/crates/storage_impl/src/lookup.rs @@ -97,13 +97,13 @@ impl ReverseLookupInterface for KVRouterStore { }, }; - match kv_wrapper::( + match Box::pin(kv_wrapper::( self, KvOperation::SetNx(&created_rev_lookup, redis_entry), PartitionKey::CombinationKey { combination: &format!("reverse_lookup_{}", &created_rev_lookup.lookup_id), }, - ) + )) .await .map_err(|err| err.to_redis_failed_response(&created_rev_lookup.lookup_id))? .try_into_setnx() @@ -140,13 +140,13 @@ impl ReverseLookupInterface for KVRouterStore { storage_enums::MerchantStorageScheme::PostgresOnly => database_call().await, storage_enums::MerchantStorageScheme::RedisKv => { let redis_fut = async { - kv_wrapper( + Box::pin(kv_wrapper( self, KvOperation::::Get, PartitionKey::CombinationKey { combination: &format!("reverse_lookup_{id}"), }, - ) + )) .await? .try_into_get() }; diff --git a/crates/storage_impl/src/payments/payment_attempt.rs b/crates/storage_impl/src/payments/payment_attempt.rs index 20b46a8460..024ab9fd81 100644 --- a/crates/storage_impl/src/payments/payment_attempt.rs +++ b/crates/storage_impl/src/payments/payment_attempt.rs @@ -1,6 +1,10 @@ #[cfg(feature = "v2")] use common_utils::types::keymanager::KeyManagerState; -use common_utils::{errors::CustomResult, fallback_reverse_lookup_not_found}; +use common_utils::{ + errors::CustomResult, + fallback_reverse_lookup_not_found, + types::{ConnectorTransactionId, ConnectorTransactionIdTrait}, +}; use diesel_models::{ enums::{ MandateAmountData as DieselMandateAmountData, MandateDataType as DieselMandateType, @@ -554,7 +558,7 @@ impl PaymentAttemptInterface for KVRouterStore { self.insert_reverse_lookup(reverse_lookup, storage_scheme) .await?; - match kv_wrapper::( + match Box::pin(kv_wrapper::( self, KvOperation::HSetNx( &field, @@ -562,7 +566,7 @@ impl PaymentAttemptInterface for KVRouterStore { redis_entry, ), key, - ) + )) .await .map_err(|err| err.to_redis_failed_response(&key_str))? .try_into_hsetnx() @@ -626,7 +630,7 @@ impl PaymentAttemptInterface for KVRouterStore { } MerchantStorageScheme::RedisKv => { let key_str = key.to_string(); - let old_connector_transaction_id = &this.connector_transaction_id; + let old_connector_transaction_id = &this.get_connector_payment_id(); let old_preprocessing_id = &this.preprocessing_step_id; let updated_attempt = PaymentAttempt::from_storage_model( payment_attempt @@ -651,7 +655,7 @@ impl PaymentAttemptInterface for KVRouterStore { match ( old_connector_transaction_id, - &updated_attempt.connector_transaction_id, + &updated_attempt.get_connector_payment_id(), ) { (None, Some(connector_transaction_id)) => { add_connector_txn_id_to_reverse_lookup( @@ -659,7 +663,7 @@ impl PaymentAttemptInterface for KVRouterStore { key_str.as_str(), &this.merchant_id, updated_attempt.attempt_id.as_str(), - connector_transaction_id.as_str(), + connector_transaction_id, storage_scheme, ) .await?; @@ -671,7 +675,7 @@ impl PaymentAttemptInterface for KVRouterStore { key_str.as_str(), &this.merchant_id, updated_attempt.attempt_id.as_str(), - connector_transaction_id.as_str(), + connector_transaction_id, storage_scheme, ) .await?; @@ -708,11 +712,11 @@ impl PaymentAttemptInterface for KVRouterStore { (_, _) => {} } - kv_wrapper::<(), _, _>( + Box::pin(kv_wrapper::<(), _, _>( self, KvOperation::Hset::((&field, redis_value), redis_entry), key, - ) + )) .await .change_context(errors::StorageError::KVError)? .try_into_hset() @@ -796,7 +800,7 @@ impl PaymentAttemptInterface for KVRouterStore { Box::pin(try_redis_get_else_try_database_get( async { - kv_wrapper(self, KvOperation::::HGet(&lookup.sk_id), key).await?.try_into_hget() + Box::pin(kv_wrapper(self, KvOperation::::HGet(&lookup.sk_id), key)).await?.try_into_hget() }, || async {self.router_store.find_payment_attempt_by_connector_transaction_id_payment_id_merchant_id(connector_transaction_id, payment_id, merchant_id, storage_scheme).await}, )) @@ -837,11 +841,11 @@ impl PaymentAttemptInterface for KVRouterStore { let pattern = "pa_*"; let redis_fut = async { - let kv_result = kv_wrapper::( + let kv_result = Box::pin(kv_wrapper::( self, KvOperation::::Scan(pattern), key, - ) + )) .await? .try_into_scan(); kv_result.and_then(|mut payment_attempts| { @@ -896,11 +900,11 @@ impl PaymentAttemptInterface for KVRouterStore { let pattern = "pa_*"; let redis_fut = async { - let kv_result = kv_wrapper::( + let kv_result = Box::pin(kv_wrapper::( self, KvOperation::::Scan(pattern), key, - ) + )) .await? .try_into_scan(); kv_result.and_then(|mut payment_attempts| { @@ -972,11 +976,11 @@ impl PaymentAttemptInterface for KVRouterStore { }; Box::pin(try_redis_get_else_try_database_get( async { - kv_wrapper( + Box::pin(kv_wrapper( self, KvOperation::::HGet(&lookup.sk_id), key, - ) + )) .await? .try_into_hget() }, @@ -1029,9 +1033,13 @@ impl PaymentAttemptInterface for KVRouterStore { let field = format!("pa_{attempt_id}"); Box::pin(try_redis_get_else_try_database_get( async { - kv_wrapper(self, KvOperation::::HGet(&field), key) - .await? - .try_into_hget() + Box::pin(kv_wrapper( + self, + KvOperation::::HGet(&field), + key, + )) + .await? + .try_into_hget() }, || async { self.router_store @@ -1092,11 +1100,11 @@ impl PaymentAttemptInterface for KVRouterStore { }; Box::pin(try_redis_get_else_try_database_get( async { - kv_wrapper( + Box::pin(kv_wrapper( self, KvOperation::::HGet(&lookup.sk_id), key, - ) + )) .await? .try_into_hget() }, @@ -1181,11 +1189,11 @@ impl PaymentAttemptInterface for KVRouterStore { Box::pin(try_redis_get_else_try_database_get( async { - kv_wrapper( + Box::pin(kv_wrapper( self, KvOperation::::HGet(&lookup.sk_id), key, - ) + )) .await? .try_into_hget() }, @@ -1235,9 +1243,13 @@ impl PaymentAttemptInterface for KVRouterStore { }; Box::pin(try_redis_get_else_try_database_get( async { - kv_wrapper(self, KvOperation::::Scan("pa_*"), key) - .await? - .try_into_scan() + Box::pin(kv_wrapper( + self, + KvOperation::::Scan("pa_*"), + key, + )) + .await? + .try_into_scan() }, || async { self.router_store @@ -1363,6 +1375,11 @@ impl DataModelExt for PaymentAttempt { type StorageModel = DieselPaymentAttempt; fn to_storage_model(self) -> Self::StorageModel { + let (connector_transaction_id, connector_transaction_data) = self + .connector_transaction_id + .map(ConnectorTransactionId::form_id_and_data) + .map(|(txn_id, txn_data)| (Some(txn_id), txn_data)) + .unwrap_or((None, None)); DieselPaymentAttempt { payment_id: self.payment_id, merchant_id: self.merchant_id, @@ -1379,7 +1396,7 @@ impl DataModelExt for PaymentAttempt { tax_amount: self.net_amount.get_tax_on_surcharge(), payment_method_id: self.payment_method_id, payment_method: self.payment_method, - connector_transaction_id: self.connector_transaction_id, + connector_transaction_id, capture_method: self.capture_method, capture_on: self.capture_on, confirm: self.confirm, @@ -1433,12 +1450,16 @@ impl DataModelExt for PaymentAttempt { customer_acceptance: self.customer_acceptance, organization_id: self.organization_id, profile_id: self.profile_id, + connector_transaction_data, shipping_cost: self.net_amount.get_shipping_cost(), order_tax_amount: self.net_amount.get_order_tax_amount(), } } fn from_storage_model(storage_model: Self::StorageModel) -> Self { + let connector_transaction_id = storage_model + .get_optional_connector_transaction_id() + .cloned(); Self { net_amount: hyperswitch_domain_models::payments::payment_attempt::NetAmount::new( storage_model.amount, @@ -1458,7 +1479,7 @@ impl DataModelExt for PaymentAttempt { offer_amount: storage_model.offer_amount, payment_method_id: storage_model.payment_method_id, payment_method: storage_model.payment_method, - connector_transaction_id: storage_model.connector_transaction_id, + connector_transaction_id, capture_method: storage_model.capture_method, capture_on: storage_model.capture_on, confirm: storage_model.confirm, diff --git a/crates/storage_impl/src/payments/payment_intent.rs b/crates/storage_impl/src/payments/payment_intent.rs index f5c3deeb18..8ca63e7903 100644 --- a/crates/storage_impl/src/payments/payment_intent.rs +++ b/crates/storage_impl/src/payments/payment_intent.rs @@ -113,7 +113,7 @@ impl PaymentIntentInterface for KVRouterStore { .await .change_context(StorageError::EncryptionError)?; - match kv_wrapper::( + match Box::pin(kv_wrapper::( self, KvOperation::::HSetNx( &field, @@ -121,7 +121,7 @@ impl PaymentIntentInterface for KVRouterStore { redis_entry, ), key, - ) + )) .await .map_err(|err| err.to_redis_failed_response(&key_str))? .try_into_hsetnx() @@ -228,11 +228,11 @@ impl PaymentIntentInterface for KVRouterStore { }, }; - kv_wrapper::<(), _, _>( + Box::pin(kv_wrapper::<(), _, _>( self, KvOperation::::Hset((&field, redis_value), redis_entry), key, - ) + )) .await .map_err(|err| err.to_redis_failed_response(&key_str))? .try_into_hset() @@ -316,11 +316,11 @@ impl PaymentIntentInterface for KVRouterStore { let field = payment_id.get_hash_key_for_kv_store(); Box::pin(utils::try_redis_get_else_try_database_get( async { - kv_wrapper::( + Box::pin(kv_wrapper::( self, KvOperation::::HGet(&field), key, - ) + )) .await? .try_into_hget() }, diff --git a/crates/storage_impl/src/payouts/payout_attempt.rs b/crates/storage_impl/src/payouts/payout_attempt.rs index 33d73f99e5..81d06a1cbd 100644 --- a/crates/storage_impl/src/payouts/payout_attempt.rs +++ b/crates/storage_impl/src/payouts/payout_attempt.rs @@ -115,7 +115,7 @@ impl PayoutAttemptInterface for KVRouterStore { self.insert_reverse_lookup(reverse_lookup, storage_scheme) .await?; - match kv_wrapper::( + match Box::pin(kv_wrapper::( self, KvOperation::::HSetNx( &field, @@ -123,7 +123,7 @@ impl PayoutAttemptInterface for KVRouterStore { redis_entry, ), key, - ) + )) .await .map_err(|err| err.to_redis_failed_response(&key_str))? .try_into_hsetnx() @@ -227,11 +227,11 @@ impl PayoutAttemptInterface for KVRouterStore { _ => {} } - kv_wrapper::<(), _, _>( + Box::pin(kv_wrapper::<(), _, _>( self, KvOperation::::Hset((&field, redis_value), redis_entry), key, - ) + )) .await .map_err(|err| err.to_redis_failed_response(&key_str))? .try_into_hset() @@ -284,11 +284,11 @@ impl PayoutAttemptInterface for KVRouterStore { }; Box::pin(utils::try_redis_get_else_try_database_get( async { - kv_wrapper( + Box::pin(kv_wrapper( self, KvOperation::::HGet(&lookup.sk_id), key, - ) + )) .await? .try_into_hget() }, @@ -345,11 +345,11 @@ impl PayoutAttemptInterface for KVRouterStore { }; Box::pin(utils::try_redis_get_else_try_database_get( async { - kv_wrapper( + Box::pin(kv_wrapper( self, KvOperation::::HGet(&lookup.sk_id), key, - ) + )) .await? .try_into_hget() }, diff --git a/crates/storage_impl/src/payouts/payouts.rs b/crates/storage_impl/src/payouts/payouts.rs index 2a49b01458..9a94743da3 100644 --- a/crates/storage_impl/src/payouts/payouts.rs +++ b/crates/storage_impl/src/payouts/payouts.rs @@ -134,7 +134,7 @@ impl PayoutsInterface for KVRouterStore { }, }; - match kv_wrapper::( + match Box::pin(kv_wrapper::( self, KvOperation::::HSetNx( &field, @@ -142,7 +142,7 @@ impl PayoutsInterface for KVRouterStore { redis_entry, ), key, - ) + )) .await .map_err(|err| err.to_redis_failed_response(&key_str))? .try_into_hsetnx() @@ -208,11 +208,11 @@ impl PayoutsInterface for KVRouterStore { }, }; - kv_wrapper::<(), _, _>( + Box::pin(kv_wrapper::<(), _, _>( self, KvOperation::::Hset((&field, redis_value), redis_entry), key, - ) + )) .await .map_err(|err| err.to_redis_failed_response(&key_str))? .try_into_hset() @@ -255,11 +255,11 @@ impl PayoutsInterface for KVRouterStore { let field = format!("po_{payout_id}"); Box::pin(utils::try_redis_get_else_try_database_get( async { - kv_wrapper::( + Box::pin(kv_wrapper::( self, KvOperation::::HGet(&field), key, - ) + )) .await? .try_into_hget() }, @@ -312,11 +312,11 @@ impl PayoutsInterface for KVRouterStore { let field = format!("po_{payout_id}"); Box::pin(utils::try_redis_get_else_try_database_get( async { - kv_wrapper::( + Box::pin(kv_wrapper::( self, KvOperation::::HGet(&field), key, - ) + )) .await? .try_into_hget() .map(Some) diff --git a/crates/storage_impl/src/redis/kv_store.rs b/crates/storage_impl/src/redis/kv_store.rs index 74b1526fe8..2fde935b67 100644 --- a/crates/storage_impl/src/redis/kv_store.rs +++ b/crates/storage_impl/src/redis/kv_store.rs @@ -312,8 +312,12 @@ where Op::Find => MerchantStorageScheme::RedisKv, Op::Update(_, _, Some("postgres_only")) => MerchantStorageScheme::PostgresOnly, Op::Update(partition_key, field, Some(_updated_by)) => { - match kv_wrapper::(store, KvOperation::::HGet(field), partition_key) - .await + match Box::pin(kv_wrapper::( + store, + KvOperation::::HGet(field), + partition_key, + )) + .await { Ok(_) => { metrics::KV_SOFT_KILL_ACTIVE_UPDATE.add(&metrics::CONTEXT, 1, &[]); diff --git a/crates/test_utils/tests/sample_auth.toml b/crates/test_utils/tests/sample_auth.toml index 08b24817c2..c7ec4f12c5 100644 --- a/crates/test_utils/tests/sample_auth.toml +++ b/crates/test_utils/tests/sample_auth.toml @@ -30,6 +30,7 @@ api_key = "Bearer MyApiKey" [worldpay] api_key = "api_key" key1 = "key1" +api_secret = "Merchant Identifier" [payu] api_key = "Bearer MyApiKey" diff --git a/cypress-tests-v2/cypress/e2e/configs/Payment/Commons.js b/cypress-tests-v2/cypress/e2e/configs/Payment/Commons.js index ea7b4f09fd..c2d1b7483c 100644 --- a/cypress-tests-v2/cypress/e2e/configs/Payment/Commons.js +++ b/cypress-tests-v2/cypress/e2e/configs/Payment/Commons.js @@ -1069,7 +1069,7 @@ export const connectorDetails = { status: 400, body: { error: - "Json deserialize error: unknown variant `United`, expected one of `AED`, `ALL`, `AMD`, `ANG`, `AOA`, `ARS`, `AUD`, `AWG`, `AZN`, `BAM`, `BBD`, `BDT`, `BGN`, `BHD`, `BIF`, `BMD`, `BND`, `BOB`, `BRL`, `BSD`, `BWP`, `BYN`, `BZD`, `CAD`, `CHF`, `CLP`, `CNY`, `COP`, `CRC`, `CUP`, `CVE`, `CZK`, `DJF`, `DKK`, `DOP`, `DZD`, `EGP`, `ETB`, `EUR`, `FJD`, `FKP`, `GBP`, `GEL`, `GHS`, `GIP`, `GMD`, `GNF`, `GTQ`, `GYD`, `HKD`, `HNL`, `HRK`, `HTG`, `HUF`, `IDR`, `ILS`, `INR`, `IQD`, `JMD`, `JOD`, `JPY`, `KES`, `KGS`, `KHR`, `KMF`, `KRW`, `KWD`, `KYD`, `KZT`, `LAK`, `LBP`, `LKR`, `LRD`, `LSL`, `LYD`, `MAD`, `MDL`, `MGA`, `MKD`, `MMK`, `MNT`, `MOP`, `MRU`, `MUR`, `MVR`, `MWK`, `MXN`, `MYR`, `MZN`, `NAD`, `NGN`, `NIO`, `NOK`, `NPR`, `NZD`, `OMR`, `PAB`, `PEN`, `PGK`, `PHP`, `PKR`, `PLN`, `PYG`, `QAR`, `RON`, `RSD`, `RUB`, `RWF`, `SAR`, `SBD`, `SCR`, `SEK`, `SGD`, `SHP`, `SLE`, `SLL`, `SOS`, `SRD`, `SSP`, `STN`, `SVC`, `SZL`, `THB`, `TND`, `TOP`, `TRY`, `TTD`, `TWD`, `TZS`, `UAH`, `UGX`, `USD`, `UYU`, `UZS`, `VES`, `VND`, `VUV`, `WST`, `XAF`, `XCD`, `XOF`, `XPF`, `YER`, `ZAR`, `ZMW`", + "Json deserialize error: unknown variant `United`, expected one of `AED`, `AFN`, `ALL`, `AMD`, `ANG`, `AOA`, `ARS`, `AUD`, `AWG`, `AZN`, `BAM`, `BBD`, `BDT`, `BGN`, `BHD`, `BIF`, `BMD`, `BND`, `BOB`, `BRL`, `BSD`, `BTN`, `BWP`, `BYN`, `BZD`, `CAD`, `CDF`, `CHF`, `CLP`, `CNY`, `COP`, `CRC`, `CUP`, `CVE`, `CZK`, `DJF`, `DKK`, `DOP`, `DZD`, `EGP`, `ERN`, `ETB`, `EUR`, `FJD`, `FKP`, `GBP`, `GEL`, `GHS`, `GIP`, `GMD`, `GNF`, `GTQ`, `GYD`, `HKD`, `HNL`, `HRK`, `HTG`, `HUF`, `IDR`, `ILS`, `INR`, `IQD`, `IRR`, `ISK`, `JMD`, `JOD`, `JPY`, `KES`, `KGS`, `KHR`, `KMF`, `KPW`, `KRW`, `KWD`, `KYD`, `KZT`, `LAK`, `LBP`, `LKR`, `LRD`, `LSL`, `LYD`, `MAD`, `MDL`, `MGA`, `MKD`, `MMK`, `MNT`, `MOP`, `MRU`, `MUR`, `MVR`, `MWK`, `MXN`, `MYR`, `MZN`, `NAD`, `NGN`, `NIO`, `NOK`, `NPR`, `NZD`, `OMR`, `PAB`, `PEN`, `PGK`, `PHP`, `PKR`, `PLN`, `PYG`, `QAR`, `RON`, `RSD`, `RUB`, `RWF`, `SAR`, `SBD`, `SCR`, `SDG`, `SEK`, `SGD`, `SHP`, `SLE`, `SLL`, `SOS`, `SRD`, `SSP`, `STN`, `SVC`, `SYP`, `SZL`, `THB`, `TJS`, `TMT`, `TND`, `TOP`, `TRY`, `TTD`, `TWD`, `TZS`, `UAH`, `UGX`, `USD`, `UYU`, `UZS`, `VES`, `VND`, `VUV`, `WST`, `XAF`, `XCD`, `XOF`, `XPF`, `YER`, `ZAR`, `ZMW`, `ZWL`", }, }, }, diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Commons.js b/cypress-tests/cypress/e2e/PaymentUtils/Commons.js index 284eff5fd1..73e54fee91 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Commons.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Commons.js @@ -1073,7 +1073,7 @@ export const connectorDetails = { status: 400, body: { error: - "Json deserialize error: unknown variant `United`, expected one of `AED`, `ALL`, `AMD`, `ANG`, `AOA`, `ARS`, `AUD`, `AWG`, `AZN`, `BAM`, `BBD`, `BDT`, `BGN`, `BHD`, `BIF`, `BMD`, `BND`, `BOB`, `BRL`, `BSD`, `BWP`, `BYN`, `BZD`, `CAD`, `CHF`, `CLP`, `CNY`, `COP`, `CRC`, `CUP`, `CVE`, `CZK`, `DJF`, `DKK`, `DOP`, `DZD`, `EGP`, `ETB`, `EUR`, `FJD`, `FKP`, `GBP`, `GEL`, `GHS`, `GIP`, `GMD`, `GNF`, `GTQ`, `GYD`, `HKD`, `HNL`, `HRK`, `HTG`, `HUF`, `IDR`, `ILS`, `INR`, `IQD`, `JMD`, `JOD`, `JPY`, `KES`, `KGS`, `KHR`, `KMF`, `KRW`, `KWD`, `KYD`, `KZT`, `LAK`, `LBP`, `LKR`, `LRD`, `LSL`, `LYD`, `MAD`, `MDL`, `MGA`, `MKD`, `MMK`, `MNT`, `MOP`, `MRU`, `MUR`, `MVR`, `MWK`, `MXN`, `MYR`, `MZN`, `NAD`, `NGN`, `NIO`, `NOK`, `NPR`, `NZD`, `OMR`, `PAB`, `PEN`, `PGK`, `PHP`, `PKR`, `PLN`, `PYG`, `QAR`, `RON`, `RSD`, `RUB`, `RWF`, `SAR`, `SBD`, `SCR`, `SEK`, `SGD`, `SHP`, `SLE`, `SLL`, `SOS`, `SRD`, `SSP`, `STN`, `SVC`, `SZL`, `THB`, `TND`, `TOP`, `TRY`, `TTD`, `TWD`, `TZS`, `UAH`, `UGX`, `USD`, `UYU`, `UZS`, `VES`, `VND`, `VUV`, `WST`, `XAF`, `XCD`, `XOF`, `XPF`, `YER`, `ZAR`, `ZMW`", + "Json deserialize error: unknown variant `United`, expected one of `AED`, `AFN`, `ALL`, `AMD`, `ANG`, `AOA`, `ARS`, `AUD`, `AWG`, `AZN`, `BAM`, `BBD`, `BDT`, `BGN`, `BHD`, `BIF`, `BMD`, `BND`, `BOB`, `BRL`, `BSD`, `BTN`, `BWP`, `BYN`, `BZD`, `CAD`, `CDF`, `CHF`, `CLP`, `CNY`, `COP`, `CRC`, `CUP`, `CVE`, `CZK`, `DJF`, `DKK`, `DOP`, `DZD`, `EGP`, `ERN`, `ETB`, `EUR`, `FJD`, `FKP`, `GBP`, `GEL`, `GHS`, `GIP`, `GMD`, `GNF`, `GTQ`, `GYD`, `HKD`, `HNL`, `HRK`, `HTG`, `HUF`, `IDR`, `ILS`, `INR`, `IQD`, `IRR`, `ISK`, `JMD`, `JOD`, `JPY`, `KES`, `KGS`, `KHR`, `KMF`, `KPW`, `KRW`, `KWD`, `KYD`, `KZT`, `LAK`, `LBP`, `LKR`, `LRD`, `LSL`, `LYD`, `MAD`, `MDL`, `MGA`, `MKD`, `MMK`, `MNT`, `MOP`, `MRU`, `MUR`, `MVR`, `MWK`, `MXN`, `MYR`, `MZN`, `NAD`, `NGN`, `NIO`, `NOK`, `NPR`, `NZD`, `OMR`, `PAB`, `PEN`, `PGK`, `PHP`, `PKR`, `PLN`, `PYG`, `QAR`, `RON`, `RSD`, `RUB`, `RWF`, `SAR`, `SBD`, `SCR`, `SDG`, `SEK`, `SGD`, `SHP`, `SLE`, `SLL`, `SOS`, `SRD`, `SSP`, `STN`, `SVC`, `SYP`, `SZL`, `THB`, `TJS`, `TMT`, `TND`, `TOP`, `TRY`, `TTD`, `TWD`, `TZS`, `UAH`, `UGX`, `USD`, `UYU`, `UZS`, `VES`, `VND`, `VUV`, `WST`, `XAF`, `XCD`, `XOF`, `XPF`, `YER`, `ZAR`, `ZMW`, `ZWL`", }, }, }, diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Paybox.js b/cypress-tests/cypress/e2e/PaymentUtils/Paybox.js index c54349b325..8fbb8c0b07 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Paybox.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Paybox.js @@ -256,7 +256,7 @@ export const connectorDetails = { status: 400, body: { error: - "Json deserialize error: unknown variant `United`, expected one of `AED`, `ALL`, `AMD`, `ANG`, `AOA`, `ARS`, `AUD`, `AWG`, `AZN`, `BAM`, `BBD`, `BDT`, `BGN`, `BHD`, `BIF`, `BMD`, `BND`, `BOB`, `BRL`, `BSD`, `BWP`, `BYN`, `BZD`, `CAD`, `CHF`, `CLP`, `CNY`, `COP`, `CRC`, `CUP`, `CVE`, `CZK`, `DJF`, `DKK`, `DOP`, `DZD`, `EGP`, `ETB`, `EUR`, `FJD`, `FKP`, `GBP`, `GEL`, `GHS`, `GIP`, `GMD`, `GNF`, `GTQ`, `GYD`, `HKD`, `HNL`, `HRK`, `HTG`, `HUF`, `IDR`, `ILS`, `INR`, `IQD`, `JMD`, `JOD`, `JPY`, `KES`, `KGS`, `KHR`, `KMF`, `KRW`, `KWD`, `KYD`, `KZT`, `LAK`, `LBP`, `LKR`, `LRD`, `LSL`, `LYD`, `MAD`, `MDL`, `MGA`, `MKD`, `MMK`, `MNT`, `MOP`, `MRU`, `MUR`, `MVR`, `MWK`, `MXN`, `MYR`, `MZN`, `NAD`, `NGN`, `NIO`, `NOK`, `NPR`, `NZD`, `OMR`, `PAB`, `PEN`, `PGK`, `PHP`, `PKR`, `PLN`, `PYG`, `QAR`, `RON`, `RSD`, `RUB`, `RWF`, `SAR`, `SBD`, `SCR`, `SEK`, `SGD`, `SHP`, `SLE`, `SLL`, `SOS`, `SRD`, `SSP`, `STN`, `SVC`, `SZL`, `THB`, `TND`, `TOP`, `TRY`, `TTD`, `TWD`, `TZS`, `UAH`, `UGX`, `USD`, `UYU`, `UZS`, `VES`, `VND`, `VUV`, `WST`, `XAF`, `XCD`, `XOF`, `XPF`, `YER`, `ZAR`, `ZMW`", + "Json deserialize error: unknown variant `United`, expected one of `AED`, `AFN`, `ALL`, `AMD`, `ANG`, `AOA`, `ARS`, `AUD`, `AWG`, `AZN`, `BAM`, `BBD`, `BDT`, `BGN`, `BHD`, `BIF`, `BMD`, `BND`, `BOB`, `BRL`, `BSD`, `BTN`, `BWP`, `BYN`, `BZD`, `CAD`, `CDF`, `CHF`, `CLP`, `CNY`, `COP`, `CRC`, `CUP`, `CVE`, `CZK`, `DJF`, `DKK`, `DOP`, `DZD`, `EGP`, `ERN`, `ETB`, `EUR`, `FJD`, `FKP`, `GBP`, `GEL`, `GHS`, `GIP`, `GMD`, `GNF`, `GTQ`, `GYD`, `HKD`, `HNL`, `HRK`, `HTG`, `HUF`, `IDR`, `ILS`, `INR`, `IQD`, `IRR`, `ISK`, `JMD`, `JOD`, `JPY`, `KES`, `KGS`, `KHR`, `KMF`, `KPW`, `KRW`, `KWD`, `KYD`, `KZT`, `LAK`, `LBP`, `LKR`, `LRD`, `LSL`, `LYD`, `MAD`, `MDL`, `MGA`, `MKD`, `MMK`, `MNT`, `MOP`, `MRU`, `MUR`, `MVR`, `MWK`, `MXN`, `MYR`, `MZN`, `NAD`, `NGN`, `NIO`, `NOK`, `NPR`, `NZD`, `OMR`, `PAB`, `PEN`, `PGK`, `PHP`, `PKR`, `PLN`, `PYG`, `QAR`, `RON`, `RSD`, `RUB`, `RWF`, `SAR`, `SBD`, `SCR`, `SDG`, `SEK`, `SGD`, `SHP`, `SLE`, `SLL`, `SOS`, `SRD`, `SSP`, `STN`, `SVC`, `SYP`, `SZL`, `THB`, `TJS`, `TMT`, `TND`, `TOP`, `TRY`, `TTD`, `TWD`, `TZS`, `UAH`, `UGX`, `USD`, `UYU`, `UZS`, `VES`, `VND`, `VUV`, `WST`, `XAF`, `XCD`, `XOF`, `XPF`, `YER`, `ZAR`, `ZMW`, `ZWL`", }, }, }, diff --git a/migrations/2024-09-25-113851_increase_connector_transaction_id_length_in_payment_and_refund/down.sql b/migrations/2024-09-25-113851_increase_connector_transaction_id_length_in_payment_and_refund/down.sql new file mode 100644 index 0000000000..8008535f87 --- /dev/null +++ b/migrations/2024-09-25-113851_increase_connector_transaction_id_length_in_payment_and_refund/down.sql @@ -0,0 +1,11 @@ +ALTER TABLE payment_attempt +DROP COLUMN IF EXISTS connector_transaction_data; + +ALTER TABLE refund +DROP COLUMN IF EXISTS connector_refund_data; + +ALTER TABLE refund +DROP COLUMN IF EXISTS connector_transaction_data; + +ALTER TABLE captures +DROP COLUMN IF EXISTS connector_capture_data; \ No newline at end of file diff --git a/migrations/2024-09-25-113851_increase_connector_transaction_id_length_in_payment_and_refund/up.sql b/migrations/2024-09-25-113851_increase_connector_transaction_id_length_in_payment_and_refund/up.sql new file mode 100644 index 0000000000..adab6dd3ed --- /dev/null +++ b/migrations/2024-09-25-113851_increase_connector_transaction_id_length_in_payment_and_refund/up.sql @@ -0,0 +1,11 @@ +ALTER TABLE payment_attempt +ADD COLUMN IF NOT EXISTS connector_transaction_data VARCHAR(512); + +ALTER TABLE refund +ADD COLUMN IF NOT EXISTS connector_refund_data VARCHAR(512); + +ALTER TABLE refund +ADD COLUMN IF NOT EXISTS connector_transaction_data VARCHAR(512); + +ALTER TABLE captures +ADD COLUMN IF NOT EXISTS connector_capture_data VARCHAR(512); \ No newline at end of file diff --git a/v2_migrations/2024-08-28-081721_add_v2_columns/down.sql b/v2_migrations/2024-08-28-081721_add_v2_columns/down.sql index cfc769e70e..519bef65cb 100644 --- a/v2_migrations/2024-08-28-081721_add_v2_columns/down.sql +++ b/v2_migrations/2024-08-28-081721_add_v2_columns/down.sql @@ -38,4 +38,5 @@ ALTER TABLE payment_attempt DROP COLUMN payment_method_type_v2, DROP COLUMN routing_result, DROP COLUMN authentication_applied, DROP COLUMN external_reference_id, - DROP COLUMN tax_on_surcharge; + DROP COLUMN tax_on_surcharge, + DROP COLUMN connector_payment_data; diff --git a/v2_migrations/2024-08-28-081721_add_v2_columns/up.sql b/v2_migrations/2024-08-28-081721_add_v2_columns/up.sql index 520bbdf6e7..136bc55081 100644 --- a/v2_migrations/2024-08-28-081721_add_v2_columns/up.sql +++ b/v2_migrations/2024-08-28-081721_add_v2_columns/up.sql @@ -41,4 +41,5 @@ ADD COLUMN payment_method_type_v2 VARCHAR, ADD COLUMN routing_result JSONB, ADD COLUMN authentication_applied "AuthenticationType", ADD COLUMN external_reference_id VARCHAR(128), - ADD COLUMN tax_on_surcharge BIGINT; + ADD COLUMN tax_on_surcharge BIGINT, + ADD COLUMN connector_payment_data VARCHAR(512); diff --git a/v2_migrations/2024-08-28-081847_drop_v1_columns/down.sql b/v2_migrations/2024-10-08-081847_drop_v1_columns/down.sql similarity index 98% rename from v2_migrations/2024-08-28-081847_drop_v1_columns/down.sql rename to v2_migrations/2024-10-08-081847_drop_v1_columns/down.sql index 65e90b126f..2cdb029603 100644 --- a/v2_migrations/2024-08-28-081847_drop_v1_columns/down.sql +++ b/v2_migrations/2024-10-08-081847_drop_v1_columns/down.sql @@ -76,6 +76,7 @@ ADD COLUMN IF NOT EXISTS attempt_id VARCHAR(64) NOT NULL, ADD COLUMN offer_amount bigint, ADD COLUMN payment_method VARCHAR, ADD COLUMN connector_transaction_id VARCHAR(64), + ADD COLUMN connector_transaction_data VARCHAR(512), ADD COLUMN capture_method "CaptureMethod", ADD COLUMN capture_on TIMESTAMP, ADD COLUMN mandate_id VARCHAR(64), diff --git a/v2_migrations/2024-08-28-081847_drop_v1_columns/up.sql b/v2_migrations/2024-10-08-081847_drop_v1_columns/up.sql similarity index 98% rename from v2_migrations/2024-08-28-081847_drop_v1_columns/up.sql rename to v2_migrations/2024-10-08-081847_drop_v1_columns/up.sql index 55b0b19d0b..48ae811bf3 100644 --- a/v2_migrations/2024-08-28-081847_drop_v1_columns/up.sql +++ b/v2_migrations/2024-10-08-081847_drop_v1_columns/up.sql @@ -74,6 +74,7 @@ ALTER TABLE payment_attempt DROP COLUMN attempt_id, DROP COLUMN offer_amount, DROP COLUMN payment_method, DROP COLUMN connector_transaction_id, + DROP COLUMN connector_transaction_data, DROP COLUMN capture_method, DROP COLUMN capture_on, DROP COLUMN mandate_id,