use std::{collections::HashMap, fmt::Debug}; use common_utils::{errors, id_type, types::MinorUnit}; pub use euclid::{ dssa::types::EuclidAnalysable, frontend::{ ast, dir::{DirKeyKind, EuclidDirFilter}, }, }; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; use crate::{ enums::{Currency, PaymentMethod}, payment_methods, }; #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct OpenRouterDecideGatewayRequest { pub payment_info: PaymentInfo, #[schema(value_type = String)] pub merchant_id: id_type::ProfileId, pub eligible_gateway_list: Option>, pub ranking_algorithm: Option, pub elimination_enabled: Option, } #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] pub struct DecideGatewayResponse { pub decided_gateway: Option, pub gateway_priority_map: Option, pub filter_wise_gateways: Option, pub priority_logic_tag: Option, pub routing_approach: Option, pub gateway_before_evaluation: Option, pub priority_logic_output: Option, pub reset_approach: Option, pub routing_dimension: Option, pub routing_dimension_level: Option, pub is_scheduled_outage: Option, pub is_dynamic_mga_enabled: Option, pub gateway_mga_id_map: Option, } #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct PriorityLogicOutput { pub is_enforcement: Option, pub gws: Option>, pub priority_logic_tag: Option, pub gateway_reference_ids: Option>, pub primary_logic: Option, pub fallback_logic: Option, } #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] pub struct PriorityLogicData { pub name: Option, pub status: Option, pub failure_reason: Option, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ToSchema)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum RankingAlgorithm { SrBasedRouting, PlBasedRouting, NtwBasedRouting, } #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct PaymentInfo { #[schema(value_type = String)] pub payment_id: id_type::PaymentId, pub amount: MinorUnit, pub currency: Currency, // customerId: Option, // preferredGateway: Option, pub payment_type: String, pub metadata: Option, // internalMetadata: Option, // isEmi: Option, // emiBank: Option, // emiTenure: Option, pub payment_method_type: String, pub payment_method: PaymentMethod, // paymentSource: Option, // authType: Option, // cardIssuerBankName: Option, pub card_isin: Option, // cardType: Option, // cardSwitchProvider: Option>, } #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] pub struct DecidedGateway { pub gateway_priority_map: Option>, pub debit_routing_output: Option, pub routing_approach: String, } #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] pub struct DebitRoutingOutput { pub co_badged_card_networks_info: CoBadgedCardNetworks, pub issuer_country: common_enums::CountryAlpha2, pub is_regulated: bool, pub regulated_name: Option, pub card_type: common_enums::CardType, } #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] pub struct CoBadgedCardNetworksInfo { pub network: common_enums::CardNetwork, pub saving_percentage: f64, } #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] pub struct CoBadgedCardNetworks(pub Vec); impl CoBadgedCardNetworks { pub fn get_card_networks(&self) -> Vec { self.0.iter().map(|info| info.network.clone()).collect() } pub fn get_signature_network(&self) -> Option { self.0 .iter() .find(|info| info.network.is_signature_network()) .map(|info| info.network.clone()) } } impl From<&DebitRoutingOutput> for payment_methods::CoBadgedCardData { fn from(output: &DebitRoutingOutput) -> Self { Self { co_badged_card_networks_info: output.co_badged_card_networks_info.clone(), issuer_country_code: output.issuer_country, is_regulated: output.is_regulated, regulated_name: output.regulated_name.clone(), } } } impl TryFrom<(payment_methods::CoBadgedCardData, String)> for DebitRoutingRequestData { type Error = error_stack::Report; fn try_from( (output, card_type): (payment_methods::CoBadgedCardData, String), ) -> Result { let parsed_card_type = card_type.parse::().map_err(|_| { error_stack::Report::new(errors::ParsingError::EnumParseFailure("CardType")) })?; Ok(Self { co_badged_card_networks_info: output.co_badged_card_networks_info.get_card_networks(), issuer_country: output.issuer_country_code, is_regulated: output.is_regulated, regulated_name: output.regulated_name, card_type: parsed_card_type, }) } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CoBadgedCardRequest { pub merchant_category_code: common_enums::DecisionEngineMerchantCategoryCode, pub acquirer_country: common_enums::CountryAlpha2, pub co_badged_card_data: Option, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct DebitRoutingRequestData { pub co_badged_card_networks_info: Vec, pub issuer_country: common_enums::CountryAlpha2, pub is_regulated: bool, pub regulated_name: Option, pub card_type: common_enums::CardType, } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct ErrorResponse { pub status: String, pub error_code: String, pub error_message: String, pub priority_logic_tag: Option, pub filter_wise_gateways: Option, pub error_info: UnifiedError, pub is_dynamic_mga_enabled: bool, } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct UnifiedError { pub code: String, pub user_message: String, pub developer_message: String, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ToSchema)] #[serde(rename_all = "camelCase")] pub struct UpdateScorePayload { #[schema(value_type = String)] pub merchant_id: id_type::ProfileId, pub gateway: String, pub status: TxnStatus, #[schema(value_type = String)] pub payment_id: id_type::PaymentId, } #[derive(Debug, Serialize, Deserialize, Clone, ToSchema)] pub struct UpdateScoreResponse { pub message: String, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum TxnStatus { Started, AuthenticationFailed, JuspayDeclined, PendingVbv, VBVSuccessful, Authorized, AuthorizationFailed, Charged, Authorizing, CODInitiated, Voided, VoidedPostCharge, VoidInitiated, Nop, CaptureInitiated, CaptureFailed, VoidFailed, AutoRefunded, PartialCharged, ToBeCharged, Pending, Failure, Declined, } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct DecisionEngineConfigSetupRequest { pub merchant_id: String, pub config: DecisionEngineConfigVariant, } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct GetDecisionEngineConfigRequest { pub merchant_id: String, pub algorithm: DecisionEngineDynamicAlgorithmType, } #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] pub enum DecisionEngineDynamicAlgorithmType { SuccessRate, Elimination, } #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(tag = "type", content = "data")] #[serde(rename_all = "camelCase")] pub enum DecisionEngineConfigVariant { SuccessRate(DecisionEngineSuccessRateData), Elimination(DecisionEngineEliminationData), } #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct DecisionEngineSuccessRateData { pub default_latency_threshold: Option, pub default_bucket_size: Option, pub default_hedging_percent: Option, pub default_lower_reset_factor: Option, pub default_upper_reset_factor: Option, pub default_gateway_extra_score: Option>, pub sub_level_input_config: Option>, } impl DecisionEngineSuccessRateData { pub fn update(&mut self, new_config: Self) { if let Some(threshold) = new_config.default_latency_threshold { self.default_latency_threshold = Some(threshold); } if let Some(bucket_size) = new_config.default_bucket_size { self.default_bucket_size = Some(bucket_size); } if let Some(hedging_percent) = new_config.default_hedging_percent { self.default_hedging_percent = Some(hedging_percent); } if let Some(lower_reset_factor) = new_config.default_lower_reset_factor { self.default_lower_reset_factor = Some(lower_reset_factor); } if let Some(upper_reset_factor) = new_config.default_upper_reset_factor { self.default_upper_reset_factor = Some(upper_reset_factor); } if let Some(gateway_extra_score) = new_config.default_gateway_extra_score { self.default_gateway_extra_score .as_mut() .map(|score| score.extend(gateway_extra_score)); } if let Some(sub_level_input_config) = new_config.sub_level_input_config { self.sub_level_input_config.as_mut().map(|config| { config.extend(sub_level_input_config); }); } } } #[derive(Debug, Serialize, Deserialize, Clone, ToSchema)] #[serde(rename_all = "camelCase")] pub struct DecisionEngineSRSubLevelInputConfig { pub payment_method_type: Option, pub payment_method: Option, pub latency_threshold: Option, pub bucket_size: Option, pub hedging_percent: Option, pub lower_reset_factor: Option, pub upper_reset_factor: Option, pub gateway_extra_score: Option>, } impl DecisionEngineSRSubLevelInputConfig { pub fn update(&mut self, new_config: Self) { if let Some(payment_method_type) = new_config.payment_method_type { self.payment_method_type = Some(payment_method_type); } if let Some(payment_method) = new_config.payment_method { self.payment_method = Some(payment_method); } if let Some(latency_threshold) = new_config.latency_threshold { self.latency_threshold = Some(latency_threshold); } if let Some(bucket_size) = new_config.bucket_size { self.bucket_size = Some(bucket_size); } if let Some(hedging_percent) = new_config.hedging_percent { self.hedging_percent = Some(hedging_percent); } if let Some(lower_reset_factor) = new_config.lower_reset_factor { self.lower_reset_factor = Some(lower_reset_factor); } if let Some(upper_reset_factor) = new_config.upper_reset_factor { self.upper_reset_factor = Some(upper_reset_factor); } if let Some(gateway_extra_score) = new_config.gateway_extra_score { self.gateway_extra_score .as_mut() .map(|score| score.extend(gateway_extra_score)); } } } #[derive(Debug, Serialize, Deserialize, Clone, ToSchema)] #[serde(rename_all = "camelCase")] pub struct DecisionEngineGatewayWiseExtraScore { pub gateway_name: String, pub gateway_sigma_factor: f64, } impl DecisionEngineGatewayWiseExtraScore { pub fn update(&mut self, new_config: Self) { self.gateway_name = new_config.gateway_name; self.gateway_sigma_factor = new_config.gateway_sigma_factor; } } #[derive(Debug, Serialize, Deserialize, Clone, ToSchema)] #[serde(rename_all = "camelCase")] pub struct DecisionEngineEliminationData { pub threshold: f64, } impl DecisionEngineEliminationData { pub fn update(&mut self, new_config: Self) { self.threshold = new_config.threshold; } } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct MerchantAccount { pub merchant_id: String, pub gateway_success_rate_based_decider_input: Option, } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct FetchRoutingConfig { pub merchant_id: String, pub algorithm: AlgorithmType, } #[derive(Debug, Serialize, Deserialize, Clone, Copy)] #[serde(rename_all = "camelCase")] pub enum AlgorithmType { SuccessRate, Elimination, DebitRouting, }