Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(connector): [WorldPay] migrate from modular to standard payment APIs #6317

Merged
merged 35 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
88aaa4f
feat(worldpay): migrate to v7
kashif-m Sep 26, 2024
c5cb6a1
chore: run formatter
hyperswitch-bot[bot] Sep 26, 2024
bbcd0a5
refactor(db): increase connector_refund_id's length to 512
kashif-m Sep 26, 2024
d0c1637
refactor: re-generate schema_v2
kashif-m Sep 26, 2024
97561b7
refactor: resolve comments
kashif-m Sep 27, 2024
dbeff46
refactor: add pm_filters for worldpay and extend Currency enum
kashif-m Sep 27, 2024
5cd1f5e
docs(openapi): re-generate OpenAPI specification
hyperswitch-bot[bot] Sep 27, 2024
8acdb1b
refactor: remove redundant logs
kashif-m Sep 26, 2024
5aab9e9
feat: add domain type for connector_transaction_id for handling id.le…
kashif-m Oct 7, 2024
5268636
Merge remote-tracking branch 'origin/main' into worldpay-updates
kashif-m Oct 7, 2024
3984237
refactor: re-generate schema_v2
kashif-m Oct 7, 2024
33fb8cb
chore: run formatter
hyperswitch-bot[bot] Oct 7, 2024
bdeeb8d
refactor: v2 support
kashif-m Oct 8, 2024
9003400
refactor: rename drop v1 queries for ordering
kashif-m Oct 8, 2024
6c149d2
refactor(worldpay): form new status based on existing intent and atte…
kashif-m Oct 9, 2024
8cd8aa6
refactor: limit hashed connector's txn ID length to 50 characters and…
kashif-m Oct 9, 2024
6b678af
Merge remote-tracking branch 'origin/main' into worldpay-updates
kashif-m Oct 10, 2024
c7ecd6d
refactor(payment_attempt): restrict connector_transaction_data to die…
kashif-m Oct 14, 2024
8f81329
Merge remote-tracking branch 'origin/main' into worldpay-updates
kashif-m Oct 14, 2024
45e1c8c
refactor: fix clippy v2 suggestions
kashif-m Oct 14, 2024
954fea3
refactor: add missing down migration for v2 columns
kashif-m Oct 14, 2024
520e54e
fix: update cypress tests for compatibility with currency changes
kashif-m Oct 15, 2024
caeef6f
refactor(connector): [WorldPay] migrate from modular to standard paym…
kashif-m Oct 15, 2024
7c68125
chore: run formatter
hyperswitch-bot[bot] Oct 15, 2024
0d4318a
fix: update pm_filters for worldpay
kashif-m Oct 15, 2024
f9986e7
Merge remote-tracking branch 'origin/main' into worldpay-updates
kashif-m Oct 16, 2024
b0509b0
refactor: remove intent_status from ConnectorIntegration data for PSync
kashif-m Oct 16, 2024
f8a7c16
Merge remote-tracking branch 'origin/worldpay-updates' into worldpay-…
kashif-m Oct 16, 2024
2771e7d
Merge remote-tracking branch 'origin/main' into worldpay-wallets-api-…
kashif-m Oct 17, 2024
5fb6afc
fix(worldpay): update narrative for worldpay during authorize request
kashif-m Oct 17, 2024
e1fcfde
refactor(worldpay): updated transformers
kashif-m Oct 18, 2024
f43eff1
Merge remote-tracking branch 'origin/main' into worldpay-wallets-api-…
kashif-m Oct 18, 2024
a0f086c
fix: clippy fix
kashif-m Oct 18, 2024
1bee074
refactor: revert connector_txn_id query
kashif-m Oct 21, 2024
5cac931
refactor(connector): move WP correlation key to consts
kashif-m Oct 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions crates/connector_configs/toml/development.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3416,6 +3416,12 @@ key1="Password"
api_secret="Merchant Identifier"
[worldpay.connector_webhook_details]
merchant_secret="Source verification key"
[worldpay.metadata.merchant_name]
name="merchant_name"
label="Name of the merchant to de displayed during 3DS challenge"
placeholder="Enter Name of the merchant"
required=true
type="Text"

