use std::num::NonZeroI64; use common_utils::pii; use masking::{PeekInterface, Secret}; use router_derive::Setter; use time::PrimitiveDateTime; use crate::{enums as api_enums, refunds}; #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum PaymentOp { Create, Update, Confirm, } #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)] #[serde(deny_unknown_fields)] pub struct PaymentsRequest { #[serde(default, deserialize_with = "payment_id_type::deserialize_option")] pub payment_id: Option, pub merchant_id: Option, #[serde(default, deserialize_with = "amount::deserialize_option")] pub amount: Option, pub connector: Option, pub currency: Option, pub capture_method: Option, pub amount_to_capture: Option, #[serde(default, with = "common_utils::custom_serde::iso8601::option")] pub capture_on: Option, pub confirm: Option, pub customer_id: Option, pub email: Option>, pub name: Option>, pub phone: Option>, pub phone_country_code: Option, pub off_session: Option, pub description: Option, pub return_url: Option, pub setup_future_usage: Option, pub authentication_type: Option, pub payment_method_data: Option, pub payment_method: Option, pub payment_token: Option, pub card_cvc: Option>, pub shipping: Option
, pub billing: Option
, pub statement_descriptor_name: Option, pub statement_descriptor_suffix: Option, pub metadata: Option, pub client_secret: Option, pub mandate_data: Option, pub mandate_id: Option, pub browser_info: Option, } #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq, Eq)] pub enum Amount { Value(NonZeroI64), #[default] Zero, } impl From for i64 { fn from(amount: Amount) -> Self { match amount { Amount::Value(val) => val.get(), Amount::Zero => 0, } } } impl From for Amount { fn from(val: i64) -> Self { NonZeroI64::new(val).map_or(Amount::Zero, Amount::Value) } } #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)] #[serde(deny_unknown_fields)] pub struct PaymentsRedirectRequest { pub payment_id: String, pub merchant_id: String, pub connector: String, pub param: String, } #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)] #[serde(deny_unknown_fields)] pub struct VerifyRequest { // The merchant_id is generated through api key // and is later passed in the struct pub merchant_id: Option, pub customer_id: Option, pub email: Option>, pub name: Option>, pub phone: Option>, pub phone_country_code: Option, pub payment_method: Option, pub payment_method_data: Option, pub payment_token: Option, pub mandate_data: Option, pub setup_future_usage: Option, pub off_session: Option, pub client_secret: Option, } impl From for VerifyRequest { fn from(item: PaymentsRequest) -> Self { Self { client_secret: item.client_secret, merchant_id: item.merchant_id, customer_id: item.customer_id, email: item.email, name: item.name, phone: item.phone, phone_country_code: item.phone_country_code, payment_method: item.payment_method, payment_method_data: item.payment_method_data, payment_token: item.payment_token, mandate_data: item.mandate_data, setup_future_usage: item.setup_future_usage, off_session: item.off_session, } } } pub enum MandateTxnType { NewMandateTxn, RecurringMandateTxn, } #[derive(Default, Eq, PartialEq, Debug, serde::Deserialize, serde::Serialize, Clone)] #[serde(deny_unknown_fields)] pub struct MandateData { pub customer_acceptance: CustomerAcceptance, pub mandate_type: MandateType, } #[derive(Clone, Eq, PartialEq, Copy, Debug, Default, serde::Serialize, serde::Deserialize)] pub struct SingleUseMandate { pub amount: i64, pub currency: api_enums::Currency, } #[derive(Clone, Eq, PartialEq, Copy, Debug, Default, serde::Serialize, serde::Deserialize)] pub struct MandateAmountData { pub amount: i64, pub currency: api_enums::Currency, } #[derive(Eq, PartialEq, Debug, serde::Deserialize, serde::Serialize, Clone)] #[serde(rename_all = "snake_case")] pub enum MandateType { SingleUse(MandateAmountData), MultiUse(Option), } impl Default for MandateType { fn default() -> Self { Self::MultiUse(None) } } #[derive(Default, Eq, PartialEq, Debug, serde::Deserialize, serde::Serialize, Clone)] #[serde(deny_unknown_fields)] pub struct CustomerAcceptance { pub acceptance_type: AcceptanceType, #[serde(default, with = "common_utils::custom_serde::iso8601::option")] pub accepted_at: Option, pub online: Option, } #[derive(Default, Debug, serde::Deserialize, serde::Serialize, PartialEq, Eq, Clone)] #[serde(rename_all = "lowercase")] pub enum AcceptanceType { Online, #[default] Offline, } #[derive(Default, Eq, PartialEq, Debug, serde::Deserialize, serde::Serialize, Clone)] #[serde(deny_unknown_fields)] pub struct OnlineMandate { pub ip_address: Secret, pub user_agent: String, } #[derive(Default, Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize)] pub struct CCard { pub card_number: Secret, pub card_exp_month: Secret, pub card_exp_year: Secret, pub card_holder_name: Secret, pub card_cvc: Secret, } #[derive(Default, Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize)] pub struct PayLaterData { pub billing_email: String, pub country: String, } #[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)] pub enum PaymentMethod { #[serde(rename(deserialize = "card"))] Card(CCard), #[serde(rename(deserialize = "bank_transfer"))] BankTransfer, #[serde(rename(deserialize = "wallet"))] Wallet(WalletData), #[serde(rename(deserialize = "pay_later"))] PayLater(PayLaterData), #[serde(rename(deserialize = "paypal"))] Paypal, } #[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)] pub struct WalletData { pub issuer_name: api_enums::WalletIssuer, pub token: String, } #[derive(Eq, PartialEq, Clone, Debug, serde::Serialize)] pub struct CCardResponse { last4: String, exp_month: String, exp_year: String, } #[derive(Debug, Clone, Eq, PartialEq, serde::Serialize)] pub enum PaymentMethodDataResponse { #[serde(rename = "card")] Card(CCardResponse), #[serde(rename(deserialize = "bank_transfer"))] BankTransfer, Wallet(WalletData), PayLater(PayLaterData), Paypal, } impl Default for PaymentMethod { fn default() -> Self { PaymentMethod::BankTransfer } } #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub enum PaymentIdType { PaymentIntentId(String), ConnectorTransactionId(String), PaymentTxnId(String), } impl Default for PaymentIdType { fn default() -> Self { Self::PaymentIntentId(Default::default()) } } //#[derive(Debug, serde::Deserialize, serde::Serialize)] //#[serde(untagged)] //pub enum enums::CaptureMethod { //Automatic, //Manual, //} //impl Default for enums::CaptureMethod { //fn default() -> Self { //enums::CaptureMethod::Manual //} //} #[derive( Default, Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, frunk::LabelledGeneric, )] #[serde(deny_unknown_fields)] pub struct Address { pub address: Option, pub phone: Option, } // used by customers also, could be moved outside #[derive( Clone, Default, Debug, Eq, serde::Deserialize, serde::Serialize, PartialEq, frunk::LabelledGeneric, )] #[serde(deny_unknown_fields)] pub struct AddressDetails { pub city: Option, pub country: Option, pub line1: Option>, pub line2: Option>, pub line3: Option>, pub zip: Option>, pub state: Option>, pub first_name: Option>, pub last_name: Option>, } #[derive( Debug, Clone, Default, Eq, PartialEq, serde::Deserialize, serde::Serialize, frunk::LabelledGeneric, )] pub struct PhoneDetails { pub number: Option>, pub country_code: Option, } #[derive(Debug, Clone, Default, Eq, PartialEq, serde::Deserialize)] pub struct PaymentsCaptureRequest { pub payment_id: Option, pub merchant_id: Option, pub amount_to_capture: Option, pub refund_uncaptured_amount: Option, pub statement_descriptor_suffix: Option, pub statement_descriptor_prefix: Option, } #[derive(Default, Clone, Debug, Eq, PartialEq, serde::Serialize)] pub struct UrlDetails { pub url: String, pub method: String, } #[derive(Default, Clone, Debug, Eq, PartialEq, serde::Serialize)] pub struct AuthenticationForStartResponse { pub authentication: UrlDetails, } #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)] #[serde(rename_all = "snake_case")] pub enum NextActionType { RedirectToUrl, DisplayQrCode, InvokeSdkClient, TriggerApi, } #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)] pub struct NextAction { #[serde(rename = "type")] pub next_action_type: NextActionType, pub redirect_to_url: Option, } #[derive(Setter, Clone, Default, Debug, Eq, PartialEq, serde::Serialize)] pub struct PaymentsResponse { pub payment_id: Option, pub merchant_id: Option, pub status: api_enums::IntentStatus, pub amount: i64, pub amount_capturable: Option, pub amount_received: Option, pub connector: Option, pub client_secret: Option>, #[serde(with = "common_utils::custom_serde::iso8601::option")] pub created: Option, pub currency: String, pub customer_id: Option, pub description: Option, pub refunds: Option>, pub mandate_id: Option, pub mandate_data: Option, pub setup_future_usage: Option, pub off_session: Option, #[serde(with = "common_utils::custom_serde::iso8601::option")] pub capture_on: Option, pub capture_method: Option, #[auth_based] pub payment_method: Option, #[auth_based] pub payment_method_data: Option, pub payment_token: Option, pub shipping: Option
, pub billing: Option
, pub metadata: Option, pub email: Option>, pub name: Option>, pub phone: Option>, pub return_url: Option, pub authentication_type: Option, pub statement_descriptor_name: Option, pub statement_descriptor_suffix: Option, pub next_action: Option, pub cancellation_reason: Option, pub error_code: Option, pub error_message: Option, } #[derive(Clone, Debug, serde::Deserialize)] #[serde(deny_unknown_fields)] pub struct PaymentListConstraints { pub customer_id: Option, pub starting_after: Option, pub ending_before: Option, #[serde(default = "default_limit")] pub limit: i64, #[serde(default, with = "common_utils::custom_serde::iso8601::option")] pub created: Option, #[serde(default, with = "common_utils::custom_serde::iso8601::option")] #[serde(rename = "created.lt")] pub created_lt: Option, #[serde(default, with = "common_utils::custom_serde::iso8601::option")] #[serde(rename = "created.gt")] pub created_gt: Option, #[serde(default, with = "common_utils::custom_serde::iso8601::option")] #[serde(rename = "created.lte")] pub created_lte: Option, #[serde(default, with = "common_utils::custom_serde::iso8601::option")] #[serde(rename = "created.gte")] pub created_gte: Option, } #[derive(Clone, Debug, serde::Serialize)] pub struct PaymentListResponse { pub size: usize, pub data: Vec, } #[derive(Setter, Clone, Default, Debug, Eq, PartialEq, serde::Serialize)] pub struct VerifyResponse { pub verify_id: Option, pub merchant_id: Option, // pub status: enums::VerifyStatus, pub client_secret: Option>, pub customer_id: Option, pub email: Option>, pub name: Option>, pub phone: Option>, pub mandate_id: Option, #[auth_based] pub payment_method: Option, #[auth_based] pub payment_method_data: Option, pub payment_token: Option, pub error_code: Option, pub error_message: Option, } fn default_limit() -> i64 { 10 } #[derive(Default, Debug, serde::Deserialize, serde::Serialize)] pub struct PaymentsRedirectionResponse { pub redirect_url: String, } pub struct MandateValidationFields { pub mandate_id: Option, pub confirm: Option, pub customer_id: Option, pub mandate_data: Option, pub setup_future_usage: Option, pub off_session: Option, } impl From<&PaymentsRequest> for MandateValidationFields { fn from(req: &PaymentsRequest) -> Self { Self { mandate_id: req.mandate_id.clone(), confirm: req.confirm, customer_id: req.customer_id.clone(), mandate_data: req.mandate_data.clone(), setup_future_usage: req.setup_future_usage, off_session: req.off_session, } } } impl From<&VerifyRequest> for MandateValidationFields { fn from(req: &VerifyRequest) -> Self { Self { mandate_id: None, confirm: Some(true), customer_id: req.customer_id.clone(), mandate_data: req.mandate_data.clone(), off_session: req.off_session, setup_future_usage: req.setup_future_usage, } } } impl From for PaymentsResponse { fn from(item: PaymentsRequest) -> Self { let payment_id = match item.payment_id { Some(PaymentIdType::PaymentIntentId(id)) => Some(id), _ => None, }; Self { payment_id, merchant_id: item.merchant_id, setup_future_usage: item.setup_future_usage, off_session: item.off_session, shipping: item.shipping, billing: item.billing, metadata: item.metadata, capture_method: item.capture_method, payment_method: item.payment_method, capture_on: item.capture_on, payment_method_data: item .payment_method_data .map(PaymentMethodDataResponse::from), email: item.email, name: item.name, phone: item.phone, payment_token: item.payment_token, return_url: item.return_url, authentication_type: item.authentication_type, statement_descriptor_name: item.statement_descriptor_name, statement_descriptor_suffix: item.statement_descriptor_suffix, mandate_data: item.mandate_data, ..Default::default() } } } impl From for VerifyResponse { fn from(item: VerifyRequest) -> Self { Self { merchant_id: item.merchant_id, customer_id: item.customer_id, email: item.email, name: item.name, phone: item.phone, payment_method: item.payment_method, payment_method_data: item .payment_method_data .map(PaymentMethodDataResponse::from), payment_token: item.payment_token, ..Default::default() } } } impl From for PaymentsResponse { fn from(item: PaymentsStartRequest) -> Self { Self { payment_id: Some(item.payment_id), merchant_id: Some(item.merchant_id), ..Default::default() } } } impl From for PaymentsResponse { fn from(item: PaymentsSessionRequest) -> Self { Self { payment_id: Some(item.payment_id), ..Default::default() } } } impl From for PaymentsSessionResponse { fn from(_item: PaymentsSessionRequest) -> Self { Self { session_token: vec![], } } } impl From for PaymentsRequest { fn from(item: PaymentsStartRequest) -> Self { Self { payment_id: Some(PaymentIdType::PaymentIntentId(item.payment_id)), merchant_id: Some(item.merchant_id), ..Default::default() } } } impl From for PaymentsResponse { // After removing the request from the payments_to_payments_response this will no longer be needed fn from(item: PaymentsRetrieveRequest) -> Self { let payment_id = match item.resource_id { PaymentIdType::PaymentIntentId(id) => Some(id), _ => None, }; Self { payment_id, merchant_id: item.merchant_id, ..Default::default() } } } impl From for PaymentsResponse { fn from(item: PaymentsCancelRequest) -> Self { Self { payment_id: Some(item.payment_id), cancellation_reason: item.cancellation_reason, ..Default::default() } } } impl From for PaymentsResponse { // After removing the request from the payments_to_payments_response this will no longer be needed fn from(item: PaymentsCaptureRequest) -> Self { Self { payment_id: item.payment_id, amount_received: item.amount_to_capture, ..Self::default() } } } impl From for CCardResponse { fn from(card: CCard) -> Self { let card_number_length = card.card_number.peek().clone().len(); Self { last4: card.card_number.peek().clone()[card_number_length - 4..card_number_length] .to_string(), exp_month: card.card_exp_month.peek().clone(), exp_year: card.card_exp_year.peek().clone(), } } } impl From for PaymentMethodDataResponse { fn from(payment_method_data: PaymentMethod) -> Self { match payment_method_data { PaymentMethod::Card(card) => PaymentMethodDataResponse::Card(CCardResponse::from(card)), PaymentMethod::BankTransfer => PaymentMethodDataResponse::BankTransfer, PaymentMethod::PayLater(pay_later_data) => { PaymentMethodDataResponse::PayLater(pay_later_data) } PaymentMethod::Wallet(wallet_data) => PaymentMethodDataResponse::Wallet(wallet_data), PaymentMethod::Paypal => PaymentMethodDataResponse::Paypal, } } } #[derive(Debug, Clone, serde::Serialize)] pub struct PgRedirectResponse { pub payment_id: String, pub status: api_enums::IntentStatus, pub gateway_id: String, pub customer_id: Option, pub amount: Option, } #[derive(Debug, serde::Serialize, PartialEq, Eq, serde::Deserialize)] pub struct RedirectionResponse { pub return_url: String, pub params: Vec<(String, String)>, pub return_url_with_query_params: String, pub http_method: String, pub headers: Vec<(String, String)>, } #[derive(Debug, serde::Deserialize)] pub struct PaymentsResponseForm { pub transaction_id: String, // pub transaction_reference_id: String, pub merchant_id: String, pub order_id: String, } #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)] pub struct PaymentsRetrieveRequest { pub resource_id: PaymentIdType, pub merchant_id: Option, pub force_sync: bool, pub param: Option, pub connector: Option, } #[derive(Default, Debug, serde::Deserialize, Clone)] pub struct PaymentsSessionRequest { pub payment_id: String, pub client_secret: String, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct GpayAllowedMethodsParameters { pub allowed_auth_methods: Vec, pub allowed_card_networks: Vec, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct GpayTokenParameters { pub gateway: String, pub gateway_merchant_id: String, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct GpayTokenizationSpecification { #[serde(rename = "type")] pub token_specification_type: String, pub parameters: GpayTokenParameters, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct GpayAllowedPaymentMethods { #[serde(rename = "type")] pub payment_method_type: String, pub parameters: GpayAllowedMethodsParameters, pub tokenization_specification: GpayTokenizationSpecification, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct GpayTransactionInfo { pub country_code: String, pub currency_code: String, pub total_price_status: String, pub total_price: i64, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct GpayMerchantInfo { pub merchant_name: String, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct GpayMetadata { pub merchant_info: GpayMerchantInfo, pub allowed_payment_methods: Vec, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct GpaySessionTokenData { pub gpay: GpayMetadata, } #[derive(Debug, Clone, serde::Serialize)] #[serde(tag = "connector_name")] #[serde(rename_all = "lowercase")] pub enum SessionToken { Gpay { allowed_payment_methods: Vec, transaction_info: GpayTransactionInfo, }, Klarna { session_token: String, session_id: String, }, Paypal { session_token: String, }, Applepay { epoch_timestamp: u64, expires_at: u64, merchant_session_identifier: String, nonce: String, merchant_identifier: String, domain_name: String, display_name: String, signature: String, operational_analytics_identifier: String, retries: u8, psp_id: String, }, } #[derive(Default, Debug, serde::Serialize, Clone)] pub struct PaymentsSessionResponse { pub session_token: Vec, } #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)] pub struct PaymentRetrieveBody { pub merchant_id: Option, pub force_sync: Option, } #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)] pub struct PaymentsCancelRequest { #[serde(skip)] pub payment_id: String, pub cancellation_reason: Option, } #[derive(Default, Debug, serde::Deserialize, serde::Serialize)] pub struct PaymentsStartRequest { pub payment_id: String, pub merchant_id: String, pub txn_id: String, } mod payment_id_type { use std::fmt; use serde::{ de::{self, Visitor}, Deserializer, }; use super::PaymentIdType; struct PaymentIdVisitor; struct OptionalPaymentIdVisitor; impl<'de> Visitor<'de> for PaymentIdVisitor { type Value = PaymentIdType; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("payment id") } fn visit_str(self, value: &str) -> Result where E: de::Error, { Ok(PaymentIdType::PaymentIntentId(value.to_string())) } } impl<'de> Visitor<'de> for OptionalPaymentIdVisitor { type Value = Option; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("payment id") } fn visit_some(self, deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_any(PaymentIdVisitor).map(Some) } fn visit_none(self) -> Result where E: de::Error, { Ok(None) } fn visit_unit(self) -> Result where E: de::Error, { Ok(None) } } #[allow(dead_code)] pub(crate) fn deserialize<'a, D>(deserializer: D) -> Result where D: Deserializer<'a>, { deserializer.deserialize_any(PaymentIdVisitor) } pub(crate) fn deserialize_option<'a, D>( deserializer: D, ) -> Result, D::Error> where D: Deserializer<'a>, { deserializer.deserialize_option(OptionalPaymentIdVisitor) } } mod amount { use serde::de; use super::Amount; struct AmountVisitor; struct OptionalAmountVisitor; // This is defined to provide guarded deserialization of amount // which itself handles zero and non-zero values internally impl<'de> de::Visitor<'de> for AmountVisitor { type Value = Amount; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { write!(formatter, "amount as integer") } fn visit_u64(self, v: u64) -> Result where E: de::Error, { self.visit_i64(v as i64) } fn visit_i64(self, v: i64) -> Result where E: de::Error, { Ok(Amount::from(v)) } } impl<'de> de::Visitor<'de> for OptionalAmountVisitor { type Value = Option; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { write!(formatter, "option of amount (as integer)") } fn visit_some(self, deserializer: D) -> Result where D: serde::Deserializer<'de>, { deserializer.deserialize_i64(AmountVisitor).map(Some) } fn visit_none(self) -> Result where E: de::Error, { Ok(None) } } #[allow(dead_code)] pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result where D: de::Deserializer<'de>, { deserializer.deserialize_any(AmountVisitor) } pub(crate) fn deserialize_option<'de, D>(deserializer: D) -> Result, D::Error> where D: de::Deserializer<'de>, { deserializer.deserialize_option(OptionalAmountVisitor) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_mandate_type() { let mandate_type = MandateType::default(); assert_eq!( serde_json::to_string(&mandate_type).unwrap(), r#"{"multi_use":null}"# ) } }