use common_enums as storage_enums; use common_utils::{ consts::{PAYMENTS_LIST_MAX_LIMIT_V1, PAYMENTS_LIST_MAX_LIMIT_V2}, pii, }; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; use super::{payment_attempt::PaymentAttempt, PaymentIntent}; use crate::{errors, RemoteStorageObject}; #[async_trait::async_trait] pub trait PaymentIntentInterface { async fn update_payment_intent( &self, this: PaymentIntent, payment_intent: PaymentIntentUpdate, storage_scheme: storage_enums::MerchantStorageScheme, ) -> error_stack::Result; async fn insert_payment_intent( &self, new: PaymentIntentNew, storage_scheme: storage_enums::MerchantStorageScheme, ) -> error_stack::Result; async fn find_payment_intent_by_payment_id_merchant_id( &self, payment_id: &str, merchant_id: &str, storage_scheme: storage_enums::MerchantStorageScheme, ) -> error_stack::Result; async fn get_active_payment_attempt( &self, payment: &mut PaymentIntent, storage_scheme: storage_enums::MerchantStorageScheme, ) -> error_stack::Result; #[cfg(feature = "olap")] async fn filter_payment_intent_by_constraints( &self, merchant_id: &str, filters: &PaymentIntentFetchConstraints, storage_scheme: storage_enums::MerchantStorageScheme, ) -> error_stack::Result, errors::StorageError>; #[cfg(feature = "olap")] async fn filter_payment_intents_by_time_range_constraints( &self, merchant_id: &str, time_range: &api_models::payments::TimeRange, storage_scheme: storage_enums::MerchantStorageScheme, ) -> error_stack::Result, errors::StorageError>; #[cfg(feature = "olap")] async fn get_filtered_payment_intents_attempt( &self, merchant_id: &str, constraints: &PaymentIntentFetchConstraints, storage_scheme: storage_enums::MerchantStorageScheme, ) -> error_stack::Result, errors::StorageError>; #[cfg(feature = "olap")] async fn get_filtered_active_attempt_ids_for_total_count( &self, merchant_id: &str, constraints: &PaymentIntentFetchConstraints, storage_scheme: storage_enums::MerchantStorageScheme, ) -> error_stack::Result, errors::StorageError>; } #[derive(Clone, Debug, Eq, PartialEq)] pub struct PaymentIntentNew { pub payment_id: String, pub merchant_id: String, pub status: storage_enums::IntentStatus, pub amount: i64, pub currency: Option, pub amount_captured: Option, pub customer_id: Option, pub description: Option, pub return_url: Option, pub metadata: Option, pub connector_id: Option, pub shipping_address_id: Option, pub billing_address_id: Option, pub statement_descriptor_name: Option, pub statement_descriptor_suffix: Option, pub created_at: Option, pub modified_at: Option, pub last_synced: Option, pub setup_future_usage: Option, pub off_session: Option, pub client_secret: Option, pub active_attempt: RemoteStorageObject, pub business_country: Option, pub business_label: Option, pub order_details: Option>, pub allowed_payment_method_types: Option, pub connector_metadata: Option, pub feature_metadata: Option, pub attempt_count: i16, pub profile_id: Option, pub merchant_decision: Option, pub payment_link_id: Option, pub payment_confirm_source: Option, pub updated_by: String, pub surcharge_applicable: Option, pub request_incremental_authorization: Option, pub incremental_authorization_allowed: Option, pub authorization_count: Option, pub session_expiry: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] pub enum PaymentIntentUpdate { ResponseUpdate { status: storage_enums::IntentStatus, amount_captured: Option, return_url: Option, updated_by: String, incremental_authorization_allowed: Option, }, MetadataUpdate { metadata: pii::SecretSerdeValue, updated_by: String, }, ReturnUrlUpdate { return_url: Option, status: Option, customer_id: Option, shipping_address_id: Option, billing_address_id: Option, updated_by: String, }, MerchantStatusUpdate { status: storage_enums::IntentStatus, shipping_address_id: Option, billing_address_id: Option, updated_by: String, }, PGStatusUpdate { status: storage_enums::IntentStatus, incremental_authorization_allowed: Option, updated_by: String, }, Update { amount: i64, currency: storage_enums::Currency, setup_future_usage: Option, status: storage_enums::IntentStatus, customer_id: Option, shipping_address_id: Option, billing_address_id: Option, return_url: Option, business_country: Option, business_label: Option, description: Option, statement_descriptor_name: Option, statement_descriptor_suffix: Option, order_details: Option>, metadata: Option, payment_confirm_source: Option, updated_by: String, session_expiry: Option, }, PaymentAttemptAndAttemptCountUpdate { active_attempt_id: String, attempt_count: i16, updated_by: String, }, StatusAndAttemptUpdate { status: storage_enums::IntentStatus, active_attempt_id: String, attempt_count: i16, updated_by: String, }, ApproveUpdate { merchant_decision: Option, updated_by: String, }, RejectUpdate { status: storage_enums::IntentStatus, merchant_decision: Option, updated_by: String, }, SurchargeApplicableUpdate { surcharge_applicable: bool, updated_by: String, }, IncrementalAuthorizationAmountUpdate { amount: i64, }, AuthorizationCountUpdate { authorization_count: i32, }, } #[derive(Clone, Debug, Default)] pub struct PaymentIntentUpdateInternal { pub amount: Option, pub currency: Option, pub status: Option, pub amount_captured: Option, pub customer_id: Option, pub return_url: Option, pub setup_future_usage: Option, pub off_session: Option, pub metadata: Option, pub billing_address_id: Option, pub shipping_address_id: Option, pub modified_at: Option, pub active_attempt_id: Option, pub business_country: Option, pub business_label: Option, pub description: Option, pub statement_descriptor_name: Option, pub statement_descriptor_suffix: Option, pub order_details: Option>, pub attempt_count: Option, // Denotes the action(approve or reject) taken by merchant in case of manual review. // Manual review can occur when the transaction is marked as risky by the frm_processor, payment processor or when there is underpayment/over payment incase of crypto payment pub merchant_decision: Option, pub payment_confirm_source: Option, pub updated_by: String, pub surcharge_applicable: Option, pub incremental_authorization_allowed: Option, pub authorization_count: Option, pub session_expiry: Option, } impl From for PaymentIntentUpdateInternal { fn from(payment_intent_update: PaymentIntentUpdate) -> Self { match payment_intent_update { PaymentIntentUpdate::Update { amount, currency, setup_future_usage, status, customer_id, shipping_address_id, billing_address_id, return_url, business_country, business_label, description, statement_descriptor_name, statement_descriptor_suffix, order_details, metadata, payment_confirm_source, updated_by, session_expiry, } => Self { amount: Some(amount), currency: Some(currency), status: Some(status), setup_future_usage, customer_id, shipping_address_id, billing_address_id, modified_at: Some(common_utils::date_time::now()), return_url, business_country, business_label, description, statement_descriptor_name, statement_descriptor_suffix, order_details, metadata, payment_confirm_source, updated_by, session_expiry, ..Default::default() }, PaymentIntentUpdate::MetadataUpdate { metadata, updated_by, } => Self { metadata: Some(metadata), modified_at: Some(common_utils::date_time::now()), updated_by, ..Default::default() }, PaymentIntentUpdate::ReturnUrlUpdate { return_url, status, customer_id, shipping_address_id, billing_address_id, updated_by, } => Self { return_url, status, customer_id, shipping_address_id, billing_address_id, modified_at: Some(common_utils::date_time::now()), updated_by, ..Default::default() }, PaymentIntentUpdate::PGStatusUpdate { status, updated_by, incremental_authorization_allowed, } => Self { status: Some(status), modified_at: Some(common_utils::date_time::now()), updated_by, incremental_authorization_allowed, ..Default::default() }, PaymentIntentUpdate::MerchantStatusUpdate { status, shipping_address_id, billing_address_id, updated_by, } => Self { status: Some(status), shipping_address_id, billing_address_id, modified_at: Some(common_utils::date_time::now()), updated_by, ..Default::default() }, PaymentIntentUpdate::ResponseUpdate { // amount, // currency, status, amount_captured, // customer_id, return_url, updated_by, incremental_authorization_allowed, } => Self { // amount, // currency: Some(currency), status: Some(status), amount_captured, // customer_id, return_url, modified_at: Some(common_utils::date_time::now()), updated_by, incremental_authorization_allowed, ..Default::default() }, PaymentIntentUpdate::PaymentAttemptAndAttemptCountUpdate { active_attempt_id, attempt_count, updated_by, } => Self { active_attempt_id: Some(active_attempt_id), attempt_count: Some(attempt_count), updated_by, ..Default::default() }, PaymentIntentUpdate::StatusAndAttemptUpdate { status, active_attempt_id, attempt_count, updated_by, } => Self { status: Some(status), active_attempt_id: Some(active_attempt_id), attempt_count: Some(attempt_count), updated_by, ..Default::default() }, PaymentIntentUpdate::ApproveUpdate { merchant_decision, updated_by, } => Self { merchant_decision, updated_by, ..Default::default() }, PaymentIntentUpdate::RejectUpdate { status, merchant_decision, updated_by, } => Self { status: Some(status), merchant_decision, updated_by, ..Default::default() }, PaymentIntentUpdate::SurchargeApplicableUpdate { surcharge_applicable, updated_by, } => Self { surcharge_applicable: Some(surcharge_applicable), updated_by, ..Default::default() }, PaymentIntentUpdate::IncrementalAuthorizationAmountUpdate { amount } => Self { amount: Some(amount), ..Default::default() }, PaymentIntentUpdate::AuthorizationCountUpdate { authorization_count, } => Self { authorization_count: Some(authorization_count), ..Default::default() }, } } } pub enum PaymentIntentFetchConstraints { Single { payment_intent_id: String }, List(Box), } pub struct PaymentIntentListParams { pub offset: u32, pub starting_at: Option, pub ending_at: Option, pub connector: Option>, pub currency: Option>, pub status: Option>, pub payment_method: Option>, pub payment_method_type: Option>, pub authentication_type: Option>, pub profile_id: Option, pub customer_id: Option, pub starting_after_id: Option, pub ending_before_id: Option, pub limit: Option, } impl From for PaymentIntentFetchConstraints { fn from(value: api_models::payments::PaymentListConstraints) -> Self { Self::List(Box::new(PaymentIntentListParams { offset: 0, starting_at: value.created_gte.or(value.created_gt).or(value.created), ending_at: value.created_lte.or(value.created_lt).or(value.created), connector: None, currency: None, status: None, payment_method: None, payment_method_type: None, authentication_type: None, profile_id: None, customer_id: value.customer_id, starting_after_id: value.starting_after, ending_before_id: value.ending_before, limit: Some(std::cmp::min(value.limit, PAYMENTS_LIST_MAX_LIMIT_V1)), })) } } impl From for PaymentIntentFetchConstraints { fn from(value: api_models::payments::TimeRange) -> Self { Self::List(Box::new(PaymentIntentListParams { offset: 0, starting_at: Some(value.start_time), ending_at: value.end_time, connector: None, currency: None, status: None, payment_method: None, payment_method_type: None, authentication_type: None, profile_id: None, customer_id: None, starting_after_id: None, ending_before_id: None, limit: None, })) } } impl From for PaymentIntentFetchConstraints { fn from(value: api_models::payments::PaymentListFilterConstraints) -> Self { if let Some(payment_intent_id) = value.payment_id { Self::Single { payment_intent_id } } else { Self::List(Box::new(PaymentIntentListParams { offset: value.offset.unwrap_or_default(), starting_at: value.time_range.map(|t| t.start_time), ending_at: value.time_range.and_then(|t| t.end_time), connector: value.connector, currency: value.currency, status: value.status, payment_method: value.payment_method, payment_method_type: value.payment_method_type, authentication_type: value.authentication_type, profile_id: value.profile_id, customer_id: value.customer_id, starting_after_id: None, ending_before_id: None, limit: Some(std::cmp::min(value.limit, PAYMENTS_LIST_MAX_LIMIT_V2)), })) } } }