[[worldpay.metadata.apple_pay]]
name="certificate"
Expand Down
6 changes: 6 additions & 0 deletions crates/connector_configs/toml/production.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2473,6 +2473,12 @@ merchant_secret="Source verification key"
api_key="Username"
key1="Password"
api_secret="Merchant Identifier"
[worldpay.metadata.merchant_name]
name="merchant_name"
label="Name of the merchant to de displayed during 3DS challenge"
placeholder="Enter Name of the merchant"
required=true
type="Text"

[[worldpay.metadata.apple_pay]]
name="certificate"
Expand Down
6 changes: 6 additions & 0 deletions crates/connector_configs/toml/sandbox.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3406,6 +3406,12 @@ key1="Password"
api_secret="Merchant Identifier"
[worldpay.connector_webhook_details]
merchant_secret="Source verification key"
[worldpay.metadata.merchant_name]
name="merchant_name"
label="Name of the merchant to de displayed during 3DS challenge"
placeholder="Enter Name of the merchant"
required=true
type="Text"

[[worldpay.metadata.apple_pay]]
name="certificate"
Expand Down
1 change: 1 addition & 0 deletions crates/router/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ tracing-futures = { version = "0.2.5", features = ["tokio"] }
unicode-segmentation = "1.11.0"
unidecode = "0.3.0"
url = { version = "2.5.0", features = ["serde"] }
urlencoding = "2.1.3"
utoipa = { version = "4.2.0", features = ["preserve_order", "preserve_path_order", "time"] }
uuid = { version = "1.8.0", features = ["v4"] }
validator = "0.17.0"
Expand Down
4 changes: 4 additions & 0 deletions crates/router/src/connector/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,7 @@ impl PaymentsPreProcessingData for types::PaymentsPreProcessingData {
pub trait PaymentsCaptureRequestData {
fn is_multiple_capture(&self) -> bool;
fn get_browser_info(&self) -> Result<BrowserInformation, Error>;
fn get_capture_method(&self) -> Option<enums::CaptureMethod>;
}

impl PaymentsCaptureRequestData for types::PaymentsCaptureData {
Expand All @@ -736,6 +737,9 @@ impl PaymentsCaptureRequestData for types::PaymentsCaptureData {
.clone()
.ok_or_else(missing_field_err("browser_info"))
}
fn get_capture_method(&self) -> Option<enums::CaptureMethod> {
self.capture_method.to_owned()
}
}

pub trait RevokeMandateRequestData {
Expand Down
104 changes: 74 additions & 30 deletions crates/router/src/connector/worldpay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use self::{requests::*, response::*};
use super::utils::{self as connector_utils, RefundsRequestData};
use crate::{
configs::settings,
consts,
core::errors::{self, CustomResult},
events::connector_api_logs::ConnectorEvent,
headers,
Expand Down Expand Up @@ -64,6 +65,7 @@ where
headers::CONTENT_TYPE.to_string(),
self.get_content_type().to_string().into(),
),
(headers::X_WP_API_VERSION.to_string(), "2024-06-01".into()),
];
let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
headers.append(&mut api_key);
Expand All @@ -81,7 +83,7 @@ impl ConnectorCommon for Worldpay {
}

fn common_get_content_type(&self) -> &'static str {
"application/vnd.worldpay.payments-v7+json"
"application/json"
}

fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str {
Expand Down Expand Up @@ -205,8 +207,9 @@ impl ConnectorIntegration<api::Void, types::PaymentsCancelData, types::PaymentsR
) -> CustomResult<String, errors::ConnectorError> {
let connector_payment_id = req.request.connector_transaction_id.clone();
Ok(format!(
"{}payments/authorizations/cancellations/{connector_payment_id}",
"{}api/payments/{}/cancellations",
self.base_url(connectors),
urlencoding::encode(&connector_payment_id),
))
}

