mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-10-29 00:49:42 +08:00 
			
		
		
		
	feat(connector): [Moneris] add template code (#7216)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
		| @ -38,10 +38,10 @@ pub use hyperswitch_connectors::connectors::{ | ||||
|     getnet, getnet::Getnet, globalpay, globalpay::Globalpay, globepay, globepay::Globepay, | ||||
|     gocardless, gocardless::Gocardless, helcim, helcim::Helcim, iatapay, iatapay::Iatapay, inespay, | ||||
|     inespay::Inespay, itaubank, itaubank::Itaubank, jpmorgan, jpmorgan::Jpmorgan, klarna, | ||||
|     klarna::Klarna, mifinity, mifinity::Mifinity, mollie, mollie::Mollie, multisafepay, | ||||
|     multisafepay::Multisafepay, nexinets, nexinets::Nexinets, nexixpay, nexixpay::Nexixpay, | ||||
|     nomupay, nomupay::Nomupay, novalnet, novalnet::Novalnet, nuvei, nuvei::Nuvei, paybox, | ||||
|     paybox::Paybox, payeezy, payeezy::Payeezy, payu, payu::Payu, placetopay, | ||||
|     klarna::Klarna, mifinity, mifinity::Mifinity, mollie, mollie::Mollie, moneris, | ||||
|     moneris::Moneris, multisafepay, multisafepay::Multisafepay, nexinets, nexinets::Nexinets, | ||||
|     nexixpay, nexixpay::Nexixpay, nomupay, nomupay::Nomupay, novalnet, novalnet::Novalnet, nuvei, | ||||
|     nuvei::Nuvei, paybox, paybox::Paybox, payeezy, payeezy::Payeezy, payu, payu::Payu, placetopay, | ||||
|     placetopay::Placetopay, powertranz, powertranz::Powertranz, prophetpay, prophetpay::Prophetpay, | ||||
|     rapyd, rapyd::Rapyd, razorpay, razorpay::Razorpay, redsys, redsys::Redsys, shift4, | ||||
|     shift4::Shift4, square, square::Square, stax, stax::Stax, taxjar, taxjar::Taxjar, thunes, | ||||
|  | ||||
| @ -1014,6 +1014,7 @@ default_imp_for_new_connector_integration_payouts!( | ||||
|     connector::Klarna, | ||||
|     connector::Mifinity, | ||||
|     connector::Mollie, | ||||
|     connector::Moneris, | ||||
|     connector::Multisafepay, | ||||
|     connector::Netcetera, | ||||
|     connector::Nexinets, | ||||
| @ -1479,6 +1480,7 @@ default_imp_for_new_connector_integration_frm!( | ||||
|     connector::Klarna, | ||||
|     connector::Mifinity, | ||||
|     connector::Mollie, | ||||
|     connector::Moneris, | ||||
|     connector::Multisafepay, | ||||
|     connector::Netcetera, | ||||
|     connector::Nexinets, | ||||
| @ -1854,6 +1856,7 @@ default_imp_for_new_connector_integration_connector_authentication!( | ||||
|     connector::Klarna, | ||||
|     connector::Mifinity, | ||||
|     connector::Mollie, | ||||
|     connector::Moneris, | ||||
|     connector::Multisafepay, | ||||
|     connector::Netcetera, | ||||
|     connector::Nexinets, | ||||
|  | ||||
| @ -434,6 +434,7 @@ default_imp_for_connector_request_id!( | ||||
|     connector::Klarna, | ||||
|     connector::Mifinity, | ||||
|     connector::Mollie, | ||||
|     connector::Moneris, | ||||
|     connector::Multisafepay, | ||||
|     connector::Netcetera, | ||||
|     connector::Nexixpay, | ||||
| @ -1393,6 +1394,7 @@ default_imp_for_fraud_check!( | ||||
|     connector::Klarna, | ||||
|     connector::Mifinity, | ||||
|     connector::Mollie, | ||||
|     connector::Moneris, | ||||
|     connector::Multisafepay, | ||||
|     connector::Netcetera, | ||||
|     connector::Nexinets, | ||||
| @ -1928,6 +1930,7 @@ default_imp_for_connector_authentication!( | ||||
|     connector::Klarna, | ||||
|     connector::Mifinity, | ||||
|     connector::Mollie, | ||||
|     connector::Moneris, | ||||
|     connector::Multisafepay, | ||||
|     connector::Nexinets, | ||||
|     connector::Nexixpay, | ||||
|  | ||||
| @ -459,6 +459,7 @@ impl ConnectorData { | ||||
|                     Ok(ConnectorEnum::Old(Box::new(connector::Klarna::new()))) | ||||
|                 } | ||||
|                 enums::Connector::Mollie => { | ||||
|                     // enums::Connector::Moneris => Ok(ConnectorEnum::Old(Box::new(connector::Moneris))), | ||||
|                     Ok(ConnectorEnum::Old(Box::new(connector::Mollie::new()))) | ||||
|                 } | ||||
|                 enums::Connector::Nexixpay => { | ||||
|  | ||||
| @ -263,6 +263,7 @@ impl ForeignTryFrom<api_enums::Connector> for common_enums::RoutableConnectors { | ||||
|             api_enums::Connector::Klarna => Self::Klarna, | ||||
|             api_enums::Connector::Mifinity => Self::Mifinity, | ||||
|             api_enums::Connector::Mollie => Self::Mollie, | ||||
|             // api_enums::Connector::Moneris => Self::Moneris, | ||||
|             api_enums::Connector::Multisafepay => Self::Multisafepay, | ||||
|             api_enums::Connector::Netcetera => { | ||||
|                 Err(common_utils::errors::ValidationError::InvalidValue { | ||||
|  | ||||
| @ -50,6 +50,7 @@ mod itaubank; | ||||
| mod jpmorgan; | ||||
| mod mifinity; | ||||
| mod mollie; | ||||
| mod moneris; | ||||
| mod multisafepay; | ||||
| mod netcetera; | ||||
| mod nexinets; | ||||
|  | ||||
							
								
								
									
										421
									
								
								crates/router/tests/connectors/moneris.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										421
									
								
								crates/router/tests/connectors/moneris.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,421 @@ | ||||
| use hyperswitch_domain_models::payment_method_data::{Card, PaymentMethodData}; | ||||
| use masking::Secret; | ||||
| use router::types::{self, api, storage::enums}; | ||||
| use test_utils::connector_auth; | ||||
|  | ||||
| use crate::utils::{self, ConnectorActions}; | ||||
|  | ||||
| #[derive(Clone, Copy)] | ||||
| struct MonerisTest; | ||||
| impl ConnectorActions for MonerisTest {} | ||||
| impl utils::Connector for MonerisTest { | ||||
|     fn get_data(&self) -> api::ConnectorData { | ||||
|         use router::connector::Moneris; | ||||
|         utils::construct_connector_data_old( | ||||
|             Box::new(Moneris::new()), | ||||
|             types::Connector::Plaid, | ||||
|             api::GetToken::Connector, | ||||
|             None, | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     fn get_auth_token(&self) -> types::ConnectorAuthType { | ||||
|         utils::to_connector_auth_type( | ||||
|             connector_auth::ConnectorAuthentication::new() | ||||
|                 .moneris | ||||
|                 .expect("Missing connector authentication configuration") | ||||
|                 .into(), | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     fn get_name(&self) -> String { | ||||
|         "moneris".to_string() | ||||
|     } | ||||
| } | ||||
|  | ||||
| static CONNECTOR: MonerisTest = MonerisTest {}; | ||||
|  | ||||
| fn get_default_payment_info() -> Option<utils::PaymentInfo> { | ||||
|     None | ||||
| } | ||||
|  | ||||
| fn payment_method_details() -> Option<types::PaymentsAuthorizeData> { | ||||
|     None | ||||
| } | ||||
|  | ||||
| // Cards Positive Tests | ||||
| // Creates a payment using the manual capture flow (Non 3DS). | ||||
| #[actix_web::test] | ||||
| async fn should_only_authorize_payment() { | ||||
|     let response = CONNECTOR | ||||
|         .authorize_payment(payment_method_details(), get_default_payment_info()) | ||||
|         .await | ||||
|         .expect("Authorize payment response"); | ||||
|     assert_eq!(response.status, enums::AttemptStatus::Authorized); | ||||
| } | ||||
|  | ||||
| // Captures a payment using the manual capture flow (Non 3DS). | ||||
| #[actix_web::test] | ||||
| async fn should_capture_authorized_payment() { | ||||
|     let response = CONNECTOR | ||||
|         .authorize_and_capture_payment(payment_method_details(), None, get_default_payment_info()) | ||||
|         .await | ||||
|         .expect("Capture payment response"); | ||||
|     assert_eq!(response.status, enums::AttemptStatus::Charged); | ||||
| } | ||||
|  | ||||
| // 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( | ||||
|             payment_method_details(), | ||||
|             Some(types::PaymentsCaptureData { | ||||
|                 amount_to_capture: 50, | ||||
|                 ..utils::PaymentCaptureType::default().0 | ||||
|             }), | ||||
|             get_default_payment_info(), | ||||
|         ) | ||||
|         .await | ||||
|         .expect("Capture payment response"); | ||||
|     assert_eq!(response.status, enums::AttemptStatus::Charged); | ||||
| } | ||||
|  | ||||
| // 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(payment_method_details(), get_default_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: types::ResponseId::ConnectorTransactionId( | ||||
|                     txn_id.unwrap(), | ||||
|                 ), | ||||
|                 ..Default::default() | ||||
|             }), | ||||
|             get_default_payment_info(), | ||||
|         ) | ||||
|         .await | ||||
|         .expect("PSync response"); | ||||
|     assert_eq!(response.status, enums::AttemptStatus::Authorized,); | ||||
| } | ||||
|  | ||||
| // Voids a payment using the manual capture flow (Non 3DS). | ||||
| #[actix_web::test] | ||||
| async fn should_void_authorized_payment() { | ||||
|     let response = CONNECTOR | ||||
|         .authorize_and_void_payment( | ||||
|             payment_method_details(), | ||||
|             Some(types::PaymentsCancelData { | ||||
|                 connector_transaction_id: String::from(""), | ||||
|                 cancellation_reason: Some("requested_by_customer".to_string()), | ||||
|                 ..Default::default() | ||||
|             }), | ||||
|             get_default_payment_info(), | ||||
|         ) | ||||
|         .await | ||||
|         .expect("Void payment response"); | ||||
|     assert_eq!(response.status, enums::AttemptStatus::Voided); | ||||
| } | ||||
|  | ||||
| // 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( | ||||
|             payment_method_details(), | ||||
|             None, | ||||
|             None, | ||||
|             get_default_payment_info(), | ||||
|         ) | ||||
|         .await | ||||
|         .unwrap(); | ||||
|     assert_eq!( | ||||
|         response.response.unwrap().refund_status, | ||||
|         enums::RefundStatus::Success, | ||||
|     ); | ||||
| } | ||||
|  | ||||
| // Partially refunds a payment using the manual capture flow (Non 3DS). | ||||
| #[actix_web::test] | ||||
| async fn should_partially_refund_manually_captured_payment() { | ||||
|     let response = CONNECTOR | ||||
|         .capture_payment_and_refund( | ||||
|             payment_method_details(), | ||||
|             None, | ||||
|             Some(types::RefundsData { | ||||
|                 refund_amount: 50, | ||||
|                 ..utils::PaymentRefundType::default().0 | ||||
|             }), | ||||
|             get_default_payment_info(), | ||||
|         ) | ||||
|         .await | ||||
|         .unwrap(); | ||||
|     assert_eq!( | ||||
|         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( | ||||
|             payment_method_details(), | ||||
|             None, | ||||
|             None, | ||||
|             get_default_payment_info(), | ||||
|         ) | ||||
|         .await | ||||
|         .unwrap(); | ||||
|     let response = CONNECTOR | ||||
|         .rsync_retry_till_status_matches( | ||||
|             enums::RefundStatus::Success, | ||||
|             refund_response.response.unwrap().connector_refund_id, | ||||
|             None, | ||||
|             get_default_payment_info(), | ||||
|         ) | ||||
|         .await | ||||
|         .unwrap(); | ||||
|     assert_eq!( | ||||
|         response.response.unwrap().refund_status, | ||||
|         enums::RefundStatus::Success, | ||||
|     ); | ||||
| } | ||||
|  | ||||
| // Creates a payment using the automatic capture flow (Non 3DS). | ||||
| #[actix_web::test] | ||||
| async fn should_make_payment() { | ||||
|     let authorize_response = CONNECTOR | ||||
|         .make_payment(payment_method_details(), get_default_payment_info()) | ||||
|         .await | ||||
|         .unwrap(); | ||||
|     assert_eq!(authorize_response.status, enums::AttemptStatus::Charged); | ||||
| } | ||||
|  | ||||
| // Synchronizes a payment using the automatic capture flow (Non 3DS). | ||||
| #[actix_web::test] | ||||
| async fn should_sync_auto_captured_payment() { | ||||
|     let authorize_response = CONNECTOR | ||||
|         .make_payment(payment_method_details(), get_default_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 response = CONNECTOR | ||||
|         .psync_retry_till_status_matches( | ||||
|             enums::AttemptStatus::Charged, | ||||
|             Some(types::PaymentsSyncData { | ||||
|                 connector_transaction_id: types::ResponseId::ConnectorTransactionId( | ||||
|                     txn_id.unwrap(), | ||||
|                 ), | ||||
|                 capture_method: Some(enums::CaptureMethod::Automatic), | ||||
|                 ..Default::default() | ||||
|             }), | ||||
|             get_default_payment_info(), | ||||
|         ) | ||||
|         .await | ||||
|         .unwrap(); | ||||
|     assert_eq!(response.status, enums::AttemptStatus::Charged,); | ||||
| } | ||||
|  | ||||
| // Refunds a payment using the automatic capture flow (Non 3DS). | ||||
| #[actix_web::test] | ||||
| async fn should_refund_auto_captured_payment() { | ||||
|     let response = CONNECTOR | ||||
|         .make_payment_and_refund(payment_method_details(), None, get_default_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 refund_response = CONNECTOR | ||||
|         .make_payment_and_refund( | ||||
|             payment_method_details(), | ||||
|             Some(types::RefundsData { | ||||
|                 refund_amount: 50, | ||||
|                 ..utils::PaymentRefundType::default().0 | ||||
|             }), | ||||
|             get_default_payment_info(), | ||||
|         ) | ||||
|         .await | ||||
|         .unwrap(); | ||||
|     assert_eq!( | ||||
|         refund_response.response.unwrap().refund_status, | ||||
|         enums::RefundStatus::Success, | ||||
|     ); | ||||
| } | ||||
|  | ||||
| // 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( | ||||
|             payment_method_details(), | ||||
|             Some(types::RefundsData { | ||||
|                 refund_amount: 50, | ||||
|                 ..utils::PaymentRefundType::default().0 | ||||
|             }), | ||||
|             get_default_payment_info(), | ||||
|         ) | ||||
|         .await; | ||||
| } | ||||
|  | ||||
| // Synchronizes a refund using the automatic capture flow (Non 3DS). | ||||
| #[actix_web::test] | ||||
| async fn should_sync_refund() { | ||||
|     let refund_response = CONNECTOR | ||||
|         .make_payment_and_refund(payment_method_details(), None, get_default_payment_info()) | ||||
|         .await | ||||
|         .unwrap(); | ||||
|     let response = CONNECTOR | ||||
|         .rsync_retry_till_status_matches( | ||||
|             enums::RefundStatus::Success, | ||||
|             refund_response.response.unwrap().connector_refund_id, | ||||
|             None, | ||||
|             get_default_payment_info(), | ||||
|         ) | ||||
|         .await | ||||
|         .unwrap(); | ||||
|     assert_eq!( | ||||
|         response.response.unwrap().refund_status, | ||||
|         enums::RefundStatus::Success, | ||||
|     ); | ||||
| } | ||||
|  | ||||
| // Cards Negative scenarios | ||||
| // Creates a payment with incorrect CVC. | ||||
| #[actix_web::test] | ||||
| async fn should_fail_payment_for_incorrect_cvc() { | ||||
|     let response = CONNECTOR | ||||
|         .make_payment( | ||||
|             Some(types::PaymentsAuthorizeData { | ||||
|                 payment_method_data: PaymentMethodData::Card(Card { | ||||
|                     card_cvc: Secret::new("12345".to_string()), | ||||
|                     ..utils::CCardType::default().0 | ||||
|                 }), | ||||
|                 ..utils::PaymentAuthorizeType::default().0 | ||||
|             }), | ||||
|             get_default_payment_info(), | ||||
|         ) | ||||
|         .await | ||||
|         .unwrap(); | ||||
|     assert_eq!( | ||||
|         response.response.unwrap_err().message, | ||||
|         "Your card's security code is 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: PaymentMethodData::Card(Card { | ||||
|                     card_exp_month: Secret::new("20".to_string()), | ||||
|                     ..utils::CCardType::default().0 | ||||
|                 }), | ||||
|                 ..utils::PaymentAuthorizeType::default().0 | ||||
|             }), | ||||
|             get_default_payment_info(), | ||||
|         ) | ||||
|         .await | ||||
|         .unwrap(); | ||||
|     assert_eq!( | ||||
|         response.response.unwrap_err().message, | ||||
|         "Your card's expiration month is invalid.".to_string(), | ||||
|     ); | ||||
| } | ||||
|  | ||||
| // 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: PaymentMethodData::Card(Card { | ||||
|                     card_exp_year: Secret::new("2000".to_string()), | ||||
|                     ..utils::CCardType::default().0 | ||||
|                 }), | ||||
|                 ..utils::PaymentAuthorizeType::default().0 | ||||
|             }), | ||||
|             get_default_payment_info(), | ||||
|         ) | ||||
|         .await | ||||
|         .unwrap(); | ||||
|     assert_eq!( | ||||
|         response.response.unwrap_err().message, | ||||
|         "Your card's expiration year is invalid.".to_string(), | ||||
|     ); | ||||
| } | ||||
|  | ||||
| // Voids a payment using automatic capture flow (Non 3DS). | ||||
| #[actix_web::test] | ||||
| async fn should_fail_void_payment_for_auto_capture() { | ||||
|     let authorize_response = CONNECTOR | ||||
|         .make_payment(payment_method_details(), get_default_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, get_default_payment_info()) | ||||
|         .await | ||||
|         .unwrap(); | ||||
|     assert_eq!( | ||||
|         void_response.response.unwrap_err().message, | ||||
|         "You cannot cancel this PaymentIntent because it has a status of succeeded." | ||||
|     ); | ||||
| } | ||||
|  | ||||
| // 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("123456789".to_string(), None, get_default_payment_info()) | ||||
|         .await | ||||
|         .unwrap(); | ||||
|     assert_eq!( | ||||
|         capture_response.response.unwrap_err().message, | ||||
|         String::from("No such payment_intent: '123456789'") | ||||
|     ); | ||||
| } | ||||
|  | ||||
| // 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( | ||||
|             payment_method_details(), | ||||
|             Some(types::RefundsData { | ||||
|                 refund_amount: 150, | ||||
|                 ..utils::PaymentRefundType::default().0 | ||||
|             }), | ||||
|             get_default_payment_info(), | ||||
|         ) | ||||
|         .await | ||||
|         .unwrap(); | ||||
|     assert_eq!( | ||||
|         response.response.unwrap_err().message, | ||||
|         "Refund amount (₹1.50) is greater than charge amount (₹1.00)", | ||||
|     ); | ||||
| } | ||||
|  | ||||
| // Connector dependent test cases goes here | ||||
|  | ||||
| // [#478]: add unit tests for non 3DS, wallets & webhooks in connector tests | ||||
| @ -310,4 +310,7 @@ api_key="API Key" | ||||
| api_key="API Key" | ||||
|  | ||||
| [chargebee] | ||||
| api_key= "API Key" | ||||
|  | ||||
| [moneris] | ||||
| api_key= "API Key" | ||||
		Reference in New Issue
	
	Block a user
	 Swangi Kumari
					Swangi Kumari