mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-11-01 02:57:02 +08:00 
			
		
		
		
	fix(connector): convert cents to dollar before sending to connector (#699)
Co-authored-by: Jagan Elavarasan <jaganelavarasan@gmail.com> Co-authored-by: Arjun Karthik <m.arjunkarthik@gmail.com> Co-authored-by: Arun Raj M <jarnura47@gmail.com>
This commit is contained in:
		| @ -4,6 +4,7 @@ use url::Url; | |||||||
| use uuid::Uuid; | use uuid::Uuid; | ||||||
|  |  | ||||||
| use crate::{ | use crate::{ | ||||||
|  |     connector::utils, | ||||||
|     core::errors, |     core::errors, | ||||||
|     pii::{self, Secret}, |     pii::{self, Secret}, | ||||||
|     services, |     services, | ||||||
| @ -14,7 +15,7 @@ use crate::{ | |||||||
| pub struct AirwallexIntentRequest { | pub struct AirwallexIntentRequest { | ||||||
|     // Unique ID to be sent for each transaction/operation request to the connector |     // Unique ID to be sent for each transaction/operation request to the connector | ||||||
|     request_id: String, |     request_id: String, | ||||||
|     amount: i64, |     amount: String, | ||||||
|     currency: enums::Currency, |     currency: enums::Currency, | ||||||
|     //ID created in merchant's order system that corresponds to this PaymentIntent. |     //ID created in merchant's order system that corresponds to this PaymentIntent. | ||||||
|     merchant_order_id: String, |     merchant_order_id: String, | ||||||
| @ -26,7 +27,7 @@ impl TryFrom<&types::PaymentsAuthorizeSessionTokenRouterData> for AirwallexInten | |||||||
|     ) -> Result<Self, Self::Error> { |     ) -> Result<Self, Self::Error> { | ||||||
|         Ok(Self { |         Ok(Self { | ||||||
|             request_id: Uuid::new_v4().to_string(), |             request_id: Uuid::new_v4().to_string(), | ||||||
|             amount: item.request.amount, |             amount: utils::to_currency_base_unit(item.request.amount, item.request.currency)?, | ||||||
|             currency: item.request.currency, |             currency: item.request.currency, | ||||||
|             merchant_order_id: item.payment_id.clone(), |             merchant_order_id: item.payment_id.clone(), | ||||||
|         }) |         }) | ||||||
| @ -145,7 +146,7 @@ impl<F, T> TryFrom<types::ResponseRouterData<F, AirwallexAuthUpdateResponse, T, | |||||||
| pub struct AirwallexPaymentsCaptureRequest { | pub struct AirwallexPaymentsCaptureRequest { | ||||||
|     // Unique ID to be sent for each transaction/operation request to the connector |     // Unique ID to be sent for each transaction/operation request to the connector | ||||||
|     request_id: String, |     request_id: String, | ||||||
|     amount: Option<i64>, |     amount: Option<String>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl TryFrom<&types::PaymentsCaptureRouterData> for AirwallexPaymentsCaptureRequest { | impl TryFrom<&types::PaymentsCaptureRouterData> for AirwallexPaymentsCaptureRequest { | ||||||
| @ -153,7 +154,13 @@ impl TryFrom<&types::PaymentsCaptureRouterData> for AirwallexPaymentsCaptureRequ | |||||||
|     fn try_from(item: &types::PaymentsCaptureRouterData) -> Result<Self, Self::Error> { |     fn try_from(item: &types::PaymentsCaptureRouterData) -> Result<Self, Self::Error> { | ||||||
|         Ok(Self { |         Ok(Self { | ||||||
|             request_id: Uuid::new_v4().to_string(), |             request_id: Uuid::new_v4().to_string(), | ||||||
|             amount: item.request.amount_to_capture, |             amount: match item.request.amount_to_capture { | ||||||
|  |                 Some(_a) => Some(utils::to_currency_base_unit( | ||||||
|  |                     item.request.amount, | ||||||
|  |                     item.request.currency, | ||||||
|  |                 )?), | ||||||
|  |                 _ => None, | ||||||
|  |             }, | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -224,7 +231,7 @@ pub struct AirwallexPaymentsResponse { | |||||||
|     status: AirwallexPaymentStatus, |     status: AirwallexPaymentStatus, | ||||||
|     //Unique identifier for the PaymentIntent |     //Unique identifier for the PaymentIntent | ||||||
|     id: String, |     id: String, | ||||||
|     amount: Option<i64>, |     amount: Option<f32>, | ||||||
|     //ID of the PaymentConsent related to this PaymentIntent |     //ID of the PaymentConsent related to this PaymentIntent | ||||||
|     payment_consent_id: Option<String>, |     payment_consent_id: Option<String>, | ||||||
|     next_action: Option<AirwallexPaymentsNextAction>, |     next_action: Option<AirwallexPaymentsNextAction>, | ||||||
| @ -277,18 +284,21 @@ impl<F, T> | |||||||
| pub struct AirwallexRefundRequest { | pub struct AirwallexRefundRequest { | ||||||
|     // Unique ID to be sent for each transaction/operation request to the connector |     // Unique ID to be sent for each transaction/operation request to the connector | ||||||
|     request_id: String, |     request_id: String, | ||||||
|     amount: Option<i64>, |     amount: Option<String>, | ||||||
|     reason: Option<String>, |     reason: Option<String>, | ||||||
|     //Identifier for the PaymentIntent for which Refund is requested |     //Identifier for the PaymentIntent for which Refund is requested | ||||||
|     payment_intent_id: String, |     payment_intent_id: String, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<F> TryFrom<&types::RefundsRouterData<F>> for AirwallexRefundRequest { | impl<F> TryFrom<&types::RefundsRouterData<F>> for AirwallexRefundRequest { | ||||||
|     type Error = error_stack::Report<errors::ParsingError>; |     type Error = error_stack::Report<errors::ConnectorError>; | ||||||
|     fn try_from(item: &types::RefundsRouterData<F>) -> Result<Self, Self::Error> { |     fn try_from(item: &types::RefundsRouterData<F>) -> Result<Self, Self::Error> { | ||||||
|         Ok(Self { |         Ok(Self { | ||||||
|             request_id: Uuid::new_v4().to_string(), |             request_id: Uuid::new_v4().to_string(), | ||||||
|             amount: Some(item.request.refund_amount), |             amount: Some(utils::to_currency_base_unit( | ||||||
|  |                 item.request.refund_amount, | ||||||
|  |                 item.request.currency, | ||||||
|  |             )?), | ||||||
|             reason: item.request.reason.clone(), |             reason: item.request.reason.clone(), | ||||||
|             payment_intent_id: item.request.connector_transaction_id.clone(), |             payment_intent_id: item.request.connector_transaction_id.clone(), | ||||||
|         }) |         }) | ||||||
| @ -320,7 +330,7 @@ impl From<RefundStatus> for enums::RefundStatus { | |||||||
| pub struct RefundResponse { | pub struct RefundResponse { | ||||||
|     //A unique number that tags a credit or debit card transaction when it goes from the merchant's bank through to the cardholder's bank. |     //A unique number that tags a credit or debit card transaction when it goes from the merchant's bank through to the cardholder's bank. | ||||||
|     acquirer_reference_number: String, |     acquirer_reference_number: String, | ||||||
|     amount: i64, |     amount: f32, | ||||||
|     //Unique identifier for the Refund |     //Unique identifier for the Refund | ||||||
|     id: String, |     id: String, | ||||||
|     status: RefundStatus, |     status: RefundStatus, | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ use common_utils::ext_traits::ValueExt; | |||||||
| use error_stack::ResultExt; | use error_stack::ResultExt; | ||||||
| use masking::{Deserialize, Serialize}; | use masking::{Deserialize, Serialize}; | ||||||
|  |  | ||||||
| use crate::{core::errors, types, utils::OptionExt}; | use crate::{connector::utils, core::errors, types, utils::OptionExt}; | ||||||
|  |  | ||||||
| #[derive(Debug, Serialize)] | #[derive(Debug, Serialize)] | ||||||
| #[serde(rename_all = "camelCase")] | #[serde(rename_all = "camelCase")] | ||||||
| @ -134,7 +134,10 @@ impl<F> | |||||||
|         let amount_info = AmountInfo { |         let amount_info = AmountInfo { | ||||||
|             label: metadata.payment_request_data.label, |             label: metadata.payment_request_data.label, | ||||||
|             label_type: "final".to_string(), |             label_type: "final".to_string(), | ||||||
|             amount: (item.data.request.amount / 100).to_string(), |             amount: utils::to_currency_base_unit( | ||||||
|  |                 item.data.request.amount, | ||||||
|  |                 item.data.request.currency, | ||||||
|  |             )?, | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         let payment_request = PaymentRequest { |         let payment_request = PaymentRequest { | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||||
|  |  | ||||||
| use crate::{ | use crate::{ | ||||||
|  |     connector::utils, | ||||||
|     core::errors, |     core::errors, | ||||||
|     pii::{self, Secret}, |     pii::{self, Secret}, | ||||||
|     types::{self, api, storage::enums, transformers::ForeignTryFrom}, |     types::{self, api, storage::enums, transformers::ForeignTryFrom}, | ||||||
| @ -9,11 +10,10 @@ use crate::{ | |||||||
| #[derive(Debug, Serialize, PartialEq)] | #[derive(Debug, Serialize, PartialEq)] | ||||||
| #[serde(rename_all = "camelCase")] | #[serde(rename_all = "camelCase")] | ||||||
| pub struct BluesnapPaymentsRequest { | pub struct BluesnapPaymentsRequest { | ||||||
|     amount: i64, |     amount: String, | ||||||
|     #[serde(flatten)] |     #[serde(flatten)] | ||||||
|     payment_method: PaymentMethodDetails, |     payment_method: PaymentMethodDetails, | ||||||
|     currency: enums::Currency, |     currency: enums::Currency, | ||||||
|     soft_descriptor: Option<String>, |  | ||||||
|     card_transaction_type: BluesnapTxnType, |     card_transaction_type: BluesnapTxnType, | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -51,10 +51,9 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for BluesnapPaymentsRequest { | |||||||
|             )), |             )), | ||||||
|         }?; |         }?; | ||||||
|         Ok(Self { |         Ok(Self { | ||||||
|             amount: item.request.amount, |             amount: utils::to_currency_base_unit(item.request.amount, item.request.currency)?, | ||||||
|             payment_method, |             payment_method, | ||||||
|             currency: item.request.currency, |             currency: item.request.currency, | ||||||
|             soft_descriptor: item.description.clone(), |  | ||||||
|             card_transaction_type: auth_mode, |             card_transaction_type: auth_mode, | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| @ -84,7 +83,7 @@ impl TryFrom<&types::PaymentsCancelRouterData> for BluesnapVoidRequest { | |||||||
| pub struct BluesnapCaptureRequest { | pub struct BluesnapCaptureRequest { | ||||||
|     card_transaction_type: BluesnapTxnType, |     card_transaction_type: BluesnapTxnType, | ||||||
|     transaction_id: String, |     transaction_id: String, | ||||||
|     amount: Option<i64>, |     amount: Option<String>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl TryFrom<&types::PaymentsCaptureRouterData> for BluesnapCaptureRequest { | impl TryFrom<&types::PaymentsCaptureRouterData> for BluesnapCaptureRequest { | ||||||
| @ -92,10 +91,14 @@ impl TryFrom<&types::PaymentsCaptureRouterData> for BluesnapCaptureRequest { | |||||||
|     fn try_from(item: &types::PaymentsCaptureRouterData) -> Result<Self, Self::Error> { |     fn try_from(item: &types::PaymentsCaptureRouterData) -> Result<Self, Self::Error> { | ||||||
|         let card_transaction_type = BluesnapTxnType::Capture; |         let card_transaction_type = BluesnapTxnType::Capture; | ||||||
|         let transaction_id = item.request.connector_transaction_id.to_string(); |         let transaction_id = item.request.connector_transaction_id.to_string(); | ||||||
|  |         let amount = utils::to_currency_base_unit_from_optional_amount( | ||||||
|  |             item.request.amount_to_capture, | ||||||
|  |             item.request.currency, | ||||||
|  |         )?; | ||||||
|         Ok(Self { |         Ok(Self { | ||||||
|             card_transaction_type, |             card_transaction_type, | ||||||
|             transaction_id, |             transaction_id, | ||||||
|             amount: item.request.amount_to_capture, |             amount: Some(amount), | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -232,7 +235,7 @@ impl<F, T> | |||||||
|  |  | ||||||
| #[derive(Default, Debug, Eq, PartialEq, Serialize)] | #[derive(Default, Debug, Eq, PartialEq, Serialize)] | ||||||
| pub struct BluesnapRefundRequest { | pub struct BluesnapRefundRequest { | ||||||
|     amount: Option<i64>, |     amount: Option<String>, | ||||||
|     reason: Option<String>, |     reason: Option<String>, | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -241,7 +244,10 @@ impl<F> TryFrom<&types::RefundsRouterData<F>> for BluesnapRefundRequest { | |||||||
|     fn try_from(item: &types::RefundsRouterData<F>) -> Result<Self, Self::Error> { |     fn try_from(item: &types::RefundsRouterData<F>) -> Result<Self, Self::Error> { | ||||||
|         Ok(Self { |         Ok(Self { | ||||||
|             reason: item.request.reason.clone(), |             reason: item.request.reason.clone(), | ||||||
|             amount: Some(item.request.refund_amount), |             amount: Some(utils::to_currency_base_unit( | ||||||
|  |                 item.request.refund_amount, | ||||||
|  |                 item.request.currency, | ||||||
|  |             )?), | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ use masking::Secret; | |||||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||||
|  |  | ||||||
| use crate::{ | use crate::{ | ||||||
|  |     connector::utils, | ||||||
|     consts, |     consts, | ||||||
|     core::errors, |     core::errors, | ||||||
|     types::{self, api, storage::enums}, |     types::{self, api, storage::enums}, | ||||||
| @ -91,7 +92,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for BraintreePaymentsRequest { | |||||||
|             Some(enums::CaptureMethod::Automatic) | None |             Some(enums::CaptureMethod::Automatic) | None | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
|         let amount = item.request.amount.to_string(); |         let amount = utils::to_currency_base_unit(item.request.amount, item.request.currency)?; | ||||||
|         let device_data = DeviceData {}; |         let device_data = DeviceData {}; | ||||||
|         let options = PaymentOptions { |         let options = PaymentOptions { | ||||||
|             submit_for_settlement, |             submit_for_settlement, | ||||||
|  | |||||||
| @ -596,30 +596,42 @@ impl TryFrom<types::RefundsResponseRouterData<api::Execute, NuveiPaymentsRespons | |||||||
|     fn try_from( |     fn try_from( | ||||||
|         item: types::RefundsResponseRouterData<api::Execute, NuveiPaymentsResponse>, |         item: types::RefundsResponseRouterData<api::Execute, NuveiPaymentsResponse>, | ||||||
|     ) -> Result<Self, Self::Error> { |     ) -> Result<Self, Self::Error> { | ||||||
|         let refund_status = item |         let response = item.response; | ||||||
|             .response |         let http_code = item.http_code; | ||||||
|  |         let refund_status = response | ||||||
|             .transaction_status |             .transaction_status | ||||||
|             .clone() |             .clone() | ||||||
|             .map(|a| a.into()) |             .map(|a| a.into()) | ||||||
|             .unwrap_or_else(|| enums::RefundStatus::Failure); |             .unwrap_or(enums::RefundStatus::Failure); | ||||||
|         let refund_response = match item.response.status { |         let refund_response = match response.status { | ||||||
|             NuveiPaymentStatus::Error => Err(types::ErrorResponse { |             NuveiPaymentStatus::Error => Err(types::ErrorResponse { | ||||||
|                 code: item |                 code: response | ||||||
|                     .response |  | ||||||
|                     .err_code |                     .err_code | ||||||
|                     .map(|c| c.to_string()) |                     .map(|c| c.to_string()) | ||||||
|                     .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()), |                     .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()), | ||||||
|                 message: item |                 message: response | ||||||
|                     .response |  | ||||||
|                     .reason |                     .reason | ||||||
|                     .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()), |                     .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()), | ||||||
|                 reason: None, |                 reason: None, | ||||||
|                 status_code: item.http_code, |                 status_code: http_code, | ||||||
|             }), |  | ||||||
|             _ => Ok(types::RefundsResponseData { |  | ||||||
|                 connector_refund_id: item.response.transaction_id.ok_or(errors::ParsingError)?, |  | ||||||
|                 refund_status, |  | ||||||
|             }), |             }), | ||||||
|  |             _ => match response.transaction_status { | ||||||
|  |                 Some(NuveiTransactionStatus::Error) => Err(types::ErrorResponse { | ||||||
|  |                     code: response | ||||||
|  |                         .gw_error_code | ||||||
|  |                         .map(|c| c.to_string()) | ||||||
|  |                         .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()), | ||||||
|  |                     message: response | ||||||
|  |                         .gw_error_reason | ||||||
|  |                         .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()), | ||||||
|  |                     reason: None, | ||||||
|  |                     status_code: http_code, | ||||||
|  |                 }), | ||||||
|  |                 _ => Ok(types::RefundsResponseData { | ||||||
|  |                     connector_refund_id: response.transaction_id.ok_or(errors::ParsingError)?, | ||||||
|  |                     refund_status, | ||||||
|  |                 }), | ||||||
|  |             }, | ||||||
|         }; |         }; | ||||||
|         Ok(Self { |         Ok(Self { | ||||||
|             response: refund_response, |             response: refund_response, | ||||||
| @ -635,30 +647,42 @@ impl TryFrom<types::RefundsResponseRouterData<api::RSync, NuveiPaymentsResponse> | |||||||
|     fn try_from( |     fn try_from( | ||||||
|         item: types::RefundsResponseRouterData<api::RSync, NuveiPaymentsResponse>, |         item: types::RefundsResponseRouterData<api::RSync, NuveiPaymentsResponse>, | ||||||
|     ) -> Result<Self, Self::Error> { |     ) -> Result<Self, Self::Error> { | ||||||
|         let refund_status = item |         let response = item.response; | ||||||
|             .response |         let http_code = item.http_code; | ||||||
|  |         let refund_status = response | ||||||
|             .transaction_status |             .transaction_status | ||||||
|             .clone() |             .clone() | ||||||
|             .map(|a| a.into()) |             .map(|a| a.into()) | ||||||
|             .unwrap_or(enums::RefundStatus::Failure); |             .unwrap_or(enums::RefundStatus::Failure); | ||||||
|         let refund_response = match item.response.status { |         let refund_response = match response.status { | ||||||
|             NuveiPaymentStatus::Error => Err(types::ErrorResponse { |             NuveiPaymentStatus::Error => Err(types::ErrorResponse { | ||||||
|                 code: item |                 code: response | ||||||
|                     .response |  | ||||||
|                     .err_code |                     .err_code | ||||||
|                     .map(|c| c.to_string()) |                     .map(|c| c.to_string()) | ||||||
|                     .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()), |                     .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()), | ||||||
|                 message: item |                 message: response | ||||||
|                     .response |  | ||||||
|                     .reason |                     .reason | ||||||
|                     .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()), |                     .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()), | ||||||
|                 reason: None, |                 reason: None, | ||||||
|                 status_code: item.http_code, |                 status_code: http_code, | ||||||
|             }), |  | ||||||
|             _ => Ok(types::RefundsResponseData { |  | ||||||
|                 connector_refund_id: item.response.transaction_id.ok_or(errors::ParsingError)?, |  | ||||||
|                 refund_status, |  | ||||||
|             }), |             }), | ||||||
|  |             _ => match response.transaction_status { | ||||||
|  |                 Some(NuveiTransactionStatus::Error) => Err(types::ErrorResponse { | ||||||
|  |                     code: response | ||||||
|  |                         .gw_error_code | ||||||
|  |                         .map(|c| c.to_string()) | ||||||
|  |                         .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()), | ||||||
|  |                     message: response | ||||||
|  |                         .gw_error_reason | ||||||
|  |                         .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()), | ||||||
|  |                     reason: None, | ||||||
|  |                     status_code: http_code, | ||||||
|  |                 }), | ||||||
|  |                 _ => Ok(types::RefundsResponseData { | ||||||
|  |                     connector_refund_id: response.transaction_id.ok_or(errors::ParsingError)?, | ||||||
|  |                     refund_status, | ||||||
|  |                 }), | ||||||
|  |             }, | ||||||
|         }; |         }; | ||||||
|         Ok(Self { |         Ok(Self { | ||||||
|             response: refund_response, |             response: refund_response, | ||||||
|  | |||||||
| @ -323,3 +323,35 @@ pub fn get_header_key_value<'a>( | |||||||
|             errors::ConnectorError::WebhookSourceVerificationFailed |             errors::ConnectorError::WebhookSourceVerificationFailed | ||||||
|         ))? |         ))? | ||||||
| } | } | ||||||
|  |  | ||||||
|  | pub fn to_currency_base_unit_from_optional_amount( | ||||||
|  |     amount: Option<i64>, | ||||||
|  |     currency: storage_models::enums::Currency, | ||||||
|  | ) -> Result<String, error_stack::Report<errors::ConnectorError>> { | ||||||
|  |     match amount { | ||||||
|  |         Some(a) => to_currency_base_unit(a, currency), | ||||||
|  |         _ => Err(errors::ConnectorError::MissingRequiredField { | ||||||
|  |             field_name: "amount", | ||||||
|  |         } | ||||||
|  |         .into()), | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn to_currency_base_unit( | ||||||
|  |     amount: i64, | ||||||
|  |     currency: storage_models::enums::Currency, | ||||||
|  | ) -> Result<String, error_stack::Report<errors::ConnectorError>> { | ||||||
|  |     let amount_u32 = u32::try_from(amount) | ||||||
|  |         .into_report() | ||||||
|  |         .change_context(errors::ConnectorError::RequestEncodingFailed)?; | ||||||
|  |     match currency { | ||||||
|  |         storage_models::enums::Currency::JPY | storage_models::enums::Currency::KRW => { | ||||||
|  |             Ok(amount.to_string()) | ||||||
|  |         } | ||||||
|  |         storage_models::enums::Currency::BHD | ||||||
|  |         | storage_models::enums::Currency::JOD | ||||||
|  |         | storage_models::enums::Currency::KWD | ||||||
|  |         | storage_models::enums::Currency::OMR => Ok((f64::from(amount_u32) / 1000.0).to_string()), | ||||||
|  |         _ => Ok((f64::from(amount_u32) / 100.0).to_string()), | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 SamraatBansal
					SamraatBansal