Expand Down Expand Up @@ -244,15 +247,24 @@ impl ConnectorIntegration<api::Void, types::PaymentsCancelData, types::PaymentsR
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
event_builder.map(|i| i.set_response_body(&response));
router_env::logger::info!(connector_response=?response);
let optional_correlation_id = res.headers.and_then(|headers| {
headers
.get(consts::WP_CORRELATION_ID)
.and_then(|header_value| header_value.to_str().ok())
.map(|id| id.to_string())
});
Ok(types::PaymentsCancelRouterData {
status: enums::AttemptStatus::Voided,
status: enums::AttemptStatus::from(response.outcome.clone()),
response: Ok(types::PaymentsResponseData::TransactionResponse {
resource_id: types::ResponseId::foreign_try_from(response.links)?,
resource_id: types::ResponseId::foreign_try_from((
response,
Some(data.request.connector_transaction_id.clone()),
))?,
redirection_data: None,
mandate_reference: None,
connector_metadata: None,
network_txn_id: None,
connector_response_reference_id: None,
connector_response_reference_id: optional_correlation_id,
incremental_authorization_allowed: None,
charge_id: None,
}),
Expand Down Expand Up @@ -306,9 +318,9 @@ impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsRe
.get_connector_transaction_id()
.change_context(errors::ConnectorError::MissingConnectorTransactionID)?;
Ok(format!(
"{}payments/events/{}",
"{}api/payments/{}",
self.base_url(connectors),
connector_payment_id
urlencoding::encode(&connector_payment_id),
))
}

Expand Down Expand Up @@ -349,6 +361,12 @@ impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsRe
event_builder.map(|i| i.set_response_body(&response));
router_env::logger::info!(connector_response=?response);

let optional_correlation_id = res.headers.and_then(|headers| {
headers
.get(consts::WP_CORRELATION_ID)
.and_then(|header_value| header_value.to_str().ok())
.map(|id| id.to_string())
});
let attempt_status = data.status;
let worldpay_status = response.last_event;
let status = match (attempt_status, worldpay_status.clone()) {
Expand All @@ -371,7 +389,7 @@ impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsRe
mandate_reference: None,
connector_metadata: None,
network_txn_id: None,
connector_response_reference_id: None,
connector_response_reference_id: optional_correlation_id,
incremental_authorization_allowed: None,
charge_id: None,
}),
Expand Down Expand Up @@ -403,9 +421,9 @@ impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::Payme
) -> CustomResult<String, errors::ConnectorError> {
let connector_payment_id = req.request.connector_transaction_id.clone();
Ok(format!(
"{}payments/settlements/partials/{}",
"{}api/payments/{}/partialSettlements",
self.base_url(connectors),
connector_payment_id
urlencoding::encode(&connector_payment_id),
))
}

