mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-27 11:24:45 +08:00
db: Added Reverse lookup table (#147)
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2600,6 +2600,7 @@ dependencies = [
|
|||||||
"common_utils",
|
"common_utils",
|
||||||
"error-stack",
|
"error-stack",
|
||||||
"fred",
|
"fred",
|
||||||
|
"futures",
|
||||||
"router_env",
|
"router_env",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
|||||||
@ -249,7 +249,7 @@ impl Default for PaymentMethod {
|
|||||||
pub enum PaymentIdType {
|
pub enum PaymentIdType {
|
||||||
PaymentIntentId(String),
|
PaymentIntentId(String),
|
||||||
ConnectorTransactionId(String),
|
ConnectorTransactionId(String),
|
||||||
PaymentTxnId(String),
|
PaymentAttemptId(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PaymentIdType {
|
impl Default for PaymentIdType {
|
||||||
|
|||||||
@ -25,7 +25,7 @@ async fn drainer_handler(
|
|||||||
stream_index: u8,
|
stream_index: u8,
|
||||||
max_read_count: u64,
|
max_read_count: u64,
|
||||||
) -> errors::DrainerResult<()> {
|
) -> errors::DrainerResult<()> {
|
||||||
let stream_name = utils::get_drainer_stream(store.clone(), stream_index);
|
let stream_name = utils::get_drainer_stream_name(store.clone(), stream_index);
|
||||||
let drainer_result = drainer(store.clone(), max_read_count, stream_name.as_str()).await;
|
let drainer_result = drainer(store.clone(), max_read_count, stream_name.as_str()).await;
|
||||||
|
|
||||||
if let Err(_e) = drainer_result {
|
if let Err(_e) = drainer_result {
|
||||||
@ -70,6 +70,9 @@ async fn drainer(
|
|||||||
kv::Insertable::PaymentAttempt(a) => {
|
kv::Insertable::PaymentAttempt(a) => {
|
||||||
macro_util::handle_resp!(a.insert(&conn).await, "ins", "pa")
|
macro_util::handle_resp!(a.insert(&conn).await, "ins", "pa")
|
||||||
}
|
}
|
||||||
|
kv::Insertable::Refund(a) => {
|
||||||
|
macro_util::handle_resp!(a.insert(&conn).await, "ins", "ref")
|
||||||
|
}
|
||||||
},
|
},
|
||||||
kv::DBOperation::Update { updatable } => match updatable {
|
kv::DBOperation::Update { updatable } => match updatable {
|
||||||
kv::Updateable::PaymentIntentUpdate(a) => {
|
kv::Updateable::PaymentIntentUpdate(a) => {
|
||||||
@ -78,6 +81,9 @@ async fn drainer(
|
|||||||
kv::Updateable::PaymentAttemptUpdate(a) => {
|
kv::Updateable::PaymentAttemptUpdate(a) => {
|
||||||
macro_util::handle_resp!(a.orig.update(&conn, a.update_data).await, "up", "pa")
|
macro_util::handle_resp!(a.orig.update(&conn, a.update_data).await, "up", "pa")
|
||||||
}
|
}
|
||||||
|
kv::Updateable::RefundUpdate(a) => {
|
||||||
|
macro_util::handle_resp!(a.orig.update(&conn, a.update_data).await, "up", "ref")
|
||||||
|
}
|
||||||
},
|
},
|
||||||
kv::DBOperation::Delete => todo!(),
|
kv::DBOperation::Delete => todo!(),
|
||||||
};
|
};
|
||||||
|
|||||||
@ -113,9 +113,9 @@ pub fn increment_stream_index(index: u8, total_streams: u8) -> u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_stream_key_flag(store: Arc<router::services::Store>, stream_index: u8) -> String {
|
pub(crate) fn get_stream_key_flag(store: Arc<router::services::Store>, stream_index: u8) -> String {
|
||||||
format!("{}_in_use", get_drainer_stream(store, stream_index))
|
format!("{}_in_use", get_drainer_stream_name(store, stream_index))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_drainer_stream(store: Arc<Store>, stream_index: u8) -> String {
|
pub(crate) fn get_drainer_stream_name(store: Arc<Store>, stream_index: u8) -> String {
|
||||||
store.drainer_stream(format!("shard_{}", stream_index).as_str())
|
store.get_drainer_stream_name(format!("shard_{}", stream_index).as_str())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ license = "Apache-2.0"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
error-stack = "0.2.4"
|
error-stack = "0.2.4"
|
||||||
fred = { version = "5.2.0", features = ["metrics", "partial-tracing"] }
|
fred = { version = "5.2.0", features = ["metrics", "partial-tracing"] }
|
||||||
|
futures = "0.3"
|
||||||
serde = { version = "1.0.149", features = ["derive"] }
|
serde = { version = "1.0.149", features = ["derive"] }
|
||||||
thiserror = "1.0.37"
|
thiserror = "1.0.37"
|
||||||
|
|
||||||
@ -18,4 +19,4 @@ common_utils = { version = "0.1.0", path = "../common_utils" }
|
|||||||
router_env = { version = "0.1.0", path = "../router_env", features = ["log_extra_implicit_fields", "log_custom_entries_to_extra"] }
|
router_env = { version = "0.1.0", path = "../router_env", features = ["log_extra_implicit_fields", "log_custom_entries_to_extra"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tokio = { version = "1.23.0", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1.23.0", features = ["macros", "rt-multi-thread"] }
|
||||||
|
|||||||
@ -10,7 +10,7 @@ use std::fmt::Debug;
|
|||||||
|
|
||||||
use common_utils::{
|
use common_utils::{
|
||||||
errors::CustomResult,
|
errors::CustomResult,
|
||||||
ext_traits::{ByteSliceExt, Encode},
|
ext_traits::{ByteSliceExt, Encode, StringExt},
|
||||||
};
|
};
|
||||||
use error_stack::{IntoReport, ResultExt};
|
use error_stack::{IntoReport, ResultExt};
|
||||||
use fred::{
|
use fred::{
|
||||||
@ -20,7 +20,8 @@ use fred::{
|
|||||||
RedisKey, RedisMap, RedisValue, SetOptions, XCap, XReadResponse,
|
RedisKey, RedisMap, RedisValue, SetOptions, XCap, XReadResponse,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use router_env::{tracing, tracing::instrument};
|
use futures::StreamExt;
|
||||||
|
use router_env::{logger, tracing, tracing::instrument};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors,
|
errors,
|
||||||
@ -245,6 +246,56 @@ impl super::RedisConnectionPool {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "DEBUG", skip(self))]
|
||||||
|
pub async fn hscan(
|
||||||
|
&self,
|
||||||
|
key: &str,
|
||||||
|
pattern: &str,
|
||||||
|
count: Option<u32>,
|
||||||
|
) -> CustomResult<Vec<String>, errors::RedisError> {
|
||||||
|
Ok(self
|
||||||
|
.pool
|
||||||
|
.hscan::<&str, &str>(key, pattern, count)
|
||||||
|
.filter_map(|value| async move {
|
||||||
|
match value {
|
||||||
|
Ok(mut v) => {
|
||||||
|
let v = v.take_results()?;
|
||||||
|
|
||||||
|
let v: Vec<String> =
|
||||||
|
v.iter().filter_map(|(_, val)| val.as_string()).collect();
|
||||||
|
Some(futures::stream::iter(v))
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
logger::error!(?err);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.await)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "DEBUG", skip(self))]
|
||||||
|
pub async fn hscan_and_deserialize<T>(
|
||||||
|
&self,
|
||||||
|
key: &str,
|
||||||
|
pattern: &str,
|
||||||
|
count: Option<u32>,
|
||||||
|
) -> CustomResult<Vec<T>, errors::RedisError>
|
||||||
|
where
|
||||||
|
T: serde::de::DeserializeOwned,
|
||||||
|
{
|
||||||
|
let redis_results = self.hscan(key, pattern, count).await?;
|
||||||
|
Ok(redis_results
|
||||||
|
.iter()
|
||||||
|
.filter_map(|v| {
|
||||||
|
let r: T = v.parse_struct(std::any::type_name::<T>()).ok()?;
|
||||||
|
Some(r)
|
||||||
|
})
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument(level = "DEBUG", skip(self))]
|
#[instrument(level = "DEBUG", skip(self))]
|
||||||
pub async fn get_hash_field<V>(
|
pub async fn get_hash_field<V>(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
@ -126,3 +126,18 @@ impl ConnectorErrorExt for error_stack::Report<errors::ConnectorError> {
|
|||||||
self.change_context(errors::ApiErrorResponse::PaymentAuthorizationFailed { data })
|
self.change_context(errors::ApiErrorResponse::PaymentAuthorizationFailed { data })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) trait RedisErrorExt {
|
||||||
|
fn to_redis_failed_response(self, key: &str) -> error_stack::Report<errors::StorageError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RedisErrorExt for error_stack::Report<errors::RedisError> {
|
||||||
|
fn to_redis_failed_response(self, key: &str) -> error_stack::Report<errors::StorageError> {
|
||||||
|
match self.current_context() {
|
||||||
|
errors::RedisError::NotFound => self.change_context(
|
||||||
|
errors::StorageError::ValueNotFound(format!("Data does not exist for key {key}",)),
|
||||||
|
),
|
||||||
|
_ => self.change_context(errors::StorageError::KVError),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -98,7 +98,7 @@ where
|
|||||||
.make_pm_data(
|
.make_pm_data(
|
||||||
state,
|
state,
|
||||||
payment_data.payment_attempt.payment_method,
|
payment_data.payment_attempt.payment_method,
|
||||||
&payment_data.payment_attempt.txn_id,
|
&payment_data.payment_attempt.attempt_id,
|
||||||
&payment_data.payment_attempt,
|
&payment_data.payment_attempt,
|
||||||
&payment_data.payment_method_data,
|
&payment_data.payment_method_data,
|
||||||
&payment_data.token,
|
&payment_data.token,
|
||||||
@ -594,7 +594,7 @@ pub async fn add_process_sync_task(
|
|||||||
force_sync: true,
|
force_sync: true,
|
||||||
merchant_id: Some(payment_attempt.merchant_id.clone()),
|
merchant_id: Some(payment_attempt.merchant_id.clone()),
|
||||||
|
|
||||||
resource_id: api::PaymentIdType::PaymentTxnId(payment_attempt.txn_id.clone()),
|
resource_id: api::PaymentIdType::PaymentAttemptId(payment_attempt.attempt_id.clone()),
|
||||||
param: None,
|
param: None,
|
||||||
connector: None,
|
connector: None,
|
||||||
};
|
};
|
||||||
@ -603,7 +603,7 @@ pub async fn add_process_sync_task(
|
|||||||
let process_tracker_id = pt_utils::get_process_tracker_id(
|
let process_tracker_id = pt_utils::get_process_tracker_id(
|
||||||
runner,
|
runner,
|
||||||
task,
|
task,
|
||||||
&payment_attempt.txn_id,
|
&payment_attempt.attempt_id,
|
||||||
&payment_attempt.merchant_id,
|
&payment_attempt.merchant_id,
|
||||||
);
|
);
|
||||||
let process_tracker_entry =
|
let process_tracker_entry =
|
||||||
|
|||||||
@ -323,7 +323,7 @@ pub fn create_startpay_url(
|
|||||||
server.base_url,
|
server.base_url,
|
||||||
payment_intent.payment_id,
|
payment_intent.payment_id,
|
||||||
payment_intent.merchant_id,
|
payment_intent.merchant_id,
|
||||||
payment_attempt.txn_id
|
payment_attempt.attempt_id
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -67,7 +67,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsCancelRequest>
|
|||||||
.find_connector_response_by_payment_id_merchant_id_txn_id(
|
.find_connector_response_by_payment_id_merchant_id_txn_id(
|
||||||
&payment_attempt.payment_id,
|
&payment_attempt.payment_id,
|
||||||
&payment_attempt.merchant_id,
|
&payment_attempt.merchant_id,
|
||||||
&payment_attempt.txn_id,
|
&payment_attempt.attempt_id,
|
||||||
storage_scheme,
|
storage_scheme,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@ -89,7 +89,7 @@ impl<F: Send + Clone> GetTracker<F, payments::PaymentData<F>, api::PaymentsCaptu
|
|||||||
.find_connector_response_by_payment_id_merchant_id_txn_id(
|
.find_connector_response_by_payment_id_merchant_id_txn_id(
|
||||||
&payment_attempt.payment_id,
|
&payment_attempt.payment_id,
|
||||||
&payment_attempt.merchant_id,
|
&payment_attempt.merchant_id,
|
||||||
&payment_attempt.txn_id,
|
&payment_attempt.attempt_id,
|
||||||
storage_scheme,
|
storage_scheme,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@ -97,7 +97,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
.find_connector_response_by_payment_id_merchant_id_txn_id(
|
.find_connector_response_by_payment_id_merchant_id_txn_id(
|
||||||
&payment_attempt.payment_id,
|
&payment_attempt.payment_id,
|
||||||
&payment_attempt.merchant_id,
|
&payment_attempt.merchant_id,
|
||||||
&payment_attempt.txn_id,
|
&payment_attempt.attempt_id,
|
||||||
storage_scheme,
|
storage_scheme,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@ -434,7 +434,7 @@ impl PaymentCreate {
|
|||||||
storage::PaymentAttemptNew {
|
storage::PaymentAttemptNew {
|
||||||
payment_id: payment_id.to_string(),
|
payment_id: payment_id.to_string(),
|
||||||
merchant_id: merchant_id.to_string(),
|
merchant_id: merchant_id.to_string(),
|
||||||
txn_id: Uuid::new_v4().to_string(),
|
attempt_id: Uuid::new_v4().to_string(),
|
||||||
status,
|
status,
|
||||||
amount: amount.into(),
|
amount: amount.into(),
|
||||||
currency,
|
currency,
|
||||||
@ -495,7 +495,7 @@ impl PaymentCreate {
|
|||||||
storage::ConnectorResponseNew {
|
storage::ConnectorResponseNew {
|
||||||
payment_id: payment_attempt.payment_id.clone(),
|
payment_id: payment_attempt.payment_id.clone(),
|
||||||
merchant_id: payment_attempt.merchant_id.clone(),
|
merchant_id: payment_attempt.merchant_id.clone(),
|
||||||
txn_id: payment_attempt.txn_id.clone(),
|
txn_id: payment_attempt.attempt_id.clone(),
|
||||||
created_at: payment_attempt.created_at,
|
created_at: payment_attempt.created_at,
|
||||||
modified_at: payment_attempt.modified_at,
|
modified_at: payment_attempt.modified_at,
|
||||||
connector_name: payment_attempt.connector.clone(),
|
connector_name: payment_attempt.connector.clone(),
|
||||||
|
|||||||
@ -285,7 +285,7 @@ impl PaymentMethodValidate {
|
|||||||
storage::PaymentAttemptNew {
|
storage::PaymentAttemptNew {
|
||||||
payment_id: payment_id.to_string(),
|
payment_id: payment_id.to_string(),
|
||||||
merchant_id: merchant_id.to_string(),
|
merchant_id: merchant_id.to_string(),
|
||||||
txn_id: Uuid::new_v4().to_string(),
|
attempt_id: Uuid::new_v4().to_string(),
|
||||||
status,
|
status,
|
||||||
// Amount & Currency will be zero in this case
|
// Amount & Currency will be zero in this case
|
||||||
amount: 0,
|
amount: 0,
|
||||||
|
|||||||
@ -106,7 +106,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsSessionRequest>
|
|||||||
.find_connector_response_by_payment_id_merchant_id_txn_id(
|
.find_connector_response_by_payment_id_merchant_id_txn_id(
|
||||||
&payment_intent.payment_id,
|
&payment_intent.payment_id,
|
||||||
&payment_intent.merchant_id,
|
&payment_intent.merchant_id,
|
||||||
&payment_attempt.txn_id,
|
&payment_attempt.attempt_id,
|
||||||
storage_scheme,
|
storage_scheme,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@ -103,7 +103,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsStartRequest> f
|
|||||||
.find_connector_response_by_payment_id_merchant_id_txn_id(
|
.find_connector_response_by_payment_id_merchant_id_txn_id(
|
||||||
&payment_intent.payment_id,
|
&payment_intent.payment_id,
|
||||||
&payment_intent.merchant_id,
|
&payment_intent.merchant_id,
|
||||||
&payment_attempt.txn_id,
|
&payment_attempt.attempt_id,
|
||||||
storage_scheme,
|
storage_scheme,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@ -215,8 +215,8 @@ async fn get_tracker_for_sync<
|
|||||||
api::PaymentIdType::ConnectorTransactionId(ref id) => {
|
api::PaymentIdType::ConnectorTransactionId(ref id) => {
|
||||||
db.find_payment_attempt_by_merchant_id_connector_txn_id(merchant_id, id, storage_scheme)
|
db.find_payment_attempt_by_merchant_id_connector_txn_id(merchant_id, id, storage_scheme)
|
||||||
}
|
}
|
||||||
api::PaymentIdType::PaymentTxnId(ref id) => {
|
api::PaymentIdType::PaymentAttemptId(ref id) => {
|
||||||
db.find_payment_attempt_by_merchant_id_txn_id(merchant_id, id, storage_scheme)
|
db.find_payment_attempt_by_merchant_id_attempt_id(merchant_id, id, storage_scheme)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.await
|
.await
|
||||||
@ -233,7 +233,7 @@ async fn get_tracker_for_sync<
|
|||||||
.find_connector_response_by_payment_id_merchant_id_txn_id(
|
.find_connector_response_by_payment_id_merchant_id_txn_id(
|
||||||
&payment_intent.payment_id,
|
&payment_intent.payment_id,
|
||||||
&payment_intent.merchant_id,
|
&payment_intent.merchant_id,
|
||||||
&payment_attempt.txn_id,
|
&payment_attempt.attempt_id,
|
||||||
storage_scheme,
|
storage_scheme,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@ -116,7 +116,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
.find_connector_response_by_payment_id_merchant_id_txn_id(
|
.find_connector_response_by_payment_id_merchant_id_txn_id(
|
||||||
&payment_intent.payment_id,
|
&payment_intent.payment_id,
|
||||||
&payment_intent.merchant_id,
|
&payment_intent.merchant_id,
|
||||||
&payment_attempt.txn_id,
|
&payment_attempt.attempt_id,
|
||||||
storage_scheme,
|
storage_scheme,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@ -490,6 +490,7 @@ fn mk_new_refund(
|
|||||||
refund_status: enums::RefundStatus::Pending,
|
refund_status: enums::RefundStatus::Pending,
|
||||||
metadata: request.metadata,
|
metadata: request.metadata,
|
||||||
description: request.reason,
|
description: request.reason,
|
||||||
|
attempt_id: payment_attempt.attempt_id.clone(),
|
||||||
..storage::RefundNew::default()
|
..storage::RefundNew::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,9 +51,11 @@ pub async fn construct_refund_router_data<'a, F>(
|
|||||||
.get_required_value("payment_method_type")?;
|
.get_required_value("payment_method_type")?;
|
||||||
let payment_method_data = match payment_method_data.cloned() {
|
let payment_method_data = match payment_method_data.cloned() {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => helpers::Vault::get_payment_method_data_from_locker(state, &payment_attempt.txn_id)
|
None => {
|
||||||
.await?
|
helpers::Vault::get_payment_method_data_from_locker(state, &payment_attempt.attempt_id)
|
||||||
.get_required_value("payment_method_data")?,
|
.await?
|
||||||
|
.get_required_value("payment_method_data")?
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let router_data = types::RouterData {
|
let router_data = types::RouterData {
|
||||||
|
|||||||
@ -14,6 +14,7 @@ pub mod payment_method;
|
|||||||
pub mod process_tracker;
|
pub mod process_tracker;
|
||||||
pub mod queue;
|
pub mod queue;
|
||||||
pub mod refund;
|
pub mod refund;
|
||||||
|
pub mod reverse_lookup;
|
||||||
pub mod temp_card;
|
pub mod temp_card;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@ -51,6 +52,7 @@ pub trait StorageInterface:
|
|||||||
+ queue::QueueInterface
|
+ queue::QueueInterface
|
||||||
+ ephemeral_key::EphemeralKeyInterface
|
+ ephemeral_key::EphemeralKeyInterface
|
||||||
+ connector_response::ConnectorResponseInterface
|
+ connector_response::ConnectorResponseInterface
|
||||||
|
+ reverse_lookup::ReverseLookupInterface
|
||||||
+ 'static
|
+ 'static
|
||||||
{
|
{
|
||||||
async fn close(&mut self) {}
|
async fn close(&mut self) {}
|
||||||
|
|||||||
@ -48,10 +48,10 @@ pub trait PaymentAttemptInterface {
|
|||||||
storage_scheme: enums::MerchantStorageScheme,
|
storage_scheme: enums::MerchantStorageScheme,
|
||||||
) -> CustomResult<types::PaymentAttempt, errors::StorageError>;
|
) -> CustomResult<types::PaymentAttempt, errors::StorageError>;
|
||||||
|
|
||||||
async fn find_payment_attempt_by_merchant_id_txn_id(
|
async fn find_payment_attempt_by_merchant_id_attempt_id(
|
||||||
&self,
|
&self,
|
||||||
merchant_id: &str,
|
merchant_id: &str,
|
||||||
txn_id: &str,
|
attempt_id: &str,
|
||||||
storage_scheme: enums::MerchantStorageScheme,
|
storage_scheme: enums::MerchantStorageScheme,
|
||||||
) -> CustomResult<types::PaymentAttempt, errors::StorageError>;
|
) -> CustomResult<types::PaymentAttempt, errors::StorageError>;
|
||||||
}
|
}
|
||||||
@ -164,15 +164,15 @@ mod storage {
|
|||||||
.into_report()
|
.into_report()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn find_payment_attempt_by_merchant_id_txn_id(
|
async fn find_payment_attempt_by_merchant_id_attempt_id(
|
||||||
&self,
|
&self,
|
||||||
merchant_id: &str,
|
merchant_id: &str,
|
||||||
txn_id: &str,
|
attempt_id: &str,
|
||||||
_storage_scheme: enums::MerchantStorageScheme,
|
_storage_scheme: enums::MerchantStorageScheme,
|
||||||
) -> CustomResult<PaymentAttempt, errors::StorageError> {
|
) -> CustomResult<PaymentAttempt, errors::StorageError> {
|
||||||
let conn = pg_connection(&self.master_pool).await;
|
let conn = pg_connection(&self.master_pool).await;
|
||||||
|
|
||||||
PaymentAttempt::find_by_merchant_id_transaction_id(&conn, merchant_id, txn_id)
|
PaymentAttempt::find_by_merchant_id_attempt_id(&conn, merchant_id, attempt_id)
|
||||||
.await
|
.await
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
.into_report()
|
.into_report()
|
||||||
@ -182,10 +182,10 @@ mod storage {
|
|||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl PaymentAttemptInterface for MockDb {
|
impl PaymentAttemptInterface for MockDb {
|
||||||
async fn find_payment_attempt_by_merchant_id_txn_id(
|
async fn find_payment_attempt_by_merchant_id_attempt_id(
|
||||||
&self,
|
&self,
|
||||||
_merchant_id: &str,
|
_merchant_id: &str,
|
||||||
_txn_id: &str,
|
_attempt_id: &str,
|
||||||
_storage_scheme: enums::MerchantStorageScheme,
|
_storage_scheme: enums::MerchantStorageScheme,
|
||||||
) -> CustomResult<types::PaymentAttempt, errors::StorageError> {
|
) -> CustomResult<types::PaymentAttempt, errors::StorageError> {
|
||||||
todo!()
|
todo!()
|
||||||
@ -214,7 +214,7 @@ impl PaymentAttemptInterface for MockDb {
|
|||||||
id,
|
id,
|
||||||
payment_id: payment_attempt.payment_id,
|
payment_id: payment_attempt.payment_id,
|
||||||
merchant_id: payment_attempt.merchant_id,
|
merchant_id: payment_attempt.merchant_id,
|
||||||
txn_id: payment_attempt.txn_id,
|
attempt_id: payment_attempt.attempt_id,
|
||||||
status: payment_attempt.status,
|
status: payment_attempt.status,
|
||||||
amount: payment_attempt.amount,
|
amount: payment_attempt.amount,
|
||||||
currency: payment_attempt.currency,
|
currency: payment_attempt.currency,
|
||||||
@ -312,9 +312,10 @@ mod storage {
|
|||||||
use super::PaymentAttemptInterface;
|
use super::PaymentAttemptInterface;
|
||||||
use crate::{
|
use crate::{
|
||||||
connection::pg_connection,
|
connection::pg_connection,
|
||||||
core::errors::{self, CustomResult},
|
core::errors::{self, utils::RedisErrorExt, CustomResult},
|
||||||
|
db::reverse_lookup::ReverseLookupInterface,
|
||||||
services::Store,
|
services::Store,
|
||||||
types::storage::{enums, kv, payment_attempt::*},
|
types::storage::{enums, kv, payment_attempt::*, ReverseLookupNew},
|
||||||
utils::storage_partitioning::KvStorePartition,
|
utils::storage_partitioning::KvStorePartition,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -338,7 +339,7 @@ mod storage {
|
|||||||
enums::MerchantStorageScheme::RedisKv => {
|
enums::MerchantStorageScheme::RedisKv => {
|
||||||
let key = format!(
|
let key = format!(
|
||||||
"{}_{}",
|
"{}_{}",
|
||||||
payment_attempt.payment_id, payment_attempt.merchant_id
|
payment_attempt.merchant_id, payment_attempt.payment_id
|
||||||
);
|
);
|
||||||
// TODO: need to add an application generated payment attempt id to distinguish between multiple attempts for the same payment id
|
// TODO: need to add an application generated payment attempt id to distinguish between multiple attempts for the same payment id
|
||||||
// Check for database presence as well Maybe use a read replica here ?
|
// Check for database presence as well Maybe use a read replica here ?
|
||||||
@ -346,7 +347,7 @@ mod storage {
|
|||||||
id: 0i32,
|
id: 0i32,
|
||||||
payment_id: payment_attempt.payment_id.clone(),
|
payment_id: payment_attempt.payment_id.clone(),
|
||||||
merchant_id: payment_attempt.merchant_id.clone(),
|
merchant_id: payment_attempt.merchant_id.clone(),
|
||||||
txn_id: payment_attempt.txn_id.clone(),
|
attempt_id: payment_attempt.attempt_id.clone(),
|
||||||
status: payment_attempt.status,
|
status: payment_attempt.status,
|
||||||
amount: payment_attempt.amount,
|
amount: payment_attempt.amount,
|
||||||
currency: payment_attempt.currency,
|
currency: payment_attempt.currency,
|
||||||
@ -376,9 +377,10 @@ mod storage {
|
|||||||
error_code: payment_attempt.error_code.clone(),
|
error_code: payment_attempt.error_code.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let field = format!("pa_{}", created_attempt.attempt_id);
|
||||||
match self
|
match self
|
||||||
.redis_conn
|
.redis_conn
|
||||||
.serialize_and_set_hash_field_if_not_exist(&key, "pa", &created_attempt)
|
.serialize_and_set_hash_field_if_not_exist(&key, &field, &created_attempt)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(HsetnxReply::KeyNotSet) => Err(errors::StorageError::DuplicateValue(
|
Ok(HsetnxReply::KeyNotSet) => Err(errors::StorageError::DuplicateValue(
|
||||||
@ -386,12 +388,29 @@ mod storage {
|
|||||||
))
|
))
|
||||||
.into_report(),
|
.into_report(),
|
||||||
Ok(HsetnxReply::KeySet) => {
|
Ok(HsetnxReply::KeySet) => {
|
||||||
|
let conn = pg_connection(&self.master_pool).await;
|
||||||
|
|
||||||
|
//Reverse lookup for attempt_id
|
||||||
|
ReverseLookupNew {
|
||||||
|
lookup_id: format!(
|
||||||
|
"{}_{}",
|
||||||
|
&created_attempt.merchant_id, &created_attempt.attempt_id,
|
||||||
|
),
|
||||||
|
pk_id: key,
|
||||||
|
sk_id: field,
|
||||||
|
source: "payment_attempt".to_string(),
|
||||||
|
}
|
||||||
|
.insert(&conn)
|
||||||
|
.await
|
||||||
|
.map_err(Into::<errors::StorageError>::into)
|
||||||
|
.into_report()?;
|
||||||
|
|
||||||
let redis_entry = kv::TypedSql {
|
let redis_entry = kv::TypedSql {
|
||||||
op: kv::DBOperation::Insert {
|
op: kv::DBOperation::Insert {
|
||||||
insertable: kv::Insertable::PaymentAttempt(payment_attempt),
|
insertable: kv::Insertable::PaymentAttempt(payment_attempt),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let stream_name = self.drainer_stream(&PaymentAttempt::shard_key(
|
let stream_name = self.get_drainer_stream_name(&PaymentAttempt::shard_key(
|
||||||
crate::utils::storage_partitioning::PartitionKey::MerchantIdPaymentId {
|
crate::utils::storage_partitioning::PartitionKey::MerchantIdPaymentId {
|
||||||
merchant_id: &created_attempt.merchant_id,
|
merchant_id: &created_attempt.merchant_id,
|
||||||
payment_id: &created_attempt.payment_id,
|
payment_id: &created_attempt.payment_id,
|
||||||
@ -432,20 +451,42 @@ mod storage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enums::MerchantStorageScheme::RedisKv => {
|
enums::MerchantStorageScheme::RedisKv => {
|
||||||
let key = format!("{}_{}", this.payment_id, this.merchant_id);
|
let key = format!("{}_{}", this.merchant_id, this.payment_id);
|
||||||
|
|
||||||
let updated_attempt = payment_attempt.clone().apply_changeset(this.clone());
|
let updated_attempt = payment_attempt.clone().apply_changeset(this.clone());
|
||||||
// Check for database presence as well Maybe use a read replica here ?
|
// Check for database presence as well Maybe use a read replica here ?
|
||||||
let redis_value = serde_json::to_string(&updated_attempt)
|
let redis_value = serde_json::to_string(&updated_attempt)
|
||||||
.into_report()
|
.into_report()
|
||||||
.change_context(errors::StorageError::KVError)?;
|
.change_context(errors::StorageError::KVError)?;
|
||||||
|
let field = format!("pa_{}", updated_attempt.attempt_id);
|
||||||
let updated_attempt = self
|
let updated_attempt = self
|
||||||
.redis_conn
|
.redis_conn
|
||||||
.set_hash_fields(&key, ("pa", &redis_value))
|
.set_hash_fields(&key, (&field, &redis_value))
|
||||||
.await
|
.await
|
||||||
.map(|_| updated_attempt)
|
.map(|_| updated_attempt)
|
||||||
.change_context(errors::StorageError::KVError)?;
|
.change_context(errors::StorageError::KVError)?;
|
||||||
|
|
||||||
|
let conn = pg_connection(&self.master_pool).await;
|
||||||
|
// Reverse lookup for connector_transaction_id
|
||||||
|
if let Some(ref connector_transaction_id) =
|
||||||
|
updated_attempt.connector_transaction_id
|
||||||
|
{
|
||||||
|
let field = format!("pa_{}", updated_attempt.attempt_id);
|
||||||
|
ReverseLookupNew {
|
||||||
|
lookup_id: format!(
|
||||||
|
"{}_{}",
|
||||||
|
&updated_attempt.merchant_id, connector_transaction_id
|
||||||
|
),
|
||||||
|
pk_id: key.clone(),
|
||||||
|
sk_id: field.clone(),
|
||||||
|
source: "payment_attempt".to_string(),
|
||||||
|
}
|
||||||
|
.insert(&conn)
|
||||||
|
.await
|
||||||
|
.map_err(Into::<errors::StorageError>::into)
|
||||||
|
.into_report()?;
|
||||||
|
}
|
||||||
|
|
||||||
let redis_entry = kv::TypedSql {
|
let redis_entry = kv::TypedSql {
|
||||||
op: kv::DBOperation::Update {
|
op: kv::DBOperation::Update {
|
||||||
updatable: kv::Updateable::PaymentAttemptUpdate(
|
updatable: kv::Updateable::PaymentAttemptUpdate(
|
||||||
@ -457,7 +498,7 @@ mod storage {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let stream_name = self.drainer_stream(&PaymentAttempt::shard_key(
|
let stream_name = self.get_drainer_stream_name(&PaymentAttempt::shard_key(
|
||||||
crate::utils::storage_partitioning::PartitionKey::MerchantIdPaymentId {
|
crate::utils::storage_partitioning::PartitionKey::MerchantIdPaymentId {
|
||||||
merchant_id: &updated_attempt.merchant_id,
|
merchant_id: &updated_attempt.merchant_id,
|
||||||
payment_id: &updated_attempt.payment_id,
|
payment_id: &updated_attempt.payment_id,
|
||||||
@ -495,21 +536,20 @@ mod storage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enums::MerchantStorageScheme::RedisKv => {
|
enums::MerchantStorageScheme::RedisKv => {
|
||||||
let key = format!("{}_{}", payment_id, merchant_id);
|
let key = format!("{}_{}", merchant_id, payment_id);
|
||||||
|
let lookup = self
|
||||||
|
.get_lookup_by_lookup_id(&key)
|
||||||
|
.await
|
||||||
|
.map_err(Into::<errors::StorageError>::into)
|
||||||
|
.into_report()?;
|
||||||
self.redis_conn
|
self.redis_conn
|
||||||
.get_hash_field_and_deserialize::<PaymentAttempt>(
|
.get_hash_field_and_deserialize::<PaymentAttempt>(
|
||||||
&key,
|
&key,
|
||||||
"pa",
|
&lookup.sk_id,
|
||||||
"PaymentAttempt",
|
"PaymentAttempt",
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|error| match error.current_context() {
|
.map_err(|error| error.to_redis_failed_response(&key))
|
||||||
errors::RedisError::NotFound => errors::StorageError::ValueNotFound(
|
|
||||||
format!("Payment Attempt does not exist for {}", key),
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
_ => error.change_context(errors::StorageError::KVError),
|
|
||||||
})
|
|
||||||
// Check for database presence as well Maybe use a read replica here ?
|
// Check for database presence as well Maybe use a read replica here ?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -518,28 +558,26 @@ mod storage {
|
|||||||
async fn find_payment_attempt_by_transaction_id_payment_id_merchant_id(
|
async fn find_payment_attempt_by_transaction_id_payment_id_merchant_id(
|
||||||
&self,
|
&self,
|
||||||
transaction_id: &str,
|
transaction_id: &str,
|
||||||
payment_id: &str,
|
_payment_id: &str,
|
||||||
merchant_id: &str,
|
merchant_id: &str,
|
||||||
storage_scheme: enums::MerchantStorageScheme,
|
_storage_scheme: enums::MerchantStorageScheme,
|
||||||
) -> CustomResult<PaymentAttempt, errors::StorageError> {
|
) -> CustomResult<PaymentAttempt, errors::StorageError> {
|
||||||
// We assume that PaymentAttempt <=> PaymentIntent is a one-to-one relation for now
|
// We assume that PaymentAttempt <=> PaymentIntent is a one-to-one relation for now
|
||||||
self.find_payment_attempt_by_payment_id_merchant_id(
|
let lookup_id = format!("{merchant_id}_{transaction_id}");
|
||||||
payment_id,
|
let lookup = self
|
||||||
merchant_id,
|
.get_lookup_by_lookup_id(&lookup_id)
|
||||||
storage_scheme,
|
.await
|
||||||
)
|
.map_err(Into::<errors::StorageError>::into)
|
||||||
.await
|
.into_report()?;
|
||||||
.and_then(|attempt| {
|
let key = &lookup.pk_id;
|
||||||
if attempt.connector_transaction_id.as_deref() == Some(transaction_id) {
|
self.redis_conn
|
||||||
Ok(attempt)
|
.get_hash_field_and_deserialize::<PaymentAttempt>(
|
||||||
} else {
|
key,
|
||||||
Err(errors::StorageError::ValueNotFound(format!(
|
&lookup.sk_id,
|
||||||
"Successful payment attempt does not exist for {}_{}",
|
"PaymentAttempt",
|
||||||
payment_id, merchant_id
|
)
|
||||||
)))
|
.await
|
||||||
.into_report()
|
.map_err(|error| error.to_redis_failed_response(key))
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn find_payment_attempt_last_successful_attempt_by_payment_id_merchant_id(
|
async fn find_payment_attempt_last_successful_attempt_by_payment_id_merchant_id(
|
||||||
@ -586,28 +624,57 @@ mod storage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enums::MerchantStorageScheme::RedisKv => {
|
enums::MerchantStorageScheme::RedisKv => {
|
||||||
Err(errors::StorageError::KVError).into_report()
|
let lookup_id = format!("{merchant_id}_{connector_txn_id}");
|
||||||
|
let lookup = self
|
||||||
|
.get_lookup_by_lookup_id(&lookup_id)
|
||||||
|
.await
|
||||||
|
.map_err(Into::<errors::StorageError>::into)
|
||||||
|
.into_report()?;
|
||||||
|
|
||||||
|
let key = &lookup.pk_id;
|
||||||
|
self.redis_conn
|
||||||
|
.get_hash_field_and_deserialize::<PaymentAttempt>(
|
||||||
|
key,
|
||||||
|
&lookup.sk_id,
|
||||||
|
"PaymentAttempt",
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|error| error.to_redis_failed_response(key))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn find_payment_attempt_by_merchant_id_txn_id(
|
async fn find_payment_attempt_by_merchant_id_attempt_id(
|
||||||
&self,
|
&self,
|
||||||
merchant_id: &str,
|
merchant_id: &str,
|
||||||
txn_id: &str,
|
attempt_id: &str,
|
||||||
storage_scheme: enums::MerchantStorageScheme,
|
storage_scheme: enums::MerchantStorageScheme,
|
||||||
) -> CustomResult<PaymentAttempt, errors::StorageError> {
|
) -> CustomResult<PaymentAttempt, errors::StorageError> {
|
||||||
match storage_scheme {
|
match storage_scheme {
|
||||||
enums::MerchantStorageScheme::PostgresOnly => {
|
enums::MerchantStorageScheme::PostgresOnly => {
|
||||||
let conn = pg_connection(&self.master_pool).await;
|
let conn = pg_connection(&self.master_pool).await;
|
||||||
PaymentAttempt::find_by_merchant_id_transaction_id(&conn, merchant_id, txn_id)
|
PaymentAttempt::find_by_merchant_id_attempt_id(&conn, merchant_id, attempt_id)
|
||||||
.await
|
.await
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
.into_report()
|
.into_report()
|
||||||
}
|
}
|
||||||
|
|
||||||
enums::MerchantStorageScheme::RedisKv => {
|
enums::MerchantStorageScheme::RedisKv => {
|
||||||
Err(errors::StorageError::KVError).into_report()
|
let lookup_id = format!("{merchant_id}_{attempt_id}");
|
||||||
|
let lookup = self
|
||||||
|
.get_lookup_by_lookup_id(&lookup_id)
|
||||||
|
.await
|
||||||
|
.map_err(Into::<errors::StorageError>::into)
|
||||||
|
.into_report()?;
|
||||||
|
let key = &lookup.pk_id;
|
||||||
|
self.redis_conn
|
||||||
|
.get_hash_field_and_deserialize::<PaymentAttempt>(
|
||||||
|
key,
|
||||||
|
&lookup.sk_id,
|
||||||
|
"PaymentAttempt",
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|error| error.to_redis_failed_response(key))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -69,7 +69,7 @@ mod storage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enums::MerchantStorageScheme::RedisKv => {
|
enums::MerchantStorageScheme::RedisKv => {
|
||||||
let key = format!("{}_{}", new.payment_id, new.merchant_id);
|
let key = format!("{}_{}", new.merchant_id, new.payment_id);
|
||||||
let created_intent = PaymentIntent {
|
let created_intent = PaymentIntent {
|
||||||
id: 0i32,
|
id: 0i32,
|
||||||
payment_id: new.payment_id.clone(),
|
payment_id: new.payment_id.clone(),
|
||||||
@ -110,7 +110,7 @@ mod storage {
|
|||||||
insertable: kv::Insertable::PaymentIntent(new),
|
insertable: kv::Insertable::PaymentIntent(new),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let stream_name = self.drainer_stream(&PaymentIntent::shard_key(
|
let stream_name = self.get_drainer_stream_name(&PaymentIntent::shard_key(
|
||||||
crate::utils::storage_partitioning::PartitionKey::MerchantIdPaymentId {
|
crate::utils::storage_partitioning::PartitionKey::MerchantIdPaymentId {
|
||||||
merchant_id: &created_intent.merchant_id,
|
merchant_id: &created_intent.merchant_id,
|
||||||
payment_id: &created_intent.payment_id,
|
payment_id: &created_intent.payment_id,
|
||||||
@ -151,7 +151,7 @@ mod storage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enums::MerchantStorageScheme::RedisKv => {
|
enums::MerchantStorageScheme::RedisKv => {
|
||||||
let key = format!("{}_{}", this.payment_id, this.merchant_id);
|
let key = format!("{}_{}", this.merchant_id, this.payment_id);
|
||||||
|
|
||||||
let updated_intent = payment_intent.clone().apply_changeset(this.clone());
|
let updated_intent = payment_intent.clone().apply_changeset(this.clone());
|
||||||
// Check for database presence as well Maybe use a read replica here ?
|
// Check for database presence as well Maybe use a read replica here ?
|
||||||
@ -176,7 +176,7 @@ mod storage {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let stream_name = self.drainer_stream(&PaymentIntent::shard_key(
|
let stream_name = self.get_drainer_stream_name(&PaymentIntent::shard_key(
|
||||||
crate::utils::storage_partitioning::PartitionKey::MerchantIdPaymentId {
|
crate::utils::storage_partitioning::PartitionKey::MerchantIdPaymentId {
|
||||||
merchant_id: &updated_intent.merchant_id,
|
merchant_id: &updated_intent.merchant_id,
|
||||||
payment_id: &updated_intent.payment_id,
|
payment_id: &updated_intent.payment_id,
|
||||||
@ -214,7 +214,7 @@ mod storage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enums::MerchantStorageScheme::RedisKv => {
|
enums::MerchantStorageScheme::RedisKv => {
|
||||||
let key = format!("{}_{}", payment_id, merchant_id);
|
let key = format!("{}_{}", merchant_id, payment_id);
|
||||||
self.redis_conn
|
self.redis_conn
|
||||||
.get_hash_field_and_deserialize::<PaymentIntent>(
|
.get_hash_field_and_deserialize::<PaymentIntent>(
|
||||||
&key,
|
&key,
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
use error_stack::{IntoReport, Report};
|
use error_stack::Report;
|
||||||
use storage_models::errors::DatabaseError;
|
use storage_models::errors::DatabaseError;
|
||||||
|
|
||||||
use super::MockDb;
|
use super::MockDb;
|
||||||
use crate::{
|
use crate::{
|
||||||
connection::pg_connection,
|
|
||||||
core::errors::{self, CustomResult, StorageError},
|
core::errors::{self, CustomResult, StorageError},
|
||||||
types::storage::{self, enums},
|
types::storage::{self as storage_types, enums},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
@ -15,14 +14,14 @@ pub trait RefundInterface {
|
|||||||
internal_reference_id: &str,
|
internal_reference_id: &str,
|
||||||
merchant_id: &str,
|
merchant_id: &str,
|
||||||
storage_scheme: enums::MerchantStorageScheme,
|
storage_scheme: enums::MerchantStorageScheme,
|
||||||
) -> CustomResult<storage::Refund, errors::StorageError>;
|
) -> CustomResult<storage_types::Refund, errors::StorageError>;
|
||||||
|
|
||||||
async fn find_refund_by_payment_id_merchant_id(
|
async fn find_refund_by_payment_id_merchant_id(
|
||||||
&self,
|
&self,
|
||||||
payment_id: &str,
|
payment_id: &str,
|
||||||
merchant_id: &str,
|
merchant_id: &str,
|
||||||
storage_scheme: enums::MerchantStorageScheme,
|
storage_scheme: enums::MerchantStorageScheme,
|
||||||
) -> CustomResult<Vec<storage::Refund>, errors::StorageError>;
|
) -> CustomResult<Vec<storage_types::Refund>, errors::StorageError>;
|
||||||
|
|
||||||
// async fn find_refund_by_payment_id_merchant_id_refund_id(
|
// async fn find_refund_by_payment_id_merchant_id_refund_id(
|
||||||
// &self,
|
// &self,
|
||||||
@ -36,117 +35,513 @@ pub trait RefundInterface {
|
|||||||
merchant_id: &str,
|
merchant_id: &str,
|
||||||
refund_id: &str,
|
refund_id: &str,
|
||||||
storage_scheme: enums::MerchantStorageScheme,
|
storage_scheme: enums::MerchantStorageScheme,
|
||||||
) -> CustomResult<storage::Refund, errors::StorageError>;
|
) -> CustomResult<storage_types::Refund, errors::StorageError>;
|
||||||
|
|
||||||
async fn update_refund(
|
async fn update_refund(
|
||||||
&self,
|
&self,
|
||||||
this: storage::Refund,
|
this: storage_types::Refund,
|
||||||
refund: storage::RefundUpdate,
|
refund: storage_types::RefundUpdate,
|
||||||
storage_scheme: enums::MerchantStorageScheme,
|
storage_scheme: enums::MerchantStorageScheme,
|
||||||
) -> CustomResult<storage::Refund, errors::StorageError>;
|
) -> CustomResult<storage_types::Refund, errors::StorageError>;
|
||||||
|
|
||||||
async fn find_refund_by_merchant_id_transaction_id(
|
async fn find_refund_by_merchant_id_transaction_id(
|
||||||
&self,
|
&self,
|
||||||
merchant_id: &str,
|
merchant_id: &str,
|
||||||
txn_id: &str,
|
txn_id: &str,
|
||||||
storage_scheme: enums::MerchantStorageScheme,
|
storage_scheme: enums::MerchantStorageScheme,
|
||||||
) -> CustomResult<Vec<storage::Refund>, errors::StorageError>;
|
) -> CustomResult<Vec<storage_types::Refund>, errors::StorageError>;
|
||||||
|
|
||||||
async fn insert_refund(
|
async fn insert_refund(
|
||||||
&self,
|
&self,
|
||||||
new: storage::RefundNew,
|
new: storage_types::RefundNew,
|
||||||
storage_scheme: enums::MerchantStorageScheme,
|
storage_scheme: enums::MerchantStorageScheme,
|
||||||
) -> CustomResult<storage::Refund, errors::StorageError>;
|
) -> CustomResult<storage_types::Refund, errors::StorageError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[cfg(not(feature = "kv_store"))]
|
||||||
impl RefundInterface for super::Store {
|
mod storage {
|
||||||
async fn find_refund_by_internal_reference_id_merchant_id(
|
use error_stack::IntoReport;
|
||||||
&self,
|
|
||||||
internal_reference_id: &str,
|
|
||||||
merchant_id: &str,
|
|
||||||
_storage_scheme: enums::MerchantStorageScheme,
|
|
||||||
) -> CustomResult<storage::Refund, errors::StorageError> {
|
|
||||||
let conn = pg_connection(&self.master_pool).await;
|
|
||||||
storage::Refund::find_by_internal_reference_id_merchant_id(
|
|
||||||
&conn,
|
|
||||||
internal_reference_id,
|
|
||||||
merchant_id,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.map_err(Into::into)
|
|
||||||
.into_report()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn insert_refund(
|
use super::RefundInterface;
|
||||||
&self,
|
use crate::{
|
||||||
new: storage::RefundNew,
|
connection::pg_connection,
|
||||||
_storage_scheme: enums::MerchantStorageScheme,
|
core::errors::{self, CustomResult},
|
||||||
) -> CustomResult<storage::Refund, errors::StorageError> {
|
services::Store,
|
||||||
let conn = pg_connection(&self.master_pool).await;
|
types::storage::{self as storage_types, enums},
|
||||||
new.insert(&conn).await.map_err(Into::into).into_report()
|
};
|
||||||
}
|
|
||||||
async fn find_refund_by_merchant_id_transaction_id(
|
#[async_trait::async_trait]
|
||||||
&self,
|
impl RefundInterface for Store {
|
||||||
merchant_id: &str,
|
async fn find_refund_by_internal_reference_id_merchant_id(
|
||||||
txn_id: &str,
|
&self,
|
||||||
_storage_scheme: enums::MerchantStorageScheme,
|
internal_reference_id: &str,
|
||||||
) -> CustomResult<Vec<storage::Refund>, errors::StorageError> {
|
merchant_id: &str,
|
||||||
let conn = pg_connection(&self.master_pool).await;
|
_storage_scheme: enums::MerchantStorageScheme,
|
||||||
storage::Refund::find_by_merchant_id_transaction_id(&conn, merchant_id, txn_id)
|
) -> CustomResult<storage_types::Refund, errors::StorageError> {
|
||||||
|
let conn = pg_connection(&self.master_pool).await;
|
||||||
|
storage_types::Refund::find_by_internal_reference_id_merchant_id(
|
||||||
|
&conn,
|
||||||
|
internal_reference_id,
|
||||||
|
merchant_id,
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
.into_report()
|
.into_report()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn insert_refund(
|
||||||
|
&self,
|
||||||
|
new: storage_types::RefundNew,
|
||||||
|
_storage_scheme: enums::MerchantStorageScheme,
|
||||||
|
) -> CustomResult<storage_types::Refund, errors::StorageError> {
|
||||||
|
let conn = pg_connection(&self.master_pool).await;
|
||||||
|
new.insert(&conn).await.map_err(Into::into).into_report()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn find_refund_by_merchant_id_transaction_id(
|
||||||
|
&self,
|
||||||
|
merchant_id: &str,
|
||||||
|
txn_id: &str,
|
||||||
|
_storage_scheme: enums::MerchantStorageScheme,
|
||||||
|
) -> CustomResult<Vec<storage_types::Refund>, errors::StorageError> {
|
||||||
|
let conn = pg_connection(&self.master_pool).await;
|
||||||
|
storage_types::Refund::find_by_merchant_id_transaction_id(&conn, merchant_id, txn_id)
|
||||||
|
.await
|
||||||
|
.map_err(Into::into)
|
||||||
|
.into_report()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn update_refund(
|
||||||
|
&self,
|
||||||
|
this: storage_types::Refund,
|
||||||
|
refund: storage_types::RefundUpdate,
|
||||||
|
_storage_scheme: enums::MerchantStorageScheme,
|
||||||
|
) -> CustomResult<storage_types::Refund, errors::StorageError> {
|
||||||
|
let conn = pg_connection(&self.master_pool).await;
|
||||||
|
this.update(&conn, refund)
|
||||||
|
.await
|
||||||
|
.map_err(Into::into)
|
||||||
|
.into_report()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn find_refund_by_merchant_id_refund_id(
|
||||||
|
&self,
|
||||||
|
merchant_id: &str,
|
||||||
|
refund_id: &str,
|
||||||
|
_storage_scheme: enums::MerchantStorageScheme,
|
||||||
|
) -> CustomResult<storage_types::Refund, errors::StorageError> {
|
||||||
|
let conn = pg_connection(&self.master_pool).await;
|
||||||
|
storage_types::Refund::find_by_merchant_id_refund_id(&conn, merchant_id, refund_id)
|
||||||
|
.await
|
||||||
|
.map_err(Into::into)
|
||||||
|
.into_report()
|
||||||
|
}
|
||||||
|
|
||||||
|
// async fn find_refund_by_payment_id_merchant_id_refund_id(
|
||||||
|
// &self,
|
||||||
|
// payment_id: &str,
|
||||||
|
// merchant_id: &str,
|
||||||
|
// refund_id: &str,
|
||||||
|
// ) -> CustomResult<Refund, errors::StorageError> {
|
||||||
|
// let conn = pg_connection(&self.master_pool).await;
|
||||||
|
// Refund::find_by_payment_id_merchant_id_refund_id(&conn, payment_id, merchant_id, refund_id)
|
||||||
|
// .await
|
||||||
|
// }
|
||||||
|
|
||||||
|
async fn find_refund_by_payment_id_merchant_id(
|
||||||
|
&self,
|
||||||
|
payment_id: &str,
|
||||||
|
merchant_id: &str,
|
||||||
|
_storage_scheme: enums::MerchantStorageScheme,
|
||||||
|
) -> CustomResult<Vec<storage_types::Refund>, errors::StorageError> {
|
||||||
|
let conn = pg_connection(&self.master_pool).await;
|
||||||
|
storage_types::Refund::find_by_payment_id_merchant_id(&conn, payment_id, merchant_id)
|
||||||
|
.await
|
||||||
|
.map_err(Into::into)
|
||||||
|
.into_report()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn update_refund(
|
#[cfg(feature = "kv_store")]
|
||||||
&self,
|
mod storage {
|
||||||
this: storage::Refund,
|
use common_utils::date_time;
|
||||||
refund: storage::RefundUpdate,
|
use error_stack::{IntoReport, ResultExt};
|
||||||
_storage_scheme: enums::MerchantStorageScheme,
|
use redis_interface::{HsetnxReply, RedisEntryId};
|
||||||
) -> CustomResult<storage::Refund, errors::StorageError> {
|
|
||||||
let conn = pg_connection(&self.master_pool).await;
|
|
||||||
this.update(&conn, refund)
|
|
||||||
.await
|
|
||||||
.map_err(Into::into)
|
|
||||||
.into_report()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn find_refund_by_merchant_id_refund_id(
|
use super::RefundInterface;
|
||||||
&self,
|
use crate::{
|
||||||
merchant_id: &str,
|
connection::pg_connection,
|
||||||
refund_id: &str,
|
core::errors::{self, utils::RedisErrorExt, CustomResult},
|
||||||
_storage_scheme: enums::MerchantStorageScheme,
|
db::reverse_lookup::ReverseLookupInterface,
|
||||||
) -> CustomResult<storage::Refund, errors::StorageError> {
|
logger,
|
||||||
let conn = pg_connection(&self.master_pool).await;
|
services::Store,
|
||||||
storage::Refund::find_by_merchant_id_refund_id(&conn, merchant_id, refund_id)
|
types::storage::{self as storage_types, enums, kv},
|
||||||
.await
|
utils::{
|
||||||
.map_err(Into::into)
|
self, db_utils,
|
||||||
.into_report()
|
storage_partitioning::{KvStorePartition, PartitionKey},
|
||||||
}
|
},
|
||||||
|
};
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl RefundInterface for Store {
|
||||||
|
async fn find_refund_by_internal_reference_id_merchant_id(
|
||||||
|
&self,
|
||||||
|
internal_reference_id: &str,
|
||||||
|
merchant_id: &str,
|
||||||
|
storage_scheme: enums::MerchantStorageScheme,
|
||||||
|
) -> CustomResult<storage_types::Refund, errors::StorageError> {
|
||||||
|
match storage_scheme {
|
||||||
|
enums::MerchantStorageScheme::PostgresOnly => {
|
||||||
|
let conn = pg_connection(&self.master_pool).await;
|
||||||
|
storage_types::Refund::find_by_internal_reference_id_merchant_id(
|
||||||
|
&conn,
|
||||||
|
internal_reference_id,
|
||||||
|
merchant_id,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(Into::into)
|
||||||
|
.into_report()
|
||||||
|
}
|
||||||
|
enums::MerchantStorageScheme::RedisKv => {
|
||||||
|
let lookup_id = format!("{}_{}", merchant_id, internal_reference_id);
|
||||||
|
let lookup = self
|
||||||
|
.get_lookup_by_lookup_id(&lookup_id)
|
||||||
|
.await
|
||||||
|
.map_err(Into::<errors::StorageError>::into)
|
||||||
|
.into_report()?;
|
||||||
|
|
||||||
// async fn find_refund_by_payment_id_merchant_id_refund_id(
|
let key = &lookup.pk_id;
|
||||||
// &self,
|
self.redis_conn
|
||||||
// payment_id: &str,
|
.get_hash_field_and_deserialize::<storage_types::Refund>(
|
||||||
// merchant_id: &str,
|
key,
|
||||||
// refund_id: &str,
|
&lookup.sk_id,
|
||||||
// ) -> CustomResult<Refund, errors::StorageError> {
|
"Refund",
|
||||||
// let conn = pg_connection(&self.master_pool).await;
|
)
|
||||||
// Refund::find_by_payment_id_merchant_id_refund_id(&conn, payment_id, merchant_id, refund_id)
|
.await
|
||||||
// .await
|
.map_err(|error| error.to_redis_failed_response(key))
|
||||||
// }
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn find_refund_by_payment_id_merchant_id(
|
async fn insert_refund(
|
||||||
&self,
|
&self,
|
||||||
payment_id: &str,
|
new: storage_types::RefundNew,
|
||||||
merchant_id: &str,
|
storage_scheme: enums::MerchantStorageScheme,
|
||||||
_storage_scheme: enums::MerchantStorageScheme,
|
) -> CustomResult<storage_types::Refund, errors::StorageError> {
|
||||||
) -> CustomResult<Vec<storage::Refund>, errors::StorageError> {
|
match storage_scheme {
|
||||||
let conn = pg_connection(&self.master_pool).await;
|
enums::MerchantStorageScheme::PostgresOnly => {
|
||||||
storage::Refund::find_by_payment_id_merchant_id(&conn, payment_id, merchant_id)
|
let conn = pg_connection(&self.master_pool).await;
|
||||||
.await
|
new.insert(&conn).await.map_err(Into::into).into_report()
|
||||||
.map_err(Into::into)
|
}
|
||||||
.into_report()
|
enums::MerchantStorageScheme::RedisKv => {
|
||||||
|
let key = format!("{}_{}", new.merchant_id, new.payment_id);
|
||||||
|
// TODO: need to add an application generated payment attempt id to distinguish between multiple attempts for the same payment id
|
||||||
|
// Check for database presence as well Maybe use a read replica here ?
|
||||||
|
let created_refund = storage_types::Refund {
|
||||||
|
id: 0i32,
|
||||||
|
refund_id: new.refund_id.clone(),
|
||||||
|
merchant_id: new.merchant_id.clone(),
|
||||||
|
attempt_id: new.attempt_id.clone(),
|
||||||
|
internal_reference_id: new.internal_reference_id.clone(),
|
||||||
|
payment_id: new.payment_id.clone(),
|
||||||
|
transaction_id: new.transaction_id.clone(),
|
||||||
|
connector: new.connector.clone(),
|
||||||
|
pg_refund_id: new.pg_refund_id.clone(),
|
||||||
|
external_reference_id: new.external_reference_id.clone(),
|
||||||
|
refund_type: new.refund_type,
|
||||||
|
total_amount: new.total_amount,
|
||||||
|
currency: new.currency,
|
||||||
|
refund_amount: new.refund_amount,
|
||||||
|
refund_status: new.refund_status,
|
||||||
|
sent_to_gateway: new.sent_to_gateway,
|
||||||
|
refund_error_message: new.refund_error_message.clone(),
|
||||||
|
metadata: new.metadata.clone(),
|
||||||
|
refund_arn: new.refund_arn.clone(),
|
||||||
|
created_at: new.created_at.unwrap_or_else(date_time::now),
|
||||||
|
updated_at: new.created_at.unwrap_or_else(date_time::now),
|
||||||
|
description: new.description.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let field = format!(
|
||||||
|
"pa_{}_ref_{}",
|
||||||
|
&created_refund.attempt_id, &created_refund.refund_id
|
||||||
|
);
|
||||||
|
match self
|
||||||
|
.redis_conn
|
||||||
|
.serialize_and_set_hash_field_if_not_exist(&key, &field, &created_refund)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(HsetnxReply::KeyNotSet) => {
|
||||||
|
Err(errors::StorageError::DuplicateValue(format!(
|
||||||
|
"Refund already exists refund_id: {}",
|
||||||
|
&created_refund.refund_id
|
||||||
|
)))
|
||||||
|
.into_report()
|
||||||
|
}
|
||||||
|
Ok(HsetnxReply::KeySet) => {
|
||||||
|
let conn = pg_connection(&self.master_pool).await;
|
||||||
|
|
||||||
|
let reverse_lookups = vec![
|
||||||
|
storage_types::ReverseLookupNew {
|
||||||
|
sk_id: field.clone(),
|
||||||
|
lookup_id: format!(
|
||||||
|
"{}_{}",
|
||||||
|
created_refund.merchant_id, created_refund.refund_id
|
||||||
|
),
|
||||||
|
pk_id: key.clone(),
|
||||||
|
source: "refund".to_string(),
|
||||||
|
},
|
||||||
|
storage_types::ReverseLookupNew {
|
||||||
|
sk_id: field.clone(),
|
||||||
|
lookup_id: format!(
|
||||||
|
"{}_{}",
|
||||||
|
created_refund.merchant_id, created_refund.transaction_id
|
||||||
|
),
|
||||||
|
pk_id: key.clone(),
|
||||||
|
source: "refund".to_string(),
|
||||||
|
},
|
||||||
|
storage_types::ReverseLookupNew {
|
||||||
|
sk_id: field.clone(),
|
||||||
|
lookup_id: format!(
|
||||||
|
"{}_{}",
|
||||||
|
created_refund.merchant_id,
|
||||||
|
created_refund.internal_reference_id
|
||||||
|
),
|
||||||
|
pk_id: key,
|
||||||
|
source: "refund".to_string(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
storage_types::ReverseLookupNew::batch_insert(reverse_lookups, &conn)
|
||||||
|
.await
|
||||||
|
.change_context(errors::StorageError::KVError)?;
|
||||||
|
|
||||||
|
let redis_entry = kv::TypedSql {
|
||||||
|
op: kv::DBOperation::Insert {
|
||||||
|
insertable: kv::Insertable::Refund(new),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let stream_name =
|
||||||
|
self.get_drainer_stream_name(&storage_types::Refund::shard_key(
|
||||||
|
PartitionKey::MerchantIdPaymentId {
|
||||||
|
merchant_id: &created_refund.merchant_id,
|
||||||
|
payment_id: &created_refund.payment_id,
|
||||||
|
},
|
||||||
|
self.config.drainer_num_partitions,
|
||||||
|
));
|
||||||
|
self.redis_conn
|
||||||
|
.stream_append_entry(
|
||||||
|
&stream_name,
|
||||||
|
&RedisEntryId::AutoGeneratedID,
|
||||||
|
redis_entry
|
||||||
|
.to_field_value_pairs()
|
||||||
|
.change_context(errors::StorageError::KVError)?,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.change_context(errors::StorageError::KVError)?;
|
||||||
|
Ok(created_refund)
|
||||||
|
}
|
||||||
|
Err(er) => Err(er).change_context(errors::StorageError::KVError),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn find_refund_by_merchant_id_transaction_id(
|
||||||
|
&self,
|
||||||
|
merchant_id: &str,
|
||||||
|
txn_id: &str,
|
||||||
|
storage_scheme: enums::MerchantStorageScheme,
|
||||||
|
) -> CustomResult<Vec<storage_types::Refund>, errors::StorageError> {
|
||||||
|
match storage_scheme {
|
||||||
|
enums::MerchantStorageScheme::PostgresOnly => {
|
||||||
|
let conn = pg_connection(&self.master_pool).await;
|
||||||
|
storage_types::Refund::find_by_merchant_id_transaction_id(
|
||||||
|
&conn,
|
||||||
|
merchant_id,
|
||||||
|
txn_id,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(Into::into)
|
||||||
|
.into_report()
|
||||||
|
}
|
||||||
|
enums::MerchantStorageScheme::RedisKv => {
|
||||||
|
let lookup_id = format!("{merchant_id}_{txn_id}");
|
||||||
|
let lookup = match self.get_lookup_by_lookup_id(&lookup_id).await {
|
||||||
|
Ok(l) => l,
|
||||||
|
Err(err) => {
|
||||||
|
logger::error!(?err);
|
||||||
|
return Ok(vec![]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let key = &lookup.pk_id;
|
||||||
|
|
||||||
|
let pattern = db_utils::generate_hscan_pattern_for_refund(&lookup.sk_id);
|
||||||
|
|
||||||
|
self.redis_conn
|
||||||
|
.hscan_and_deserialize(key, &pattern, None)
|
||||||
|
.await
|
||||||
|
.change_context(errors::StorageError::KVError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn update_refund(
|
||||||
|
&self,
|
||||||
|
this: storage_types::Refund,
|
||||||
|
refund: storage_types::RefundUpdate,
|
||||||
|
storage_scheme: enums::MerchantStorageScheme,
|
||||||
|
) -> CustomResult<storage_types::Refund, errors::StorageError> {
|
||||||
|
match storage_scheme {
|
||||||
|
enums::MerchantStorageScheme::PostgresOnly => {
|
||||||
|
let conn = pg_connection(&self.master_pool).await;
|
||||||
|
this.update(&conn, refund)
|
||||||
|
.await
|
||||||
|
.map_err(Into::into)
|
||||||
|
.into_report()
|
||||||
|
}
|
||||||
|
enums::MerchantStorageScheme::RedisKv => {
|
||||||
|
let key = format!("{}_{}", this.merchant_id, this.payment_id);
|
||||||
|
|
||||||
|
let updated_refund = refund.clone().apply_changeset(this.clone());
|
||||||
|
// Check for database presence as well Maybe use a read replica here ?
|
||||||
|
// TODO: Add a proper error for serialization failure
|
||||||
|
|
||||||
|
let lookup = self
|
||||||
|
.get_lookup_by_lookup_id(&key)
|
||||||
|
.await
|
||||||
|
.map_err(Into::<errors::StorageError>::into)
|
||||||
|
.into_report()?;
|
||||||
|
|
||||||
|
let field = &lookup.sk_id;
|
||||||
|
|
||||||
|
let redis_value =
|
||||||
|
utils::Encode::<storage_types::Refund>::encode_to_string_of_json(
|
||||||
|
&updated_refund,
|
||||||
|
)
|
||||||
|
.change_context(errors::StorageError::KVError)?;
|
||||||
|
|
||||||
|
self.redis_conn
|
||||||
|
.set_hash_fields(&key, (field, redis_value))
|
||||||
|
.await
|
||||||
|
.change_context(errors::StorageError::KVError)?;
|
||||||
|
|
||||||
|
let stream_name =
|
||||||
|
self.get_drainer_stream_name(&storage_types::Refund::shard_key(
|
||||||
|
PartitionKey::MerchantIdPaymentId {
|
||||||
|
merchant_id: &updated_refund.merchant_id,
|
||||||
|
payment_id: &updated_refund.payment_id,
|
||||||
|
},
|
||||||
|
self.config.drainer_num_partitions,
|
||||||
|
));
|
||||||
|
let redis_entry = kv::TypedSql {
|
||||||
|
op: kv::DBOperation::Update {
|
||||||
|
updatable: kv::Updateable::RefundUpdate(kv::RefundUpdateMems {
|
||||||
|
orig: this,
|
||||||
|
update_data: refund,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
self.redis_conn
|
||||||
|
.stream_append_entry(
|
||||||
|
&stream_name,
|
||||||
|
&RedisEntryId::AutoGeneratedID,
|
||||||
|
redis_entry
|
||||||
|
.to_field_value_pairs()
|
||||||
|
.change_context(errors::StorageError::KVError)?,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.change_context(errors::StorageError::KVError)?;
|
||||||
|
Ok(updated_refund)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn find_refund_by_merchant_id_refund_id(
|
||||||
|
&self,
|
||||||
|
merchant_id: &str,
|
||||||
|
refund_id: &str,
|
||||||
|
storage_scheme: enums::MerchantStorageScheme,
|
||||||
|
) -> CustomResult<storage_types::Refund, errors::StorageError> {
|
||||||
|
match storage_scheme {
|
||||||
|
enums::MerchantStorageScheme::PostgresOnly => {
|
||||||
|
let conn = pg_connection(&self.master_pool).await;
|
||||||
|
storage_types::Refund::find_by_merchant_id_refund_id(
|
||||||
|
&conn,
|
||||||
|
merchant_id,
|
||||||
|
refund_id,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(Into::into)
|
||||||
|
.into_report()
|
||||||
|
}
|
||||||
|
enums::MerchantStorageScheme::RedisKv => {
|
||||||
|
let lookup_id = format!("{merchant_id}_{refund_id}");
|
||||||
|
let lookup = self
|
||||||
|
.get_lookup_by_lookup_id(&lookup_id)
|
||||||
|
.await
|
||||||
|
.map_err(Into::<errors::StorageError>::into)
|
||||||
|
.into_report()?;
|
||||||
|
|
||||||
|
let key = &lookup.pk_id;
|
||||||
|
self.redis_conn
|
||||||
|
.get_hash_field_and_deserialize::<storage_types::Refund>(
|
||||||
|
key,
|
||||||
|
&lookup.sk_id,
|
||||||
|
"Refund",
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|error| error.to_redis_failed_response(key))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// async fn find_refund_by_payment_id_merchant_id_refund_id(
|
||||||
|
// &self,
|
||||||
|
// payment_id: &str,
|
||||||
|
// merchant_id: &str,
|
||||||
|
// refund_id: &str,
|
||||||
|
// ) -> CustomResult<Refund, errors::StorageError> {
|
||||||
|
// let conn = pg_connection(&self.master_pool).await;
|
||||||
|
// Refund::find_by_payment_id_merchant_id_refund_id(&conn, payment_id, merchant_id, refund_id)
|
||||||
|
// .await
|
||||||
|
// }
|
||||||
|
|
||||||
|
async fn find_refund_by_payment_id_merchant_id(
|
||||||
|
&self,
|
||||||
|
payment_id: &str,
|
||||||
|
merchant_id: &str,
|
||||||
|
storage_scheme: enums::MerchantStorageScheme,
|
||||||
|
) -> CustomResult<Vec<storage_types::Refund>, errors::StorageError> {
|
||||||
|
match storage_scheme {
|
||||||
|
enums::MerchantStorageScheme::PostgresOnly => {
|
||||||
|
let conn = pg_connection(&self.master_pool).await;
|
||||||
|
storage_types::Refund::find_by_payment_id_merchant_id(
|
||||||
|
&conn,
|
||||||
|
payment_id,
|
||||||
|
merchant_id,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(Into::into)
|
||||||
|
.into_report()
|
||||||
|
}
|
||||||
|
enums::MerchantStorageScheme::RedisKv => {
|
||||||
|
let key = format!("{}_{}", merchant_id, payment_id);
|
||||||
|
let lookup = self
|
||||||
|
.get_lookup_by_lookup_id(&key)
|
||||||
|
.await
|
||||||
|
.map_err(Into::<errors::StorageError>::into)
|
||||||
|
.into_report()?;
|
||||||
|
|
||||||
|
let pattern = db_utils::generate_hscan_pattern_for_refund(&lookup.sk_id);
|
||||||
|
|
||||||
|
self.redis_conn
|
||||||
|
.hscan_and_deserialize(&key, &pattern, None)
|
||||||
|
.await
|
||||||
|
.change_context(errors::StorageError::KVError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,24 +552,25 @@ impl RefundInterface for MockDb {
|
|||||||
_internal_reference_id: &str,
|
_internal_reference_id: &str,
|
||||||
_merchant_id: &str,
|
_merchant_id: &str,
|
||||||
_storage_scheme: enums::MerchantStorageScheme,
|
_storage_scheme: enums::MerchantStorageScheme,
|
||||||
) -> CustomResult<storage::Refund, errors::StorageError> {
|
) -> CustomResult<storage_types::Refund, errors::StorageError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn insert_refund(
|
async fn insert_refund(
|
||||||
&self,
|
&self,
|
||||||
new: storage::RefundNew,
|
new: storage_types::RefundNew,
|
||||||
_storage_scheme: enums::MerchantStorageScheme,
|
_storage_scheme: enums::MerchantStorageScheme,
|
||||||
) -> CustomResult<storage::Refund, errors::StorageError> {
|
) -> CustomResult<storage_types::Refund, errors::StorageError> {
|
||||||
let mut refunds = self.refunds.lock().await;
|
let mut refunds = self.refunds.lock().await;
|
||||||
let current_time = common_utils::date_time::now();
|
let current_time = common_utils::date_time::now();
|
||||||
|
|
||||||
let refund = storage::Refund {
|
let refund = storage_types::Refund {
|
||||||
id: refunds.len() as i32,
|
id: refunds.len() as i32,
|
||||||
internal_reference_id: new.internal_reference_id,
|
internal_reference_id: new.internal_reference_id,
|
||||||
refund_id: new.refund_id,
|
refund_id: new.refund_id,
|
||||||
payment_id: new.payment_id,
|
payment_id: new.payment_id,
|
||||||
merchant_id: new.merchant_id,
|
merchant_id: new.merchant_id,
|
||||||
|
attempt_id: new.attempt_id,
|
||||||
transaction_id: new.transaction_id,
|
transaction_id: new.transaction_id,
|
||||||
connector: new.connector,
|
connector: new.connector,
|
||||||
pg_refund_id: new.pg_refund_id,
|
pg_refund_id: new.pg_refund_id,
|
||||||
@ -187,7 +583,7 @@ impl RefundInterface for MockDb {
|
|||||||
sent_to_gateway: new.sent_to_gateway,
|
sent_to_gateway: new.sent_to_gateway,
|
||||||
refund_error_message: new.refund_error_message,
|
refund_error_message: new.refund_error_message,
|
||||||
metadata: new.metadata,
|
metadata: new.metadata,
|
||||||
refund_arn: new.refund_arn,
|
refund_arn: new.refund_arn.clone(),
|
||||||
created_at: new.created_at.unwrap_or(current_time),
|
created_at: new.created_at.unwrap_or(current_time),
|
||||||
updated_at: current_time,
|
updated_at: current_time,
|
||||||
description: new.description,
|
description: new.description,
|
||||||
@ -200,7 +596,7 @@ impl RefundInterface for MockDb {
|
|||||||
merchant_id: &str,
|
merchant_id: &str,
|
||||||
txn_id: &str,
|
txn_id: &str,
|
||||||
_storage_scheme: enums::MerchantStorageScheme,
|
_storage_scheme: enums::MerchantStorageScheme,
|
||||||
) -> CustomResult<Vec<storage::Refund>, errors::StorageError> {
|
) -> CustomResult<Vec<storage_types::Refund>, errors::StorageError> {
|
||||||
let refunds = self.refunds.lock().await;
|
let refunds = self.refunds.lock().await;
|
||||||
|
|
||||||
Ok(refunds
|
Ok(refunds
|
||||||
@ -214,10 +610,10 @@ impl RefundInterface for MockDb {
|
|||||||
|
|
||||||
async fn update_refund(
|
async fn update_refund(
|
||||||
&self,
|
&self,
|
||||||
_this: storage::Refund,
|
_this: storage_types::Refund,
|
||||||
_refund: storage::RefundUpdate,
|
_refund: storage_types::RefundUpdate,
|
||||||
_storage_scheme: enums::MerchantStorageScheme,
|
_storage_scheme: enums::MerchantStorageScheme,
|
||||||
) -> CustomResult<storage::Refund, errors::StorageError> {
|
) -> CustomResult<storage_types::Refund, errors::StorageError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,7 +622,7 @@ impl RefundInterface for MockDb {
|
|||||||
merchant_id: &str,
|
merchant_id: &str,
|
||||||
refund_id: &str,
|
refund_id: &str,
|
||||||
_storage_scheme: enums::MerchantStorageScheme,
|
_storage_scheme: enums::MerchantStorageScheme,
|
||||||
) -> CustomResult<storage::Refund, errors::StorageError> {
|
) -> CustomResult<storage_types::Refund, errors::StorageError> {
|
||||||
let refunds = self.refunds.lock().await;
|
let refunds = self.refunds.lock().await;
|
||||||
|
|
||||||
refunds
|
refunds
|
||||||
@ -245,7 +641,7 @@ impl RefundInterface for MockDb {
|
|||||||
_payment_id: &str,
|
_payment_id: &str,
|
||||||
_merchant_id: &str,
|
_merchant_id: &str,
|
||||||
_storage_scheme: enums::MerchantStorageScheme,
|
_storage_scheme: enums::MerchantStorageScheme,
|
||||||
) -> CustomResult<Vec<storage::Refund>, errors::StorageError> {
|
) -> CustomResult<Vec<storage_types::Refund>, errors::StorageError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
36
crates/router/src/db/reverse_lookup.rs
Normal file
36
crates/router/src/db/reverse_lookup.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use storage_models::{errors, StorageResult};
|
||||||
|
|
||||||
|
use super::{MockDb, Store};
|
||||||
|
use crate::{
|
||||||
|
connection::pg_connection,
|
||||||
|
types::storage::reverse_lookup::{ReverseLookup, ReverseLookupNew},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
pub trait ReverseLookupInterface {
|
||||||
|
async fn insert_reverse_lookup(&self, _new: ReverseLookupNew) -> StorageResult<ReverseLookup>;
|
||||||
|
async fn get_lookup_by_lookup_id(&self, _id: &str) -> StorageResult<ReverseLookup>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl ReverseLookupInterface for Store {
|
||||||
|
async fn insert_reverse_lookup(&self, new: ReverseLookupNew) -> StorageResult<ReverseLookup> {
|
||||||
|
let conn = pg_connection(&self.master_pool).await;
|
||||||
|
new.insert(&conn).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_lookup_by_lookup_id(&self, id: &str) -> StorageResult<ReverseLookup> {
|
||||||
|
let conn = pg_connection(&self.master_pool).await;
|
||||||
|
ReverseLookup::find_by_lookup_id(id, &conn).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl ReverseLookupInterface for MockDb {
|
||||||
|
async fn insert_reverse_lookup(&self, _new: ReverseLookupNew) -> StorageResult<ReverseLookup> {
|
||||||
|
Err(errors::DatabaseError::NotFound.into())
|
||||||
|
}
|
||||||
|
async fn get_lookup_by_lookup_id(&self, _id: &str) -> StorageResult<ReverseLookup> {
|
||||||
|
Err(errors::DatabaseError::NotFound.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -40,7 +40,7 @@ impl Store {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "kv_store")]
|
#[cfg(feature = "kv_store")]
|
||||||
pub fn drainer_stream(&self, shard_key: &str) -> String {
|
pub fn get_drainer_stream_name(&self, shard_key: &str) -> String {
|
||||||
// Example: {shard_5}_drainer_stream
|
// Example: {shard_5}_drainer_stream
|
||||||
format!("{{{}}}_{}", shard_key, self.config.drainer_stream_name,)
|
format!("{{{}}}_{}", shard_key, self.config.drainer_stream_name,)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -348,7 +348,9 @@ impl From<&storage::PaymentAttempt> for BachRedirectResponse {
|
|||||||
Self {
|
Self {
|
||||||
url: format!(
|
url: format!(
|
||||||
"/payments/start/{}/{}/{}",
|
"/payments/start/{}/{}/{}",
|
||||||
&payment_attempt.payment_id, &payment_attempt.merchant_id, &payment_attempt.txn_id
|
&payment_attempt.payment_id,
|
||||||
|
&payment_attempt.merchant_id,
|
||||||
|
&payment_attempt.attempt_id
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -87,7 +87,7 @@ impl PaymentIdTypeExt for PaymentIdType {
|
|||||||
fn get_payment_intent_id(&self) -> errors::CustomResult<String, errors::ValidationError> {
|
fn get_payment_intent_id(&self) -> errors::CustomResult<String, errors::ValidationError> {
|
||||||
match self {
|
match self {
|
||||||
Self::PaymentIntentId(id) => Ok(id.clone()),
|
Self::PaymentIntentId(id) => Ok(id.clone()),
|
||||||
Self::ConnectorTransactionId(_) | Self::PaymentTxnId(_) => {
|
Self::ConnectorTransactionId(_) | Self::PaymentAttemptId(_) => {
|
||||||
Err(errors::ValidationError::IncorrectValueProvided {
|
Err(errors::ValidationError::IncorrectValueProvided {
|
||||||
field_name: "payment_id",
|
field_name: "payment_id",
|
||||||
})
|
})
|
||||||
|
|||||||
@ -13,6 +13,7 @@ pub mod payment_attempt;
|
|||||||
pub mod payment_intent;
|
pub mod payment_intent;
|
||||||
pub mod payment_method;
|
pub mod payment_method;
|
||||||
pub mod process_tracker;
|
pub mod process_tracker;
|
||||||
|
pub mod reverse_lookup;
|
||||||
|
|
||||||
mod query;
|
mod query;
|
||||||
pub mod refund;
|
pub mod refund;
|
||||||
@ -24,5 +25,6 @@ pub mod kv;
|
|||||||
pub use self::{
|
pub use self::{
|
||||||
address::*, configs::*, connector_response::*, customers::*, events::*, locker_mock_up::*,
|
address::*, configs::*, connector_response::*, customers::*, events::*, locker_mock_up::*,
|
||||||
mandate::*, merchant_account::*, merchant_connector_account::*, payment_attempt::*,
|
mandate::*, merchant_account::*, merchant_connector_account::*, payment_attempt::*,
|
||||||
payment_intent::*, payment_method::*, process_tracker::*, refund::*, temp_card::*,
|
payment_intent::*, payment_method::*, process_tracker::*, refund::*, reverse_lookup::*,
|
||||||
|
temp_card::*,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
pub use storage_models::kv::{
|
pub use storage_models::kv::{
|
||||||
DBOperation, Insertable, PaymentAttemptUpdateMems, PaymentIntentUpdateMems, TypedSql,
|
DBOperation, Insertable, PaymentAttemptUpdateMems, PaymentIntentUpdateMems, RefundUpdateMems,
|
||||||
Updateable,
|
TypedSql, Updateable,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
pub use storage_models::refund::{
|
pub use storage_models::refund::{
|
||||||
Refund, RefundCoreWorkflow, RefundNew, RefundUpdate, RefundUpdateInternal,
|
Refund, RefundCoreWorkflow, RefundNew, RefundUpdate, RefundUpdateInternal,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "kv_store")]
|
||||||
|
impl crate::utils::storage_partitioning::KvStorePartition for Refund {}
|
||||||
|
|||||||
1
crates/router/src/types/storage/reverse_lookup.rs
Normal file
1
crates/router/src/types/storage/reverse_lookup.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub use storage_models::reverse_lookup::{ReverseLookup, ReverseLookupNew};
|
||||||
@ -1,7 +1,9 @@
|
|||||||
pub(crate) mod crypto;
|
pub(crate) mod crypto;
|
||||||
pub(crate) mod custom_serde;
|
pub(crate) mod custom_serde;
|
||||||
|
pub(crate) mod db_utils;
|
||||||
mod ext_traits;
|
mod ext_traits;
|
||||||
mod fp_utils;
|
mod fp_utils;
|
||||||
|
|
||||||
#[cfg(feature = "kv_store")]
|
#[cfg(feature = "kv_store")]
|
||||||
pub(crate) mod storage_partitioning;
|
pub(crate) mod storage_partitioning;
|
||||||
|
|
||||||
|
|||||||
10
crates/router/src/utils/db_utils.rs
Normal file
10
crates/router/src/utils/db_utils.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#[cfg(feature = "kv_store")]
|
||||||
|
/// Generates hscan field pattern. Suppose the field is pa_1234_ref_1211 it will generate
|
||||||
|
/// pa_1234_ref_*
|
||||||
|
pub fn generate_hscan_pattern_for_refund(sk: &str) -> String {
|
||||||
|
sk.split('_')
|
||||||
|
.take(3)
|
||||||
|
.chain(["*"])
|
||||||
|
.collect::<Vec<&str>>()
|
||||||
|
.join("_")
|
||||||
|
}
|
||||||
@ -562,6 +562,8 @@ pub enum ProcessTrackerStatus {
|
|||||||
Default,
|
Default,
|
||||||
Eq,
|
Eq,
|
||||||
PartialEq,
|
PartialEq,
|
||||||
|
serde::Serialize,
|
||||||
|
serde::Deserialize,
|
||||||
strum::Display,
|
strum::Display,
|
||||||
strum::EnumString,
|
strum::EnumString,
|
||||||
router_derive::DieselEnum,
|
router_derive::DieselEnum,
|
||||||
@ -585,6 +587,8 @@ pub enum RefundStatus {
|
|||||||
Default,
|
Default,
|
||||||
Eq,
|
Eq,
|
||||||
PartialEq,
|
PartialEq,
|
||||||
|
serde::Serialize,
|
||||||
|
serde::Deserialize,
|
||||||
strum::Display,
|
strum::Display,
|
||||||
strum::EnumString,
|
strum::EnumString,
|
||||||
router_derive::DieselEnum,
|
router_derive::DieselEnum,
|
||||||
|
|||||||
@ -5,6 +5,7 @@ use crate::{
|
|||||||
errors,
|
errors,
|
||||||
payment_attempt::{PaymentAttempt, PaymentAttemptNew, PaymentAttemptUpdate},
|
payment_attempt::{PaymentAttempt, PaymentAttemptNew, PaymentAttemptUpdate},
|
||||||
payment_intent::{PaymentIntent, PaymentIntentNew, PaymentIntentUpdate},
|
payment_intent::{PaymentIntent, PaymentIntentNew, PaymentIntentUpdate},
|
||||||
|
refund::{Refund, RefundNew, RefundUpdate},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
@ -37,6 +38,7 @@ impl TypedSql {
|
|||||||
pub enum Insertable {
|
pub enum Insertable {
|
||||||
PaymentIntent(PaymentIntentNew),
|
PaymentIntent(PaymentIntentNew),
|
||||||
PaymentAttempt(PaymentAttemptNew),
|
PaymentAttempt(PaymentAttemptNew),
|
||||||
|
Refund(RefundNew),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
@ -44,6 +46,7 @@ pub enum Insertable {
|
|||||||
pub enum Updateable {
|
pub enum Updateable {
|
||||||
PaymentIntentUpdate(PaymentIntentUpdateMems),
|
PaymentIntentUpdate(PaymentIntentUpdateMems),
|
||||||
PaymentAttemptUpdate(PaymentAttemptUpdateMems),
|
PaymentAttemptUpdate(PaymentAttemptUpdateMems),
|
||||||
|
RefundUpdate(RefundUpdateMems),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
@ -57,3 +60,9 @@ pub struct PaymentAttemptUpdateMems {
|
|||||||
pub orig: PaymentAttempt,
|
pub orig: PaymentAttempt,
|
||||||
pub update_data: PaymentAttemptUpdate,
|
pub update_data: PaymentAttemptUpdate,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct RefundUpdateMems {
|
||||||
|
pub orig: Refund,
|
||||||
|
pub update_data: RefundUpdate,
|
||||||
|
}
|
||||||
|
|||||||
@ -19,6 +19,7 @@ pub mod payment_method;
|
|||||||
pub mod process_tracker;
|
pub mod process_tracker;
|
||||||
pub mod query;
|
pub mod query;
|
||||||
pub mod refund;
|
pub mod refund;
|
||||||
|
pub mod reverse_lookup;
|
||||||
pub mod schema;
|
pub mod schema;
|
||||||
pub mod temp_card;
|
pub mod temp_card;
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ pub struct PaymentAttempt {
|
|||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub payment_id: String,
|
pub payment_id: String,
|
||||||
pub merchant_id: String,
|
pub merchant_id: String,
|
||||||
pub txn_id: String,
|
pub attempt_id: String,
|
||||||
pub status: storage_enums::AttemptStatus,
|
pub status: storage_enums::AttemptStatus,
|
||||||
pub amount: i64,
|
pub amount: i64,
|
||||||
pub currency: Option<storage_enums::Currency>,
|
pub currency: Option<storage_enums::Currency>,
|
||||||
@ -47,7 +47,7 @@ pub struct PaymentAttempt {
|
|||||||
pub struct PaymentAttemptNew {
|
pub struct PaymentAttemptNew {
|
||||||
pub payment_id: String,
|
pub payment_id: String,
|
||||||
pub merchant_id: String,
|
pub merchant_id: String,
|
||||||
pub txn_id: String,
|
pub attempt_id: String,
|
||||||
pub status: storage_enums::AttemptStatus,
|
pub status: storage_enums::AttemptStatus,
|
||||||
pub amount: i64,
|
pub amount: i64,
|
||||||
pub currency: Option<storage_enums::Currency>,
|
pub currency: Option<storage_enums::Currency>,
|
||||||
|
|||||||
@ -13,4 +13,5 @@ pub mod payment_intent;
|
|||||||
pub mod payment_method;
|
pub mod payment_method;
|
||||||
pub mod process_tracker;
|
pub mod process_tracker;
|
||||||
pub mod refund;
|
pub mod refund;
|
||||||
|
pub mod reverse_lookup;
|
||||||
pub mod temp_card;
|
pub mod temp_card;
|
||||||
|
|||||||
@ -133,16 +133,16 @@ impl PaymentAttempt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(conn))]
|
#[instrument(skip(conn))]
|
||||||
pub async fn find_by_merchant_id_transaction_id(
|
pub async fn find_by_merchant_id_attempt_id(
|
||||||
conn: &PgPooledConn,
|
conn: &PgPooledConn,
|
||||||
merchant_id: &str,
|
merchant_id: &str,
|
||||||
txn_id: &str,
|
attempt_id: &str,
|
||||||
) -> StorageResult<Self> {
|
) -> StorageResult<Self> {
|
||||||
generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
|
generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
|
||||||
conn,
|
conn,
|
||||||
dsl::merchant_id
|
dsl::merchant_id
|
||||||
.eq(merchant_id.to_owned())
|
.eq(merchant_id.to_owned())
|
||||||
.and(dsl::txn_id.eq(txn_id.to_owned())),
|
.and(dsl::attempt_id.eq(attempt_id.to_owned())),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,8 +9,6 @@ use crate::{
|
|||||||
PgPooledConn, StorageResult,
|
PgPooledConn, StorageResult,
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: Find by partition key : Review
|
|
||||||
|
|
||||||
impl RefundNew {
|
impl RefundNew {
|
||||||
#[instrument(skip(conn))]
|
#[instrument(skip(conn))]
|
||||||
pub async fn insert(self, conn: &PgPooledConn) -> StorageResult<Refund> {
|
pub async fn insert(self, conn: &PgPooledConn) -> StorageResult<Refund> {
|
||||||
|
|||||||
33
crates/storage_models/src/query/reverse_lookup.rs
Normal file
33
crates/storage_models/src/query/reverse_lookup.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
use diesel::{associations::HasTable, ExpressionMethods};
|
||||||
|
use router_env::{tracing, tracing::instrument};
|
||||||
|
|
||||||
|
use super::generics;
|
||||||
|
use crate::{
|
||||||
|
reverse_lookup::{ReverseLookup, ReverseLookupNew},
|
||||||
|
schema::reverse_lookup::dsl,
|
||||||
|
PgPooledConn, StorageResult,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl ReverseLookupNew {
|
||||||
|
#[instrument(skip(conn))]
|
||||||
|
pub async fn insert(self, conn: &PgPooledConn) -> StorageResult<ReverseLookup> {
|
||||||
|
generics::generic_insert(conn, self).await
|
||||||
|
}
|
||||||
|
#[instrument(skip(conn))]
|
||||||
|
pub async fn batch_insert(
|
||||||
|
reverse_lookups: Vec<Self>,
|
||||||
|
conn: &PgPooledConn,
|
||||||
|
) -> StorageResult<()> {
|
||||||
|
generics::generic_insert::<_, _, ReverseLookup>(conn, reverse_lookups).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ReverseLookup {
|
||||||
|
pub async fn find_by_lookup_id(lookup_id: &str, conn: &PgPooledConn) -> StorageResult<Self> {
|
||||||
|
generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
|
||||||
|
conn,
|
||||||
|
dsl::lookup_id.eq(lookup_id.to_owned()),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,7 +4,9 @@ use time::PrimitiveDateTime;
|
|||||||
|
|
||||||
use crate::{enums as storage_enums, schema::refund};
|
use crate::{enums as storage_enums, schema::refund};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, Identifiable, Queryable, PartialEq)]
|
#[derive(
|
||||||
|
Clone, Debug, Eq, Identifiable, Queryable, PartialEq, serde::Serialize, serde::Deserialize,
|
||||||
|
)]
|
||||||
#[diesel(table_name = refund)]
|
#[diesel(table_name = refund)]
|
||||||
pub struct Refund {
|
pub struct Refund {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
@ -28,9 +30,20 @@ pub struct Refund {
|
|||||||
pub created_at: PrimitiveDateTime,
|
pub created_at: PrimitiveDateTime,
|
||||||
pub updated_at: PrimitiveDateTime,
|
pub updated_at: PrimitiveDateTime,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
|
pub attempt_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Insertable, router_derive::DebugAsDisplay)]
|
#[derive(
|
||||||
|
Clone,
|
||||||
|
Debug,
|
||||||
|
Default,
|
||||||
|
Eq,
|
||||||
|
PartialEq,
|
||||||
|
Insertable,
|
||||||
|
router_derive::DebugAsDisplay,
|
||||||
|
serde::Serialize,
|
||||||
|
serde::Deserialize,
|
||||||
|
)]
|
||||||
#[diesel(table_name = refund)]
|
#[diesel(table_name = refund)]
|
||||||
pub struct RefundNew {
|
pub struct RefundNew {
|
||||||
pub refund_id: String,
|
pub refund_id: String,
|
||||||
@ -53,9 +66,10 @@ pub struct RefundNew {
|
|||||||
pub created_at: Option<PrimitiveDateTime>,
|
pub created_at: Option<PrimitiveDateTime>,
|
||||||
pub modified_at: Option<PrimitiveDateTime>,
|
pub modified_at: Option<PrimitiveDateTime>,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
|
pub attempt_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum RefundUpdate {
|
pub enum RefundUpdate {
|
||||||
Update {
|
Update {
|
||||||
pg_refund_id: String,
|
pg_refund_id: String,
|
||||||
@ -132,6 +146,21 @@ impl From<RefundUpdate> for RefundUpdateInternal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RefundUpdate {
|
||||||
|
pub fn apply_changeset(self, source: Refund) -> Refund {
|
||||||
|
let pa_update: RefundUpdateInternal = self.into();
|
||||||
|
Refund {
|
||||||
|
pg_refund_id: pa_update.pg_refund_id,
|
||||||
|
refund_status: pa_update.refund_status.unwrap_or(source.refund_status),
|
||||||
|
sent_to_gateway: pa_update.sent_to_gateway.unwrap_or(source.sent_to_gateway),
|
||||||
|
refund_error_message: pa_update.refund_error_message,
|
||||||
|
refund_arn: pa_update.refund_arn,
|
||||||
|
metadata: pa_update.metadata,
|
||||||
|
..source
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Deserialize, Serialize)]
|
#[derive(Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||||
pub struct RefundCoreWorkflow {
|
pub struct RefundCoreWorkflow {
|
||||||
pub refund_internal_reference_id: String,
|
pub refund_internal_reference_id: String,
|
||||||
|
|||||||
33
crates/storage_models/src/reverse_lookup.rs
Normal file
33
crates/storage_models/src/reverse_lookup.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
use diesel::{Identifiable, Insertable, Queryable};
|
||||||
|
|
||||||
|
use crate::schema::reverse_lookup;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// This reverse lookup table basically looks up id's and get result_id that you want. This is
|
||||||
|
/// useful for KV where you can't lookup without key
|
||||||
|
#[derive(
|
||||||
|
Clone, Debug, serde::Serialize, serde::Deserialize, Identifiable, Queryable, Eq, PartialEq,
|
||||||
|
)]
|
||||||
|
#[diesel(table_name = reverse_lookup)]
|
||||||
|
#[diesel(primary_key(lookup_id))]
|
||||||
|
pub struct ReverseLookup {
|
||||||
|
/// Primary key. The key id.
|
||||||
|
pub lookup_id: String,
|
||||||
|
/// the value id. i.e the id you want to access KV table.
|
||||||
|
pub pk_id: String,
|
||||||
|
/// the `field` in KV database. Which is used to differentiate between two same keys
|
||||||
|
pub sk_id: String,
|
||||||
|
/// the source of insertion for reference
|
||||||
|
pub source: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(
|
||||||
|
Clone, Debug, Insertable, router_derive::DebugAsDisplay, Eq, PartialEq, serde::Serialize,
|
||||||
|
)]
|
||||||
|
#[diesel(table_name = reverse_lookup)]
|
||||||
|
pub struct ReverseLookupNew {
|
||||||
|
pub lookup_id: String,
|
||||||
|
pub pk_id: String,
|
||||||
|
pub sk_id: String,
|
||||||
|
pub source: String,
|
||||||
|
}
|
||||||
@ -187,7 +187,7 @@ diesel::table! {
|
|||||||
id -> Int4,
|
id -> Int4,
|
||||||
payment_id -> Varchar,
|
payment_id -> Varchar,
|
||||||
merchant_id -> Varchar,
|
merchant_id -> Varchar,
|
||||||
txn_id -> Varchar,
|
attempt_id -> Varchar,
|
||||||
status -> AttemptStatus,
|
status -> AttemptStatus,
|
||||||
amount -> Int8,
|
amount -> Int8,
|
||||||
currency -> Nullable<Currency>,
|
currency -> Nullable<Currency>,
|
||||||
@ -325,6 +325,19 @@ diesel::table! {
|
|||||||
created_at -> Timestamp,
|
created_at -> Timestamp,
|
||||||
modified_at -> Timestamp,
|
modified_at -> Timestamp,
|
||||||
description -> Nullable<Varchar>,
|
description -> Nullable<Varchar>,
|
||||||
|
attempt_id -> Varchar,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diesel::table! {
|
||||||
|
use diesel::sql_types::*;
|
||||||
|
use crate::enums::diesel_exports::*;
|
||||||
|
|
||||||
|
reverse_lookup (lookup_id) {
|
||||||
|
lookup_id -> Varchar,
|
||||||
|
sk_id -> Varchar,
|
||||||
|
pk_id -> Varchar,
|
||||||
|
source -> Varchar,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,5 +368,6 @@ diesel::allow_tables_to_appear_in_same_query!(
|
|||||||
payment_methods,
|
payment_methods,
|
||||||
process_tracker,
|
process_tracker,
|
||||||
refund,
|
refund,
|
||||||
|
reverse_lookup,
|
||||||
temp_card,
|
temp_card,
|
||||||
);
|
);
|
||||||
|
|||||||
2
migrations/2022-12-12-132936_reverse_lookup/down.sql
Normal file
2
migrations/2022-12-12-132936_reverse_lookup/down.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
DROP TABLE IF EXISTS reverse_lookup;
|
||||||
|
|
||||||
8
migrations/2022-12-12-132936_reverse_lookup/up.sql
Normal file
8
migrations/2022-12-12-132936_reverse_lookup/up.sql
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
CREATE TABLE reverse_lookup (
|
||||||
|
lookup_id VARCHAR(255) NOT NULL PRIMARY KEY,
|
||||||
|
sk_id VARCHAR(50) NOT NULL,
|
||||||
|
pk_id VARCHAR(255) NOT NULL,
|
||||||
|
source VARCHAR(30) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX lookup_id_index ON reverse_lookup (lookup_id);
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE payment_id
|
||||||
|
RENAME attempt_id to txn_id;
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE payment_attempt
|
||||||
|
RENAME COLUMN txn_id to attempt_id;
|
||||||
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE refund DROP COLUMN attempt_id;
|
||||||
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE refund ADD COLUMN attempt_id VARCHAR(64) NOT NULL;
|
||||||
Reference in New Issue
Block a user