diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index f265af4d90..e0e11520ad 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -947,7 +947,7 @@ pub struct BankDebitBilling { #[serde(rename_all = "snake_case")] pub enum WalletData { /// The wallet data for Ali Pay QrCode - AliPay(Box), + AliPayQr(Box), /// The wallet data for Ali Pay redirect AliPayRedirect(AliPayRedirection), /// The wallet data for Ali Pay HK redirect @@ -977,6 +977,8 @@ pub enum WalletData { WeChatPayRedirect(Box), /// The wallet data for WeChat Pay WeChatPay(Box), + /// The wallet data for WeChat Pay Display QrCode + WeChatPayQr(Box), } #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] @@ -1019,11 +1021,14 @@ pub struct WeChatPayRedirection {} #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] pub struct WeChatPay {} +#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] +pub struct WeChatPayQr {} + #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] pub struct PaypalRedirection {} #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] -pub struct AliPay {} +pub struct AliPayQr {} #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] pub struct AliPayRedirection {} diff --git a/crates/router/src/connector/globepay.rs b/crates/router/src/connector/globepay.rs index 2f6c59eac0..bd3bfdb920 100644 --- a/crates/router/src/connector/globepay.rs +++ b/crates/router/src/connector/globepay.rs @@ -327,22 +327,152 @@ impl ConnectorIntegration for Globepay { + fn get_headers( + &self, + req: &types::RefundsRouterData, + connectors: &settings::Connectors, + ) -> CustomResult)>, errors::ConnectorError> { + self.build_headers(req, connectors) + } + + fn get_content_type(&self) -> &'static str { + self.common_get_content_type() + } + + fn get_url( + &self, + req: &types::RefundsRouterData, + connectors: &settings::Connectors, + ) -> CustomResult { + let query_params = get_globlepay_query_params(&req.connector_auth_type)?; + Ok(format!( + "{}api/v1.0/gateway/partners/{}/orders/{}/refunds/{}{query_params}", + self.base_url(connectors), + get_partner_code(&req.connector_auth_type)?, + req.payment_id, + req.request.refund_id + )) + } + + fn get_request_body( + &self, + req: &types::RefundsRouterData, + ) -> CustomResult, errors::ConnectorError> { + let connector_req = globepay::GlobepayRefundRequest::try_from(req)?; + let globepay_req = types::RequestBody::log_and_get_request_body( + &connector_req, + utils::Encode::::encode_to_string_of_json, + ) + .change_context(errors::ConnectorError::RequestEncodingFailed)?; + Ok(Some(globepay_req)) + } + fn build_request( &self, - _req: &types::RefundsRouterData, - _connectors: &settings::Connectors, + req: &types::RefundsRouterData, + connectors: &settings::Connectors, ) -> CustomResult, errors::ConnectorError> { - Err(errors::ConnectorError::NotImplemented("Refund".to_string()).into()) + Ok(Some( + services::RequestBuilder::new() + .method(services::Method::Put) + .url(&types::RefundExecuteType::get_url(self, req, connectors)?) + .attach_default_headers() + .headers(types::RefundExecuteType::get_headers( + self, req, connectors, + )?) + .body(types::RefundExecuteType::get_request_body(self, req)?) + .build(), + )) + } + + fn handle_response( + &self, + data: &types::RefundsRouterData, + res: Response, + ) -> CustomResult, errors::ConnectorError> { + let response: globepay::GlobepayRefundResponse = res + .response + .parse_struct("Globalpay RefundResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + types::RouterData::try_from(types::ResponseRouterData { + response, + data: data.clone(), + http_code: res.status_code, + }) + } + + fn get_error_response( + &self, + res: Response, + ) -> CustomResult { + self.build_error_response(res) } } impl ConnectorIntegration for Globepay { + fn get_headers( + &self, + req: &types::RefundSyncRouterData, + connectors: &settings::Connectors, + ) -> CustomResult)>, errors::ConnectorError> { + self.build_headers(req, connectors) + } + + fn get_content_type(&self) -> &'static str { + self.common_get_content_type() + } + + fn get_url( + &self, + req: &types::RefundSyncRouterData, + connectors: &settings::Connectors, + ) -> CustomResult { + let query_params = get_globlepay_query_params(&req.connector_auth_type)?; + Ok(format!( + "{}api/v1.0/gateway/partners/{}/orders/{}/refunds/{}{query_params}", + self.base_url(connectors), + get_partner_code(&req.connector_auth_type)?, + req.payment_id, + req.request.refund_id + )) + } + fn build_request( &self, - _req: &types::RefundSyncRouterData, - _connectors: &settings::Connectors, + req: &types::RefundSyncRouterData, + connectors: &settings::Connectors, ) -> CustomResult, errors::ConnectorError> { - Err(errors::ConnectorError::NotImplemented("Refund Sync".to_string()).into()) + Ok(Some( + services::RequestBuilder::new() + .method(services::Method::Get) + .url(&types::RefundSyncType::get_url(self, req, connectors)?) + .attach_default_headers() + .headers(types::RefundSyncType::get_headers(self, req, connectors)?) + .build(), + )) + } + + fn handle_response( + &self, + data: &types::RefundSyncRouterData, + res: Response, + ) -> CustomResult { + let response: globepay::GlobepayRefundResponse = res + .response + .parse_struct("Globalpay RefundResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + types::RouterData::try_from(types::ResponseRouterData { + response, + data: data.clone(), + http_code: res.status_code, + }) + } + + fn get_error_response( + &self, + res: Response, + ) -> CustomResult { + self.build_error_response(res) } } diff --git a/crates/router/src/connector/globepay/transformers.rs b/crates/router/src/connector/globepay/transformers.rs index 413a7a2e94..c084607c4d 100644 --- a/crates/router/src/connector/globepay/transformers.rs +++ b/crates/router/src/connector/globepay/transformers.rs @@ -8,6 +8,7 @@ use crate::{ core::errors, types::{self, api, storage::enums}, }; +type Error = error_stack::Report; #[derive(Debug, Serialize)] pub struct GlobepayPaymentsRequest { @@ -24,12 +25,12 @@ pub enum GlobepayChannel { } impl TryFrom<&types::PaymentsAuthorizeRouterData> for GlobepayPaymentsRequest { - type Error = error_stack::Report; + type Error = Error; fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result { let channel: GlobepayChannel = match &item.request.payment_method_data { api::PaymentMethodData::Wallet(ref wallet_data) => match wallet_data { - api::WalletData::AliPay(_) => GlobepayChannel::Alipay, - api::WalletData::WeChatPay(_) => GlobepayChannel::Wechat, + api::WalletData::AliPayQr(_) => GlobepayChannel::Alipay, + api::WalletData::WeChatPayQr(_) => GlobepayChannel::Wechat, _ => Err(errors::ConnectorError::NotImplemented( "Payment method".to_string(), ))?, @@ -54,7 +55,7 @@ pub struct GlobepayAuthType { } impl TryFrom<&types::ConnectorAuthType> for GlobepayAuthType { - type Error = error_stack::Report; + type Error = Error; fn try_from(auth_type: &types::ConnectorAuthType) -> Result { match auth_type { types::ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self { @@ -110,13 +111,14 @@ pub enum GlobepayReturnCode { NotPermitted, InvalidChannel, DuplicateOrderId, + OrderNotPaid, } impl TryFrom> for types::RouterData { - type Error = error_stack::Report; + type Error = Error; fn try_from( item: types::ResponseRouterData< F, @@ -206,7 +208,7 @@ impl TryFrom> for types::RouterData { - type Error = error_stack::Report; + type Error = Error; fn try_from( item: types::ResponseRouterData, ) -> Result { @@ -260,74 +262,81 @@ fn get_error_response( #[derive(Debug, Serialize)] pub struct GlobepayRefundRequest { - pub amount: i64, + pub fee: i64, } impl TryFrom<&types::RefundsRouterData> for GlobepayRefundRequest { - type Error = error_stack::Report; + type Error = Error; fn try_from(item: &types::RefundsRouterData) -> Result { Ok(Self { - amount: item.request.refund_amount, + fee: item.request.refund_amount, }) } } -#[allow(dead_code)] -#[derive(Debug, Serialize, Default, Deserialize, Clone)] -pub enum RefundStatus { - Succeeded, +#[derive(Debug, Deserialize)] +pub enum GlobepayRefundStatus { + Waiting, + CreateFailed, Failed, - #[default] - Processing, + Success, + Finished, + Change, } -impl From for enums::RefundStatus { - fn from(item: RefundStatus) -> Self { +impl From for enums::RefundStatus { + fn from(item: GlobepayRefundStatus) -> Self { match item { - RefundStatus::Succeeded => Self::Success, - RefundStatus::Failed => Self::Failure, - RefundStatus::Processing => Self::Pending, + GlobepayRefundStatus::Finished => Self::Success, //FINISHED: Refund success(funds has already been returned to user's account) + GlobepayRefundStatus::Failed + | GlobepayRefundStatus::CreateFailed + | GlobepayRefundStatus::Change => Self::Failure, //CHANGE: Refund can not return to user's account. Manual operation is required + GlobepayRefundStatus::Waiting | GlobepayRefundStatus::Success => Self::Pending, // SUCCESS: Submission succeeded, but refund is not yet complete. Waiting = Submission succeeded, but refund is not yet complete. } } } -#[derive(Default, Debug, Clone, Serialize, Deserialize)] -pub struct RefundResponse { - id: String, - status: RefundStatus, +#[derive(Debug, Deserialize)] +pub struct GlobepayRefundResponse { + pub result_code: Option, + pub refund_id: Option, + pub return_code: GlobepayReturnCode, + pub return_msg: Option, } -impl TryFrom> - for types::RefundsRouterData +impl TryFrom> + for types::RefundsRouterData { - type Error = error_stack::Report; + type Error = Error; fn try_from( - item: types::RefundsResponseRouterData, + item: types::RefundsResponseRouterData, ) -> Result { - Ok(Self { - response: Ok(types::RefundsResponseData { - connector_refund_id: item.response.id.to_string(), - refund_status: enums::RefundStatus::from(item.response.status), - }), - ..item.data - }) - } -} - -impl TryFrom> - for types::RefundsRouterData -{ - type Error = error_stack::Report; - fn try_from( - item: types::RefundsResponseRouterData, - ) -> Result { - Ok(Self { - response: Ok(types::RefundsResponseData { - connector_refund_id: item.response.id.to_string(), - refund_status: enums::RefundStatus::from(item.response.status), - }), - ..item.data - }) + if item.response.return_code == GlobepayReturnCode::Success { + let globepay_refund_id = item + .response + .refund_id + .ok_or(errors::ConnectorError::ResponseHandlingFailed)?; + let globepay_refund_status = item + .response + .result_code + .ok_or(errors::ConnectorError::ResponseHandlingFailed)?; + Ok(Self { + response: Ok(types::RefundsResponseData { + connector_refund_id: globepay_refund_id, + refund_status: enums::RefundStatus::from(globepay_refund_status), + }), + ..item.data + }) + } else { + Ok(Self { + response: Err(get_error_response( + item.response.return_code, + item.response.return_msg, + item.http_code, + )), + ..item.data + }) + } } } diff --git a/crates/router/src/openapi.rs b/crates/router/src/openapi.rs index 204f6f4429..5e1e565b50 100644 --- a/crates/router/src/openapi.rs +++ b/crates/router/src/openapi.rs @@ -167,12 +167,13 @@ Never share your secret api keys. Keep them guarded and secure. api_models::disputes::DisputeResponsePaymentsRetrieve, api_models::payments::AddressDetails, api_models::payments::BankDebitData, - api_models::payments::AliPay, + api_models::payments::AliPayQr, api_models::payments::AliPayRedirection, api_models::payments::AliPayHkRedirection, api_models::payments::MbWayRedirection, api_models::payments::MobilePayRedirection, api_models::payments::WeChatPayRedirection, + api_models::payments::WeChatPayQr, api_models::payments::BankDebitBilling, api_models::payments::CryptoData, api_models::payments::RewardData, diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index c6d34ef6dd..f1c8266d12 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -1739,10 +1739,10 @@ } } }, - "AliPay": { + "AliPayHkRedirection": { "type": "object" }, - "AliPayHkRedirection": { + "AliPayQr": { "type": "object" }, "AliPayRedirection": { @@ -8761,11 +8761,11 @@ { "type": "object", "required": [ - "ali_pay" + "ali_pay_qr" ], "properties": { - "ali_pay": { - "$ref": "#/components/schemas/AliPay" + "ali_pay_qr": { + "$ref": "#/components/schemas/AliPayQr" } } }, @@ -8933,12 +8933,26 @@ "$ref": "#/components/schemas/WeChatPay" } } + }, + { + "type": "object", + "required": [ + "we_chat_pay_qr" + ], + "properties": { + "we_chat_pay_qr": { + "$ref": "#/components/schemas/WeChatPayQr" + } + } } ] }, "WeChatPay": { "type": "object" }, + "WeChatPayQr": { + "type": "object" + }, "WeChatPayRedirection": { "type": "object" },