Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 94 additions & 9 deletions src/decider/gatewaydecider/gw_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1669,6 +1669,7 @@ pub async fn filterGatewaysForValidationType(

(ETGCI::ValidationType::Tpv, e_mgas)
};

if matches!(validation_type,ETGCI::ValidationType::TpvEmandate | ETGCI::ValidationType::Emandate) && is_otm_flow {
return Ok(returnGwListWithLog(
this,
Expand All @@ -1692,13 +1693,43 @@ pub async fn filterGatewaysForValidationType(

let amount = Utils::effective_amount_with_txn_amount(txn_detail.clone()).await;

let m_pf = Utils::get_pf_from_validation_type(&validation_type);

let (empty_csi_mgas , gpmf_source_mgas): (Vec<_>, Vec<_>,) = enabled_gateway_accounts.clone().into_iter().partition(|mga| mga.config_source_info.is_none());

// --- Second Partition on gpmfSourceMgas ---
let (gpmf_based_mgas, non_gpmf_inferred_mgas): (Vec<_>, Vec<_>) =
gpmf_source_mgas
.into_iter()
.partition(|mga| {
let config_info_opt = &mga.config_source_info;

let gpmf_flows_opt: Option<&Vec<PaymentFlow>> = config_info_opt
.as_ref()
.and_then(|info| info.gpmf_inferred_flows.as_ref());

let is_gpmf_flows_empty = gpmf_flows_opt.map_or(true, |flows| flows.is_empty());

let m_pf_is_present_in_gpmf_flows = m_pf
.as_ref()
.map_or(false, |pf_val| {
gpmf_flows_opt.map_or(false, |flows_vec_opt| { flows_vec_opt.contains(pf_val)})
});
is_gpmf_flows_empty || m_pf_is_present_in_gpmf_flows
});

let gci_based_mgas: Vec<MerchantGatewayAccount> = empty_csi_mgas
.into_iter()
.chain(non_gpmf_inferred_mgas.into_iter())
.collect();

// Filter gateways for payment method and validation type
let merchant_gateway_card_infos =
SETMCI::filter_gateways_for_payment_method_and_validation_type(
this.state(),
macc,
txn_card_info.clone(),
enabled_gateway_accounts.clone(),
gci_based_mgas.clone(),
validation_type,
transaction_id_to_text(txn_detail.txnId.clone()),
)
Expand All @@ -1708,9 +1739,9 @@ pub async fn filterGatewaysForValidationType(
let merchant_gateway_card_infos =
Utils::filter_gateway_card_info_for_max_register_amount(
txn_detail.clone(),
txn_card_info,
txn_card_info.clone(),
merchant_gateway_card_infos,
amount,
amount.clone(),
);

// Extract gateway card info IDs
Expand All @@ -1734,10 +1765,7 @@ pub async fn filterGatewaysForValidationType(

let new_st = catMaybes(&nst);

// Update gateway list and MGAs
setGwsAndMgas(
this,
enabled_gateway_accounts
let mgci_matched_final_mgas: Vec<MerchantGatewayAccount> = gci_based_mgas
.into_iter()
.filter(|mga| {
new_st.contains(&mga.gateway)
Expand All @@ -1747,8 +1775,65 @@ pub async fn filterGatewaysForValidationType(
.collect::<Vec<_>>()
.contains(&Some(mga.id.clone()))
})
.collect(),
);
.collect();

let mgpmf_matched_final_mgas = match (m_pf.as_ref(), gpmf_based_mgas.is_empty()) {
(Some(pf), false) => {
let maybe_jbc = find_bank_code(txn_card_info.paymentMethod).await;
match maybe_jbc {
None => vec![],
Some(jbc) => {
let gw_list: Vec<String> = gpmf_based_mgas
.iter()
.map(|mga| mga.gateway.clone())
.collect();

let all_gpmf_entries = GPMF::find_all_gpmf_by_country_code_gw_pf_id_pmt_jbcid_db(
crate::types::country::country_iso::CountryISO::IND,
gw_list,
pf.clone(),
txn_card_info.paymentMethodType.clone(),
jbc.id,
)
.await
.unwrap_or_default();

let mga_ids = gpmf_based_mgas
.iter()
.map(|mga| mga.id.merchantGwAccId)
.collect::<Vec<_>>();

let gpmf_ids: Vec<GatewayPaymentMethodFlowId> = all_gpmf_entries
.iter()
.map(|entry| to_gateway_payment_method_flow_id(entry.id.clone()))
.collect();

let mgpmf_entries =
MGPMF::get_all_mgpmf_by_mga_id_and_gpmf_ids(mga_ids, gpmf_ids).await;

let max_amount_filtered_entries = Utils::filter_mgpmf_for_max_register_amount(
pf.clone(),
&txn_card_info.paymentMethodType,
mgpmf_entries.clone(),
amount,
);

let mgpmf_mga_id_entries = max_amount_filtered_entries
.await.iter()
.map(|entry| entry.merchantGatewayAccountId)
.collect::<Vec<_>>();

gpmf_based_mgas
.into_iter()
.filter(|mga| mgpmf_mga_id_entries.contains(&mga.id.merchantGwAccId))
.collect()
}
}
}
_ => vec![],
};
let new_gws = [mgci_matched_final_mgas, mgpmf_matched_final_mgas].concat();
setGwsAndMgas(this, new_gws);
}
}
// Handle other transaction types
Expand Down
72 changes: 71 additions & 1 deletion src/decider/gatewaydecider/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::types::card::card_type::card_type_to_text;
use crate::types::merchant::id::{merchant_id_to_text, MerchantId};
use crate::types::merchant::merchant_gateway_account::MerchantGatewayAccount;
use crate::types::money::internal::Money;
use crate::types::payment_flow::{payment_flows_to_text, PaymentFlow};
use crate::types::payment_flow::{payment_flows_to_text, to_flow_level_id, FlowLevel, FlowLevelId, MicroPaymentFlowName, PaymentFlow};
use crate::types::user_eligibility_info::{
get_eligibility_info, identifier_name_to_text, IdentifierName,
};
Expand Down Expand Up @@ -85,6 +85,8 @@ use crate::types::isin_routes as ETIsinR;
// // use configs::env_vars as ENV;
use crate::types::gateway_card_info::ValidationType;
use crate::error::StorageError;
use crate::types::merchant_gateway_payment_method_flow::{ MerchantGatewayPaymentMethodFlow};
use crate::types::micro_payment_flow:: {find_mpf_by_flow_level_flow_level_ids_mpf_name, MicroPaymentFlowF};

pub fn either_decode_t<T: for<'de> Deserialize<'de>>(text: &str) -> Result<T, String> {
from_slice(text.as_bytes()).map_err(|e| e.to_string())
Expand Down Expand Up @@ -616,6 +618,10 @@ pub fn is_emandate_register_transaction(txn_detail: &ETTD::TxnDetail) -> bool {
txn_detail.txnObjectType == ETTD::TxnObjectType::EmandateRegister
}

fn is_pmt_eligible_for_emandate_amount_filter(pmt: &PaymentMethodType) -> bool {
matches!(pmt, PaymentMethodType::Card | PaymentMethodType::NB | PaymentMethodType::Aadhaar | PaymentMethodType::PAN)
}

pub async fn get_card_brand(decider_flow: &mut DeciderFlow<'_>) -> Option<String> {
let c_card_brand = decider_flow.writer.cardBrand.clone();
if let Some(cb) = c_card_brand {
Expand Down Expand Up @@ -2727,6 +2733,70 @@ pub async fn get_penality_factor_(
}
}

pub fn get_pf_from_validation_type(vt: &ValidationType) -> Option<PaymentFlow> {
match vt {
ValidationType::Tpv => Some(PaymentFlow::TPV),
ValidationType::TpvEmandate => Some(PaymentFlow::TPV_EMANDATE),
ValidationType::Emandate => Some(PaymentFlow::EMANDATE),
_ => None,
}
}

pub async fn filter_mgpmf_for_max_register_amount(
pf: PaymentFlow,
payment_method_type: &PaymentMethodType,
merchant_gateway_payment_method_flows: Vec<MerchantGatewayPaymentMethodFlow>,
txn_amount: Money,
) -> Vec<MerchantGatewayPaymentMethodFlow> {
if matches!(pf, PaymentFlow::EMANDATE | PaymentFlow::TPV_EMANDATE)
&& is_pmt_eligible_for_emandate_amount_filter(payment_method_type)
{
let flow_level_ids = extract_mgpmf_ids_as_flow_level_ids(&merchant_gateway_payment_method_flows);

let min_amount = Money::from_double(10000.0);

let mpfs: Vec<MicroPaymentFlowF> = find_mpf_by_flow_level_flow_level_ids_mpf_name(FlowLevel::MerchantGatewayPaymentMethodFlow, flow_level_ids, MicroPaymentFlowName::RegisterMaxAmount).await;

let filtered_ids: Vec<FlowLevelId> = mpfs
.iter()
.filter_map(|mpf| {
let val= from_str(&mpf.value).ok().unwrap_or(min_amount.clone());
if txn_amount <= val {
Some(mpf.flowLevelId.clone())
} else {
None
}
})
.collect();

merchant_gateway_payment_method_flows
.into_iter()
.filter_map(|mgpmf| {
match mgpmf.id.map(|id| to_flow_level_id(id.to_string())) {
Some(value) => if filtered_ids.contains(&value) {
Some(mgpmf)
} else {
None
}
_ => None
}


})
.collect()
} else {
merchant_gateway_payment_method_flows
}
}

fn extract_mgpmf_ids_as_flow_level_ids(
flows: &[MerchantGatewayPaymentMethodFlow],
) -> Vec<FlowLevelId> {
flows
.iter()
.filter_map(|flow| flow.id.map(|id| to_flow_level_id(id.to_string())))
.collect()
}

// fn push_to_stream(decided_gateway: OptionETG::Gateway, final_decider_approach: types::GatewayDeciderApproach, m_priority_logic_tag: Option, current_gateway_score_map: GatewayScoreMap) -> DeciderFlow<()> {
// if let Some(decided_gateway) = decided_gateway {
Expand Down
16 changes: 16 additions & 0 deletions src/storage/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ diesel::table! {
gateway_identifier -> Nullable<Text>,
gateway_type -> Nullable<Text>,
supported_txn_type -> Nullable<Text>,
config_source_info -> Nullable<Text>,
}
}

Expand Down Expand Up @@ -293,6 +294,20 @@ diesel::table! {
}
}

diesel::table! {
micro_payment_flow (id) {
id -> Text,
flow_level -> Text,
flow_level_id -> Text,
micro_payment_flow_name -> Text,
#[sql_name = "type"]
value_type -> Text,
value -> Text,
date_created -> Datetime,
last_updated -> Datetime,
}
}

diesel::table! {
merchant_iframe_preferences (id) {
id -> Bigint,
Expand Down Expand Up @@ -546,3 +561,4 @@ diesel::allow_tables_to_appear_in_same_query!(
txn_offer_detail,
user_eligibility_info,
);

14 changes: 14 additions & 0 deletions src/storage/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ pub struct MerchantGatewayAccount {
pub gateway_identifier: Option<String>,
pub gateway_type: Option<String>,
pub supported_txn_type: Option<String>,
pub config_source_info: Option<String>,
}

#[derive(Debug, Clone, Identifiable, Queryable)]
Expand Down Expand Up @@ -373,6 +374,19 @@ pub struct MerchantGatewayPaymentMethodFlow {
pub gateway_bank_code: Option<String>,
}

#[derive(Debug, Clone, Identifiable, Queryable)]
#[cfg_attr(feature = "mysql", diesel(table_name = schema::micro_payment_flow))]
#[cfg_attr(feature = "postgres", diesel(table_name = schema_pg::micro_payment_flow))]
pub struct MicroPaymentFlow {
pub id: String,
pub flow_level: String,
pub flow_level_id: String,
pub micro_payment_flow_name: String,
pub value_type: String,
pub value: String,
pub date_created: PrimitiveDateTime,
pub last_updated: PrimitiveDateTime,
}

#[derive(Debug, Clone, PartialEq, FromSqlRow, AsExpression, Serialize)]
#[cfg_attr(feature = "mysql", diesel(sql_type = Bit))]
Expand Down
1 change: 1 addition & 0 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ pub mod txn_offer;
pub mod txn_offer_detail;
pub mod txn_offer_info;
pub mod user_eligibility_info;
pub mod micro_payment_flow;
23 changes: 23 additions & 0 deletions src/types/merchant/merchant_gateway_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use crate::storage::schema_pg::merchant_gateway_account::dsl;
use diesel::associations::HasTable;
use diesel::*;
use std::fmt::Debug;
use crate::types::payment_flow::PaymentFlow;

// #[derive(Debug, PartialEq, Serialize, Deserialize)]
// pub struct EulerAccountDetails {
Expand Down Expand Up @@ -86,6 +87,25 @@ pub fn to_mga_reference_id(id: String) -> MgaReferenceId {
}
}


#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Serialize, Deserialize)]
enum FlowConfigSource { GPMF}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ConfigSourceInfo {
#[serde(rename = "flowConfigSource")]
pub flow_config_source: FlowConfigSource,
#[serde(rename = "gpmfInferredFlows")]
pub gpmf_inferred_flows: Option<Vec<PaymentFlow>>,
}

fn to_config_source_info(csi: String) -> Result<ConfigSourceInfo, ApiError> {
match serde_json::from_str::<ConfigSourceInfo>(&csi) {
Ok(res) => Ok(res),
Err(_) => Err(ApiError::ParsingError("Invalid ConfigSourceInfo value")),
}
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct MerchantGatewayAccount {
#[serde(rename = "id")]
Expand All @@ -112,6 +132,8 @@ pub struct MerchantGatewayAccount {
pub gatewayType: Option<String>,
#[serde(rename = "supportedTxnType")]
pub supportedTxnType: Option<String>,
#[serde(rename = "configSourceInfo")]
pub config_source_info: Option<ConfigSourceInfo>,
}

impl TryFrom<DBMerchantGatewayAccount> for MerchantGatewayAccount {
Expand All @@ -134,6 +156,7 @@ impl TryFrom<DBMerchantGatewayAccount> for MerchantGatewayAccount {
gatewayIdentifier: value.gateway_identifier,
gatewayType: value.gateway_type,
supportedTxnType: value.supported_txn_type,
config_source_info: value.config_source_info.map(|csi| to_config_source_info(csi)).transpose()?,
})
}
}
Expand Down
Loading
Loading