Bug: fix(connector) : [Globalpay] unit tests for globalpay



refactor and add unit tests for globalpay
diff --git a/crates/router/src/connector/globalpay.rs b/crates/router/src/connector/globalpay.rs
index 5bd472a2d04..ac0797cc89a 100644
--- a/crates/router/src/connector/globalpay.rs
+++ b/crates/router/src/connector/globalpay.rs
@@ -15,6 +15,7 @@ use self::{
         GlobalpayRefreshTokenResponse,
     },
 };
+use super::utils::RefundsRequestData;
 use crate::{
     configs::settings,
     connector::utils as conn_utils,
@@ -33,7 +34,7 @@ use crate::{
         api::{self, ConnectorCommon, ConnectorCommonExt, PaymentsCompleteAuthorize},
         ErrorResponse,
     },
-    utils::{self, crypto, BytesExt, OptionExt},
+    utils::{self, crypto, BytesExt},
 };
 
 #[derive(Debug, Clone)]
@@ -744,13 +745,7 @@ impl ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponse
         req: &types::RefundSyncRouterData,
         connectors: &settings::Connectors,
     ) -> CustomResult<String, errors::ConnectorError> {
-        let refund_id = req
-            .response
-            .clone()
-            .ok()
-            .get_required_value("response")
-            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?
-            .connector_refund_id;
+        let refund_id = req.request.get_connector_refund_id()?;
         Ok(format!(
             "{}transactions/{}",
             self.base_url(connectors),
diff --git a/crates/router/src/connector/globalpay/transformers.rs b/crates/router/src/connector/globalpay/transformers.rs
index a0454296572..8a0916ae934 100644
--- a/crates/router/src/connector/globalpay/transformers.rs
+++ b/crates/router/src/connector/globalpay/transformers.rs
@@ -12,7 +12,7 @@ use super::{
     response::{GlobalpayPaymentStatus, GlobalpayPaymentsResponse, GlobalpayRefreshTokenResponse},
 };
 use crate::{
-    connector::utils::{self, PaymentsAuthorizeRequestData, RouterData, WalletData},
+    connector::utils::{self, CardData, PaymentsAuthorizeRequestData, RouterData, WalletData},
     consts,
     core::errors,
     services::{self, RedirectForm},
@@ -340,7 +340,7 @@ fn get_payment_method_data(
         api::PaymentMethodData::Card(ccard) => Ok(PaymentMethodData::Card(requests::Card {
             number: ccard.card_number.clone(),
             expiry_month: ccard.card_exp_month.clone(),
-            expiry_year: ccard.card_exp_year.clone(),
+            expiry_year: ccard.get_card_expiry_year_2_digit(),
             cvv: ccard.card_cvc.clone(),
             account_type: None,
             authcode: None,
diff --git a/crates/router/tests/connectors/connector_auth.rs b/crates/router/tests/connectors/connector_auth.rs
index ef31b20c3b6..52cd3562cd0 100644
--- a/crates/router/tests/connectors/connector_auth.rs
+++ b/crates/router/tests/connectors/connector_auth.rs
@@ -21,7 +21,7 @@ pub struct ConnectorAuthentication {
     pub dummyconnector: Option<HeaderKey>,
     pub fiserv: Option<SignatureKey>,
     pub forte: Option<MultiAuthKey>,
-    pub globalpay: Option<HeaderKey>,
+    pub globalpay: Option<BodyKey>,
     pub iatapay: Option<SignatureKey>,
     pub mollie: Option<HeaderKey>,
     pub multisafepay: Option<HeaderKey>,
diff --git a/crates/router/tests/connectors/globalpay.rs b/crates/router/tests/connectors/globalpay.rs
index 88df64e514e..598b66eda0a 100644
--- a/crates/router/tests/connectors/globalpay.rs
+++ b/crates/router/tests/connectors/globalpay.rs
@@ -1,16 +1,18 @@
 use std::str::FromStr;
 
-use router::types::{self, api, storage::enums};
+use masking::Secret;
+use router::types::{self, api, storage::enums, AccessToken, ConnectorAuthType};
 use serde_json::json;
 
 use crate::{
     connector_auth,
-    utils::{self, ConnectorActions, PaymentInfo},
+    utils::{self, Connector, ConnectorActions, PaymentInfo},
 };
 
 struct Globalpay;
 impl ConnectorActions for Globalpay {}
-impl utils::Connector for Globalpay {
+static CONNECTOR: Globalpay = Globalpay {};
+impl Connector for Globalpay {
     fn get_data(&self) -> types::api::ConnectorData {
         use router::connector::Globalpay;
         types::api::ConnectorData {
@@ -20,7 +22,7 @@ impl utils::Connector for Globalpay {
         }
     }
 
-    fn get_auth_token(&self) -> types::ConnectorAuthType {
+    fn get_auth_token(&self) -> ConnectorAuthType {
         types::ConnectorAuthType::from(
             connector_auth::ConnectorAuthentication::new()
                 .globalpay
@@ -37,69 +39,80 @@ impl utils::Connector for Globalpay {
     }
 }
 
-fn get_default_payment_info() -> Option<PaymentInfo> {
-    Some(PaymentInfo {
-        address: Some(types::PaymentAddress {
-            billing: Some(api::Address {
-                address: Some(api::AddressDetails {
-                    country: Some(api_models::enums::CountryAlpha2::US),
-                    ..Default::default()
+fn get_access_token() -> Option<AccessToken> {
+    match utils::Connector::get_auth_token(&CONNECTOR) {
+        ConnectorAuthType::BodyKey { api_key, key1: _ } => Some(AccessToken {
+            token: api_key,
+            expires: 18600,
+        }),
+        _ => None,
+    }
+}
+
+impl Globalpay {
+    fn get_request_interval(&self) -> u64 {
+        5
+    }
+    fn get_payment_info() -> Option<PaymentInfo> {
+        Some(PaymentInfo {
+            address: Some(types::PaymentAddress {
+                billing: Some(api::Address {
+                    address: Some(api::AddressDetails {
+                        country: Some(api_models::enums::CountryAlpha2::US),
+                        ..Default::default()
+                    }),
+                    phone: None,
                 }),
-                phone: None,
+                ..Default::default()
             }),
+            access_token: get_access_token(),
+            connector_meta_data: CONNECTOR.get_connector_meta(),
             ..Default::default()
-        }),
-        access_token: Some(types::AccessToken {
-            token: "<access_token>".to_string(),
-            expires: 18600,
-        }),
-        ..Default::default()
-    })
+        })
+    }
 }
 
 #[actix_web::test]
 async fn should_only_authorize_payment() {
-    let response = Globalpay {}
-        .authorize_payment(None, get_default_payment_info())
+    let response = CONNECTOR
+        .authorize_payment(None, Globalpay::get_payment_info())
         .await
         .unwrap();
     assert_eq!(response.status, enums::AttemptStatus::Authorized);
 }
 
 #[actix_web::test]
-async fn should_authorize_and_capture_payment() {
-    let response = Globalpay {}
-        .make_payment(None, get_default_payment_info())
+async fn should_make_payment() {
+    let response = CONNECTOR
+        .make_payment(None, Globalpay::get_payment_info())
         .await
         .unwrap();
     assert_eq!(response.status, enums::AttemptStatus::Charged);
 }
 
 #[actix_web::test]
-async fn should_capture_already_authorized_payment() {
-    let connector = Globalpay {};
-    let response = connector
+async fn should_capture_authorized_payment() {
+    let response = CONNECTOR
         .authorize_and_capture_payment(
             None,
             Some(types::PaymentsCaptureData {
                 amount_to_capture: 50,
                 ..utils::PaymentCaptureType::default().0
             }),
-            get_default_payment_info(),
+            Globalpay::get_payment_info(),
         )
         .await;
     assert_eq!(response.unwrap().status, enums::AttemptStatus::Charged);
 }
 
 #[actix_web::test]
-async fn should_sync_payment() {
-    let connector = Globalpay {};
-    let authorize_response = connector
-        .authorize_payment(None, get_default_payment_info())
+async fn should_sync_auto_captured_payment() {
+    let authorize_response = CONNECTOR
+        .authorize_payment(None, Globalpay::get_payment_info())
         .await
         .unwrap();
     let txn_id = utils::get_connector_transaction_id(authorize_response.response);
-    let response = connector
+    let response = CONNECTOR
         .psync_retry_till_status_matches(
             enums::AttemptStatus::Authorized,
             Some(types::PaymentsSyncData {
@@ -108,7 +121,7 @@ async fn should_sync_payment() {
                 ),
                 ..Default::default()
             }),
-            get_default_payment_info(),
+            Globalpay::get_payment_info(),
         )
         .await
         .unwrap();
@@ -117,7 +130,7 @@ async fn should_sync_payment() {
 
 #[actix_web::test]
 async fn should_fail_payment_for_incorrect_cvc() {
-    let response = Globalpay {}
+    let response = CONNECTOR
         .make_payment(
             Some(types::PaymentsAuthorizeData {
                 payment_method_data: types::api::PaymentMethodData::Card(api::Card {
@@ -126,7 +139,7 @@ async fn should_fail_payment_for_incorrect_cvc() {
                 }),
                 ..utils::PaymentAuthorizeType::default().0
             }),
-            get_default_payment_info(),
+            Globalpay::get_payment_info(),
         )
         .await
         .unwrap();
@@ -135,10 +148,9 @@ async fn should_fail_payment_for_incorrect_cvc() {
 }
 
 #[actix_web::test]
-async fn should_refund_succeeded_payment() {
-    let connector = Globalpay {};
-    let response = connector
-        .make_payment_and_refund(None, None, get_default_payment_info())
+async fn should_refund_auto_captured_payment() {
+    let response = CONNECTOR
+        .make_payment_and_refund(None, None, Globalpay::get_payment_info())
         .await
         .unwrap();
     assert_eq!(
@@ -148,29 +160,270 @@ async fn should_refund_succeeded_payment() {
 }
 
 #[actix_web::test]
-async fn should_void_already_authorized_payment() {
-    let connector = Globalpay {};
-    let response = connector
-        .authorize_and_void_payment(None, None, get_default_payment_info())
+async fn should_void_authorized_payment() {
+    let response = CONNECTOR
+        .authorize_and_void_payment(None, None, Globalpay::get_payment_info())
         .await;
     assert_eq!(response.unwrap().status, enums::AttemptStatus::Voided);
 }
 
 #[actix_web::test]
 async fn should_sync_refund() {
-    let connector = Globalpay {};
-    let refund_response = connector
-        .make_payment_and_refund(None, None, get_default_payment_info())
+    let refund_response = CONNECTOR
+        .make_payment_and_refund(None, None, Globalpay::get_payment_info())
         .await
         .unwrap();
-    let response = connector
+    tokio::time::sleep(std::time::Duration::from_secs(
+        CONNECTOR.get_request_interval(),
+    ))
+    .await;
+    let response = CONNECTOR
         .rsync_retry_till_status_matches(
             enums::RefundStatus::Success,
             refund_response.response.unwrap().connector_refund_id,
             None,
-            get_default_payment_info(),
+            Globalpay::get_payment_info(),
+        )
+        .await
+        .unwrap();
+    assert_eq!(
+        response.response.unwrap().refund_status,
+        enums::RefundStatus::Success,
+    );
+}
+
+// Partially captures a payment using the manual capture flow (Non 3DS).
+#[actix_web::test]
+async fn should_partially_capture_authorized_payment() {
+    let response = CONNECTOR
+        .authorize_and_capture_payment(
+            None,
+            Some(types::PaymentsCaptureData {
+                amount_to_capture: 50,
+                ..utils::PaymentCaptureType::default().0
+            }),
+            Globalpay::get_payment_info(),
+        )
+        .await
+        .expect("Capture payment response");
+    assert_eq!(response.status, enums::AttemptStatus::Charged);
+}
+
+#[actix_web::test]
+async fn should_partially_refund_manually_captured_payment() {
+    let response = CONNECTOR
+        .capture_payment_and_refund(
+            None,
+            None,
+            Some(types::RefundsData {
+                refund_amount: 50,
+                ..utils::PaymentRefundType::default().0
+            }),
+            Globalpay::get_payment_info(),
+        )
+        .await
+        .unwrap();
+    assert_eq!(
+        response.response.unwrap().refund_status,
+        enums::RefundStatus::Success,
+    );
+}
+
+// Partially refunds a payment using the automatic capture flow (Non 3DS).
+#[actix_web::test]
+async fn should_partially_refund_succeeded_payment() {
+    let authorize_response = CONNECTOR
+        .make_payment(None, Globalpay::get_payment_info())
+        .await
+        .unwrap();
+
+    let txn_id = utils::get_connector_transaction_id(authorize_response.response.clone()).unwrap();
+    let refund_response = CONNECTOR
+        .refund_payment(
+            txn_id,
+            Some(types::RefundsData {
+                refund_amount: 50,
+                ..utils::PaymentRefundType::default().0
+            }),
+            Globalpay::get_payment_info(),
+        )
+        .await
+        .unwrap();
+    assert_eq!(
+        refund_response.response.unwrap().refund_status,
+        enums::RefundStatus::Success,
+    );
+}
+
+// Synchronizes a refund using the manual capture flow (Non 3DS).
+#[actix_web::test]
+async fn should_sync_manually_captured_refund() {
+    let refund_response = CONNECTOR
+        .capture_payment_and_refund(None, None, None, Globalpay::get_payment_info())
+        .await
+        .unwrap();
+    tokio::time::sleep(std::time::Duration::from_secs(
+        CONNECTOR.get_request_interval(),
+    ))
+    .await;
+    let response = CONNECTOR
+        .rsync_retry_till_status_matches(
+            enums::RefundStatus::Success,
+            refund_response.response.unwrap().connector_refund_id,
+            None,
+            Globalpay::get_payment_info(),
+        )
+        .await
+        .unwrap();
+    assert_eq!(
+        response.response.unwrap().refund_status,
+        enums::RefundStatus::Success,
+    );
+}
+
+// Refunds a payment with refund amount higher than payment amount.
+#[actix_web::test]
+async fn should_fail_for_refund_amount_higher_than_payment_amount() {
+    let response = CONNECTOR
+        .make_payment_and_refund(
+            None,
+            Some(types::RefundsData {
+                refund_amount: 150,
+                ..utils::PaymentRefundType::default().0
+            }),
+            Globalpay::get_payment_info(),
+        )
+        .await
+        .unwrap();
+    assert_eq!(
+        response.response.unwrap_err().message,
+        "You may only refund up to 115% of the original amount ",
+    );
+}
+
+// Captures a payment using invalid connector payment id.
+#[actix_web::test]
+async fn should_fail_capture_for_invalid_payment() {
+    let capture_response = CONNECTOR
+        .capture_payment("123ddsa12".to_string(), None, Globalpay::get_payment_info())
+        .await
+        .unwrap();
+    assert_eq!(
+        capture_response.response.unwrap_err().message,
+        String::from("Transaction 123ddsa12 not found at this location.")
+    );
+}
+
+// Voids a payment using automatic capture flow (Non 3DS).
+#[actix_web::test]
+#[ignore]
+async fn should_fail_void_payment_for_auto_capture() {
+    let authorize_response = CONNECTOR
+        .make_payment(None, Globalpay::get_payment_info())
+        .await
+        .unwrap();
+    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
+    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
+    assert_ne!(txn_id, None, "Empty connector transaction id");
+    let void_response = CONNECTOR
+        .void_payment(txn_id.unwrap(), None, Globalpay::get_payment_info())
+        .await
+        .unwrap();
+    assert_eq!(
+        void_response.response.unwrap_err().message,
+        "You cannot cancel this PaymentIntent because it has a status of succeeded."
+    );
+}
+
+// Creates a payment with incorrect expiry year.
+#[actix_web::test]
+async fn should_fail_payment_for_incorrect_expiry_year() {
+    let response = CONNECTOR
+        .make_payment(
+            Some(types::PaymentsAuthorizeData {
+                payment_method_data: types::api::PaymentMethodData::Card(api::Card {
+                    card_exp_year: Secret::new("2000".to_string()),
+                    ..utils::CCardType::default().0
+                }),
+                ..utils::PaymentAuthorizeType::default().0
+            }),
+            Globalpay::get_payment_info(),
+        )
+        .await
+        .unwrap();
+    assert_eq!(
+        response.response.unwrap_err().message,
+        "Expiry date invalid".to_string(),
+    );
+}
+
+// Creates a payment with incorrect expiry month.
+#[actix_web::test]
+async fn should_fail_payment_for_invalid_exp_month() {
+    let response = CONNECTOR
+        .make_payment(
+            Some(types::PaymentsAuthorizeData {
+                payment_method_data: types::api::PaymentMethodData::Card(api::Card {
+                    card_exp_month: Secret::new("20".to_string()),
+                    ..utils::CCardType::default().0
+                }),
+                ..utils::PaymentAuthorizeType::default().0
+            }),
+            Globalpay::get_payment_info(),
+        )
+        .await
+        .unwrap();
+    assert_eq!(
+        response.response.unwrap_err().message,
+        "Invalid Expiry Date".to_string(),
+    );
+}
+
+// Creates multiple refunds against a payment using the automatic capture flow (Non 3DS).
+#[actix_web::test]
+async fn should_refund_succeeded_payment_multiple_times() {
+    CONNECTOR
+        .make_payment_and_multiple_refund(
+            None,
+            Some(types::RefundsData {
+                refund_amount: 50,
+                ..utils::PaymentRefundType::default().0
+            }),
+            Globalpay::get_payment_info(),
+        )
+        .await;
+}
+
+// Synchronizes a payment using the manual capture flow (Non 3DS).
+#[actix_web::test]
+async fn should_sync_authorized_payment() {
+    let authorize_response = CONNECTOR
+        .authorize_payment(None, Globalpay::get_payment_info())
+        .await
+        .expect("Authorize payment response");
+    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
+    let response = CONNECTOR
+        .psync_retry_till_status_matches(
+            enums::AttemptStatus::Authorized,
+            Some(types::PaymentsSyncData {
+                connector_transaction_id: router::types::ResponseId::ConnectorTransactionId(
+                    txn_id.unwrap(),
+                ),
+                ..Default::default()
+            }),
+            Globalpay::get_payment_info(),
         )
         .await
+        .expect("PSync response");
+    assert_eq!(response.status, enums::AttemptStatus::Authorized,);
+}
+
+// Refunds a payment using the manual capture flow (Non 3DS).
+#[actix_web::test]
+async fn should_refund_manually_captured_payment() {
+    let response = CONNECTOR
+        .capture_payment_and_refund(None, None, None, Globalpay::get_payment_info())
+        .await
         .unwrap();
     assert_eq!(
         response.response.unwrap().refund_status,
diff --git a/crates/router/tests/connectors/sample_auth.toml b/crates/router/tests/connectors/sample_auth.toml
index 02d78e1b80f..06120aa8eec 100644
--- a/crates/router/tests/connectors/sample_auth.toml
+++ b/crates/router/tests/connectors/sample_auth.toml
@@ -35,7 +35,8 @@ api_key = "Bearer MyApiKey"
 key1 = "MerchantPosId"
 
 [globalpay]
-api_key = "Bearer MyApiKey"
+api_key = "api_key"
+key1 = "key1"
 
 [rapyd]
 api_key = "access_key"

## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [x] Bugfix
- [ ] New feature
- [ ] Enhancement
- [ ] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
<!-- Describe your changes in detail -->
This PR contains following changes 
1)unit tests for globalpay
2)expiry year fix
### Additional Changes

- [ ] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables

<!-- 
Provide links to the files with corresponding changes.

Following are the paths where you can find config files:
1. `config`
2. `crates/router/src/configs`
3. `loadtest/config`
-->


## Motivation and Context
unit tests for globalpay
<!--
Why is this change required? What problem does it solve?
If it fixes an open issue, please link to the issue here.

If you don't have an issue, we'd recommend starting with one first so the PR
can focus on the implementation (unless its an obvious bug or documentation fix
that will have little conversation).
-->


## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
unit tests 
Note : `should_fail_void_payment_for_auto_capture` is failing from connector end .


<img width="1044" alt="Screenshot 2023-05-29 at 11 56 41 AM" src="https://github.com/juspay/hyperswitch/assets/121822803/db7a86a9-522f-4e73-b1ea-f7f775ab6b05">


## Checklist
<!-- Put an `x` in the boxes that apply -->

- [x] I formatted the code `cargo +nightly fmt --all`
- [x] I addressed lints thrown by `cargo clippy`
- [x] I reviewed submitted code
- [x] I added unit tests for my changes where possible
- [ ] I added a [CHANGELOG](/CHANGELOG.md) entry if applicable