Expand Down Expand Up @@ -457,15 +475,24 @@ impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::Payme
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
event_builder.map(|i| i.set_response_body(&response));
router_env::logger::info!(connector_response=?response);
let optional_correlation_id = res.headers.and_then(|headers| {
headers
.get(consts::WP_CORRELATION_ID)
.and_then(|header_value| header_value.to_str().ok())
.map(|id| id.to_string())
});
Ok(types::PaymentsCaptureRouterData {
status: enums::AttemptStatus::Pending,
response: Ok(types::PaymentsResponseData::TransactionResponse {
resource_id: types::ResponseId::foreign_try_from(response.links)?,
resource_id: types::ResponseId::foreign_try_from((
response,
Some(data.request.connector_transaction_id.clone()),
))?,
redirection_data: None,
mandate_reference: None,
connector_metadata: None,
network_txn_id: None,
connector_response_reference_id: None,
connector_response_reference_id: optional_correlation_id,
incremental_authorization_allowed: None,
charge_id: None,
}),
Expand Down Expand Up @@ -514,10 +541,7 @@ impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::P
_req: &types::PaymentsAuthorizeRouterData,
connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
Ok(format!(
"{}cardPayments/customerInitiatedTransactions",
self.base_url(connectors)
))
Ok(format!("{}api/payments", self.base_url(connectors)))
}

fn get_request_body(
Expand Down Expand Up @@ -573,12 +597,21 @@ impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::P

event_builder.map(|i| i.set_response_body(&response));
router_env::logger::info!(connector_response=?response);

types::RouterData::try_from(types::ResponseRouterData {
response,
data: data.clone(),
http_code: res.status_code,
})
let optional_correlation_id = res.headers.and_then(|headers| {
headers
.get(consts::WP_CORRELATION_ID)
.and_then(|header_value| header_value.to_str().ok())
.map(|id| id.to_string())
});

types::RouterData::foreign_try_from((
types::ResponseRouterData {
response,
data: data.clone(),
http_code: res.status_code,
},
optional_correlation_id,
))
.change_context(errors::ConnectorError::ResponseHandlingFailed)
}

Expand Down Expand Up @@ -631,9 +664,9 @@ impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsRespon
) -> CustomResult<String, errors::ConnectorError> {
let connector_payment_id = req.request.connector_transaction_id.clone();
Ok(format!(
"{}payments/settlements/refunds/partials/{}",
"{}api/payments/{}/partialRefunds",
self.base_url(connectors),
connector_payment_id
urlencoding::encode(&connector_payment_id),
))
}

Expand Down Expand Up @@ -670,9 +703,19 @@ impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsRespon
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
event_builder.map(|i| i.set_response_body(&response));
router_env::logger::info!(connector_response=?response);
let optional_correlation_id = res.headers.and_then(|headers| {
headers
.get(consts::WP_CORRELATION_ID)
.and_then(|header_value| header_value.to_str().ok())
.map(|id| id.to_string())
});
Ok(types::RefundExecuteRouterData {
response: Ok(types::RefundsResponseData {
connector_refund_id: ResponseIdStr::try_from(response.links)?.id,
connector_refund_id: ResponseIdStr::foreign_try_from((
response,
optional_correlation_id,
))?
.id,
refund_status: enums::RefundStatus::Pending,
}),
..data.clone()
Expand Down Expand Up @@ -710,9 +753,9 @@ impl ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponse
connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
Ok(format!(
"{}payments/events/{}",
"{}api/payments/{}",
self.base_url(connectors),
req.request.get_connector_refund_id()?
urlencoding::encode(&req.request.get_connector_refund_id()?),
))
}

Expand Down Expand Up @@ -813,7 +856,7 @@ impl api::IncomingWebhook for Worldpay {
.parse_struct("WorldpayWebhookTransactionId")
.change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
api::PaymentIdType::ConnectorTransactionId(body.event_details.transaction_reference),
api::PaymentIdType::PaymentAttemptId(body.event_details.transaction_reference),
))
}

Expand All @@ -829,13 +872,14 @@ impl api::IncomingWebhook for Worldpay {
EventType::Authorized => {
Ok(api::IncomingWebhookEvent::PaymentIntentAuthorizationSuccess)
}
EventType::SentForSettlement => Ok(api::IncomingWebhookEvent::PaymentIntentProcessing),
EventType::Settled => Ok(api::IncomingWebhookEvent::PaymentIntentSuccess),
EventType::SentForSettlement | EventType::SentForAuthorization => {
Ok(api::IncomingWebhookEvent::PaymentIntentProcessing)
}
EventType::Error | EventType::Expired | EventType::SettlementFailed => {
Ok(api::IncomingWebhookEvent::PaymentIntentFailure)
}
EventType::Unknown
| EventType::SentForAuthorization
| EventType::Cancelled
| EventType::Refused
| EventType::Refunded
Expand Down
Loading
Loading