mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
feat(core): Add support for process tracker retrieve api in v2 (#7602)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -11,10 +11,11 @@ pub mod payouts;
|
||||
#[cfg(feature = "recon")]
|
||||
pub mod recon;
|
||||
pub mod refund;
|
||||
#[cfg(feature = "v2")]
|
||||
pub mod revenue_recovery;
|
||||
pub mod routing;
|
||||
pub mod user;
|
||||
pub mod user_role;
|
||||
|
||||
use common_utils::{
|
||||
events::{ApiEventMetric, ApiEventsType},
|
||||
impl_api_event_type,
|
||||
|
||||
14
crates/api_models/src/events/revenue_recovery.rs
Normal file
14
crates/api_models/src/events/revenue_recovery.rs
Normal file
@ -0,0 +1,14 @@
|
||||
use common_utils::events::{ApiEventMetric, ApiEventsType};
|
||||
|
||||
use crate::process_tracker::revenue_recovery::{RevenueRecoveryId, RevenueRecoveryResponse};
|
||||
|
||||
impl ApiEventMetric for RevenueRecoveryResponse {
|
||||
fn get_api_event_type(&self) -> Option<ApiEventsType> {
|
||||
Some(ApiEventsType::ProcessTracker)
|
||||
}
|
||||
}
|
||||
impl ApiEventMetric for RevenueRecoveryId {
|
||||
fn get_api_event_type(&self) -> Option<ApiEventsType> {
|
||||
Some(ApiEventsType::ProcessTracker)
|
||||
}
|
||||
}
|
||||
@ -30,6 +30,7 @@ pub mod payments;
|
||||
pub mod payouts;
|
||||
pub mod pm_auth;
|
||||
pub mod poll;
|
||||
pub mod process_tracker;
|
||||
#[cfg(feature = "recon")]
|
||||
pub mod recon;
|
||||
pub mod refunds;
|
||||
|
||||
2
crates/api_models/src/process_tracker.rs
Normal file
2
crates/api_models/src/process_tracker.rs
Normal file
@ -0,0 +1,2 @@
|
||||
#[cfg(feature = "v2")]
|
||||
pub mod revenue_recovery;
|
||||
21
crates/api_models/src/process_tracker/revenue_recovery.rs
Normal file
21
crates/api_models/src/process_tracker/revenue_recovery.rs
Normal file
@ -0,0 +1,21 @@
|
||||
use common_utils::id_type;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::PrimitiveDateTime;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use crate::enums;
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
||||
pub struct RevenueRecoveryResponse {
|
||||
pub id: String,
|
||||
pub name: Option<String>,
|
||||
pub schedule_time_for_payment: Option<PrimitiveDateTime>,
|
||||
pub schedule_time_for_psync: Option<PrimitiveDateTime>,
|
||||
#[schema(value_type = ProcessTrackerStatus, example = "finish")]
|
||||
pub status: enums::ProcessTrackerStatus,
|
||||
pub business_status: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
||||
pub struct RevenueRecoveryId {
|
||||
pub revenue_recovery_id: id_type::GlobalPaymentId,
|
||||
}
|
||||
@ -21,7 +21,8 @@ pub mod diesel_exports {
|
||||
DbDisputeStatus as DisputeStatus, DbFraudCheckStatus as FraudCheckStatus,
|
||||
DbFutureUsage as FutureUsage, DbIntentStatus as IntentStatus,
|
||||
DbMandateStatus as MandateStatus, DbPaymentMethodIssuerCode as PaymentMethodIssuerCode,
|
||||
DbPaymentType as PaymentType, DbRefundStatus as RefundStatus,
|
||||
DbPaymentType as PaymentType, DbProcessTrackerStatus as ProcessTrackerStatus,
|
||||
DbRefundStatus as RefundStatus,
|
||||
DbRequestIncrementalAuthorization as RequestIncrementalAuthorization,
|
||||
DbScaExemptionType as ScaExemptionType,
|
||||
DbSuccessBasedRoutingConclusiveState as SuccessBasedRoutingConclusiveState,
|
||||
@ -6980,6 +6981,7 @@ pub enum Resource {
|
||||
ReconReports,
|
||||
RunRecon,
|
||||
ReconConfig,
|
||||
RevenueRecovery,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, serde::Serialize, Hash)]
|
||||
@ -7819,6 +7821,60 @@ pub enum TriggeredBy {
|
||||
External,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
Eq,
|
||||
PartialEq,
|
||||
serde::Deserialize,
|
||||
serde::Serialize,
|
||||
strum::Display,
|
||||
strum::EnumString,
|
||||
ToSchema,
|
||||
)]
|
||||
#[router_derive::diesel_enum(storage_type = "db_enum")]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum ProcessTrackerStatus {
|
||||
// Picked by the producer
|
||||
Processing,
|
||||
// State when the task is added
|
||||
New,
|
||||
// Send to retry
|
||||
Pending,
|
||||
// Picked by consumer
|
||||
ProcessStarted,
|
||||
// Finished by consumer
|
||||
Finish,
|
||||
// Review the task
|
||||
Review,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
serde::Serialize,
|
||||
serde::Deserialize,
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
strum::EnumString,
|
||||
strum::Display,
|
||||
)]
|
||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
|
||||
pub enum ProcessTrackerRunner {
|
||||
PaymentsSyncWorkflow,
|
||||
RefundWorkflowRouter,
|
||||
DeleteTokenizeDataWorkflow,
|
||||
ApiKeyExpiryWorkflow,
|
||||
OutgoingWebhookRetryWorkflow,
|
||||
AttachPayoutAccountWorkflow,
|
||||
PaymentMethodStatusUpdateWorkflow,
|
||||
PassiveRecoveryWorkflow,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CryptoPadding {
|
||||
PKCS7,
|
||||
|
||||
@ -121,6 +121,7 @@ pub enum ApiEventsType {
|
||||
PaymentMethodSession {
|
||||
payment_method_session_id: id_type::GlobalPaymentMethodSessionId,
|
||||
},
|
||||
ProcessTracker,
|
||||
}
|
||||
|
||||
impl ApiEventMetric for serde_json::Value {}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use common_enums::enums;
|
||||
use error_stack::ResultExt;
|
||||
|
||||
use crate::{errors, generate_id_with_default_len, generate_time_ordered_id_without_prefix, types};
|
||||
@ -31,6 +32,15 @@ impl GlobalPaymentId {
|
||||
pub fn generate_client_secret(&self) -> types::ClientSecret {
|
||||
types::ClientSecret::new(self.clone(), generate_time_ordered_id_without_prefix())
|
||||
}
|
||||
|
||||
/// Generate the id for revenue recovery Execute PT workflow
|
||||
pub fn get_execute_revenue_recovery_id(
|
||||
&self,
|
||||
task: &str,
|
||||
runner: enums::ProcessTrackerRunner,
|
||||
) -> String {
|
||||
format!("{task}_{runner}_{}", self.get_string_repr())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: refactor the macro to include this id use case as well
|
||||
@ -67,6 +77,15 @@ impl GlobalAttemptId {
|
||||
pub fn get_string_repr(&self) -> &str {
|
||||
self.0.get_string_repr()
|
||||
}
|
||||
|
||||
/// Generate the id for Revenue Recovery Psync PT workflow
|
||||
pub fn get_psync_revenue_recovery_id(
|
||||
&self,
|
||||
task: &str,
|
||||
runner: enums::ProcessTrackerRunner,
|
||||
) -> String {
|
||||
format!("{runner}_{task}_{}", self.get_string_repr())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<std::borrow::Cow<'static, str>> for GlobalAttemptId {
|
||||
|
||||
@ -78,35 +78,6 @@ pub enum EventObjectType {
|
||||
PayoutDetails,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
Eq,
|
||||
PartialEq,
|
||||
serde::Deserialize,
|
||||
serde::Serialize,
|
||||
strum::Display,
|
||||
strum::EnumString,
|
||||
)]
|
||||
#[diesel_enum(storage_type = "db_enum")]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum ProcessTrackerStatus {
|
||||
// Picked by the producer
|
||||
Processing,
|
||||
// State when the task is added
|
||||
New,
|
||||
// Send to retry
|
||||
Pending,
|
||||
// Picked by consumer
|
||||
ProcessStarted,
|
||||
// Finished by consumer
|
||||
Finish,
|
||||
// Review the task
|
||||
Review,
|
||||
}
|
||||
|
||||
// Refund
|
||||
#[derive(
|
||||
Clone,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use common_enums::ApiVersion;
|
||||
pub use common_enums::{enums::ProcessTrackerRunner, ApiVersion};
|
||||
use common_utils::ext_traits::Encode;
|
||||
use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
|
||||
use error_stack::ResultExt;
|
||||
@ -196,30 +196,6 @@ impl From<ProcessTrackerUpdate> for ProcessTrackerUpdateInternal {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
serde::Serialize,
|
||||
serde::Deserialize,
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
strum::EnumString,
|
||||
strum::Display,
|
||||
)]
|
||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
|
||||
pub enum ProcessTrackerRunner {
|
||||
PaymentsSyncWorkflow,
|
||||
RefundWorkflowRouter,
|
||||
DeleteTokenizeDataWorkflow,
|
||||
ApiKeyExpiryWorkflow,
|
||||
OutgoingWebhookRetryWorkflow,
|
||||
AttachPayoutAccountWorkflow,
|
||||
PaymentMethodStatusUpdateWorkflow,
|
||||
PassiveRecoveryWorkflow,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
@ -148,6 +148,9 @@ Never share your secret api keys. Keep them guarded and secure.
|
||||
|
||||
//Routes for refunds
|
||||
routes::refunds::refunds_create,
|
||||
|
||||
// Routes for Revenue Recovery flow under Process Tracker
|
||||
routes::revenue_recovery::revenue_recovery_pt_retrieve_api
|
||||
),
|
||||
components(schemas(
|
||||
common_utils::types::MinorUnit,
|
||||
@ -708,6 +711,8 @@ Never share your secret api keys. Keep them guarded and secure.
|
||||
api_models::payment_methods::PaymentMethodSessionConfirmRequest,
|
||||
api_models::payment_methods::PaymentMethodSessionResponse,
|
||||
api_models::payment_methods::AuthenticationDetails,
|
||||
api_models::process_tracker::revenue_recovery::RevenueRecoveryResponse,
|
||||
api_models::enums::ProcessTrackerStatus,
|
||||
routes::payments::ForceSync,
|
||||
)),
|
||||
modifiers(&SecurityAddon)
|
||||
|
||||
@ -17,5 +17,6 @@ pub mod poll;
|
||||
pub mod profile;
|
||||
pub mod refunds;
|
||||
pub mod relay;
|
||||
pub mod revenue_recovery;
|
||||
pub mod routing;
|
||||
pub mod webhook_events;
|
||||
|
||||
22
crates/openapi/src/routes/revenue_recovery.rs
Normal file
22
crates/openapi/src/routes/revenue_recovery.rs
Normal file
@ -0,0 +1,22 @@
|
||||
#[cfg(feature = "v2")]
|
||||
/// Revenue Recovery - Retrieve
|
||||
///
|
||||
/// Retrieve the Revenue Recovery Payment Info
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/v2/process_tracker/revenue_recovery_workflow/{revenue_recovery_id}",
|
||||
params(
|
||||
("recovery_recovery_id" = String, Path, description = "The payment intent id"),
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Revenue Recovery Info Retrieved Successfully", body = RevenueRecoveryResponse),
|
||||
(status = 500, description = "Internal server error"),
|
||||
(status = 404, description = "Resource missing"),
|
||||
(status = 422, description = "Unprocessable request"),
|
||||
(status = 403, description = "Forbidden"),
|
||||
),
|
||||
tag = "Revenue Recovery",
|
||||
operation_id = "Retrieve Revenue Recovery Info",
|
||||
security(("jwt_key" = []))
|
||||
)]
|
||||
pub async fn revenue_recovery_pt_retrieve_api() {}
|
||||
@ -321,9 +321,9 @@ impl ProcessTrackerWorkflows<routes::SessionState> for WorkflowRunner {
|
||||
storage::ProcessTrackerRunner::PaymentMethodStatusUpdateWorkflow => Ok(Box::new(
|
||||
workflows::payment_method_status_update::PaymentMethodStatusUpdateWorkflow,
|
||||
)),
|
||||
storage::ProcessTrackerRunner::PassiveRecoveryWorkflow => Ok(Box::new(
|
||||
workflows::passive_churn_recovery_workflow::ExecutePcrWorkflow,
|
||||
)),
|
||||
storage::ProcessTrackerRunner::PassiveRecoveryWorkflow => {
|
||||
Ok(Box::new(workflows::revenue_recovery::ExecutePcrWorkflow))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -57,6 +57,6 @@ pub mod webhooks;
|
||||
|
||||
pub mod unified_authentication_service;
|
||||
|
||||
#[cfg(feature = "v2")]
|
||||
pub mod passive_churn_recovery;
|
||||
pub mod relay;
|
||||
#[cfg(feature = "v2")]
|
||||
pub mod revenue_recovery;
|
||||
|
||||
@ -1,33 +1,40 @@
|
||||
pub mod transformers;
|
||||
pub mod types;
|
||||
use api_models::payments::{PaymentRevenueRecoveryMetadata, PaymentsRetrieveRequest};
|
||||
use common_utils::{self, ext_traits::OptionExt, id_type, types::keymanager::KeyManagerState};
|
||||
use api_models::{payments::PaymentsRetrieveRequest, process_tracker::revenue_recovery};
|
||||
use common_utils::{
|
||||
self,
|
||||
ext_traits::{OptionExt, ValueExt},
|
||||
id_type,
|
||||
types::keymanager::KeyManagerState,
|
||||
};
|
||||
use diesel_models::process_tracker::business_status;
|
||||
use error_stack::{self, ResultExt};
|
||||
use hyperswitch_domain_models::{
|
||||
behaviour::ReverseConversion,
|
||||
errors::api_error_response,
|
||||
api::ApplicationResponse,
|
||||
payments::{PaymentIntent, PaymentStatusData},
|
||||
ApiModelToDieselModelConvertor,
|
||||
};
|
||||
use scheduler::errors;
|
||||
use scheduler::errors as sch_errors;
|
||||
|
||||
use crate::{
|
||||
core::{
|
||||
errors::RouterResult,
|
||||
passive_churn_recovery::types as pcr_types,
|
||||
errors::{self, RouterResponse, RouterResult, StorageErrorExt},
|
||||
payments::{self, operations::Operation},
|
||||
revenue_recovery::types as pcr_types,
|
||||
},
|
||||
db::StorageInterface,
|
||||
logger,
|
||||
routes::{metrics, SessionState},
|
||||
types::{
|
||||
api,
|
||||
storage::{self, passive_churn_recovery as pcr},
|
||||
storage::{self, revenue_recovery as pcr},
|
||||
transformers::ForeignInto,
|
||||
},
|
||||
};
|
||||
|
||||
pub const EXECUTE_WORKFLOW: &str = "EXECUTE_WORKFLOW";
|
||||
pub const PSYNC_WORKFLOW: &str = "PSYNC_WORKFLOW";
|
||||
|
||||
pub async fn perform_execute_payment(
|
||||
state: &SessionState,
|
||||
execute_task_process: &storage::ProcessTracker,
|
||||
@ -35,7 +42,7 @@ pub async fn perform_execute_payment(
|
||||
pcr_data: &pcr::PcrPaymentData,
|
||||
_key_manager_state: &KeyManagerState,
|
||||
payment_intent: &PaymentIntent,
|
||||
) -> Result<(), errors::ProcessTrackerError> {
|
||||
) -> Result<(), sch_errors::ProcessTrackerError> {
|
||||
let db = &*state.store;
|
||||
|
||||
let mut pcr_metadata = payment_intent
|
||||
@ -79,9 +86,9 @@ pub async fn perform_execute_payment(
|
||||
|
||||
pcr_types::Decision::Psync(attempt_status, attempt_id) => {
|
||||
// find if a psync task is already present
|
||||
let task = "PSYNC_WORKFLOW";
|
||||
let task = PSYNC_WORKFLOW;
|
||||
let runner = storage::ProcessTrackerRunner::PassiveRecoveryWorkflow;
|
||||
let process_tracker_id = format!("{runner}_{task}_{}", attempt_id.get_string_repr());
|
||||
let process_tracker_id = attempt_id.get_psync_revenue_recovery_id(task, runner);
|
||||
let psync_process = db.find_process_by_id(&process_tracker_id).await?;
|
||||
|
||||
match psync_process {
|
||||
@ -138,8 +145,8 @@ async fn insert_psync_pcr_task(
|
||||
payment_attempt_id: id_type::GlobalAttemptId,
|
||||
runner: storage::ProcessTrackerRunner,
|
||||
) -> RouterResult<storage::ProcessTracker> {
|
||||
let task = "PSYNC_WORKFLOW";
|
||||
let process_tracker_id = format!("{runner}_{task}_{}", payment_attempt_id.get_string_repr());
|
||||
let task = PSYNC_WORKFLOW;
|
||||
let process_tracker_id = payment_attempt_id.get_psync_revenue_recovery_id(task, runner);
|
||||
let schedule_time = common_utils::date_time::now();
|
||||
let psync_workflow_tracking_data = pcr::PcrWorkflowTrackingData {
|
||||
global_payment_id: payment_id,
|
||||
@ -158,13 +165,13 @@ async fn insert_psync_pcr_task(
|
||||
schedule_time,
|
||||
hyperswitch_domain_models::consts::API_VERSION,
|
||||
)
|
||||
.change_context(api_error_response::ApiErrorResponse::InternalServerError)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Failed to construct delete tokenized data process tracker task")?;
|
||||
|
||||
let response = db
|
||||
.insert_process(process_tracker_entry)
|
||||
.await
|
||||
.change_context(api_error_response::ApiErrorResponse::InternalServerError)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Failed to construct delete tokenized data process tracker task")?;
|
||||
metrics::TASKS_ADDED_COUNT.add(1, router_env::metric_attributes!(("flow", "PsyncPcr")));
|
||||
|
||||
@ -219,3 +226,57 @@ pub async fn call_psync_api(
|
||||
.await?;
|
||||
Ok(payment_data)
|
||||
}
|
||||
|
||||
pub async fn retrieve_revenue_recovery_process_tracker(
|
||||
state: SessionState,
|
||||
id: id_type::GlobalPaymentId,
|
||||
) -> RouterResponse<revenue_recovery::RevenueRecoveryResponse> {
|
||||
let db = &*state.store;
|
||||
let task = EXECUTE_WORKFLOW;
|
||||
let runner = storage::ProcessTrackerRunner::PassiveRecoveryWorkflow;
|
||||
let process_tracker_id = id.get_execute_revenue_recovery_id(task, runner);
|
||||
|
||||
let process_tracker = db
|
||||
.find_process_by_id(&process_tracker_id)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)
|
||||
.attach_printable("error retrieving the process tracker id")?
|
||||
.get_required_value("Process Tracker")
|
||||
.change_context(errors::ApiErrorResponse::GenericNotFoundError {
|
||||
message: "Entry For the following id doesn't exists".to_owned(),
|
||||
})?;
|
||||
|
||||
let tracking_data = process_tracker
|
||||
.tracking_data
|
||||
.clone()
|
||||
.parse_value::<pcr::PcrWorkflowTrackingData>("PCRWorkflowTrackingData")
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("unable to deserialize Pcr Workflow Tracking Data")?;
|
||||
|
||||
let psync_task = PSYNC_WORKFLOW;
|
||||
|
||||
let process_tracker_id_for_psync = tracking_data
|
||||
.payment_attempt_id
|
||||
.get_psync_revenue_recovery_id(psync_task, runner);
|
||||
|
||||
let process_tracker_for_psync = db
|
||||
.find_process_by_id(&process_tracker_id_for_psync)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
logger::error!("Error while retreiving psync task : {:?}", e);
|
||||
})
|
||||
.ok()
|
||||
.flatten();
|
||||
|
||||
let schedule_time_for_psync = process_tracker_for_psync.and_then(|pt| pt.schedule_time);
|
||||
|
||||
let response = revenue_recovery::RevenueRecoveryResponse {
|
||||
id: process_tracker.id,
|
||||
name: process_tracker.name,
|
||||
schedule_time_for_payment: process_tracker.schedule_time,
|
||||
schedule_time_for_psync,
|
||||
status: process_tracker.status,
|
||||
business_status: process_tracker.business_status,
|
||||
};
|
||||
Ok(ApplicationResponse::Json(response))
|
||||
}
|
||||
@ -1,8 +1,6 @@
|
||||
use common_enums::AttemptStatus;
|
||||
|
||||
use crate::{
|
||||
core::passive_churn_recovery::types::PcrAttemptStatus, types::transformers::ForeignFrom,
|
||||
};
|
||||
use crate::{core::revenue_recovery::types::PcrAttemptStatus, types::transformers::ForeignFrom};
|
||||
|
||||
impl ForeignFrom<AttemptStatus> for PcrAttemptStatus {
|
||||
fn foreign_from(s: AttemptStatus) -> Self {
|
||||
@ -19,14 +19,14 @@ use time::PrimitiveDateTime;
|
||||
use crate::{
|
||||
core::{
|
||||
errors::{self, RouterResult},
|
||||
passive_churn_recovery::{self as core_pcr},
|
||||
payments::{self, operations::Operation},
|
||||
revenue_recovery::{self as core_pcr},
|
||||
},
|
||||
db::StorageInterface,
|
||||
logger,
|
||||
routes::SessionState,
|
||||
types::{api::payments as api_types, storage, transformers::ForeignInto},
|
||||
workflows::passive_churn_recovery_workflow::get_schedule_time_to_retry_mit_payments,
|
||||
workflows::revenue_recovery::get_schedule_time_to_retry_mit_payments,
|
||||
};
|
||||
|
||||
type RecoveryResult<T> = error_stack::Result<T, errors::RecoveryError>;
|
||||
@ -87,7 +87,7 @@ impl Decision {
|
||||
intent_status: enums::IntentStatus,
|
||||
called_connector: enums::PaymentConnectorTransmission,
|
||||
active_attempt_id: Option<id_type::GlobalAttemptId>,
|
||||
pcr_data: &storage::passive_churn_recovery::PcrPaymentData,
|
||||
pcr_data: &storage::revenue_recovery::PcrPaymentData,
|
||||
payment_id: &id_type::GlobalPaymentId,
|
||||
) -> RecoveryResult<Self> {
|
||||
Ok(match (intent_status, called_connector, active_attempt_id) {
|
||||
@ -132,7 +132,7 @@ impl Action {
|
||||
merchant_id: &id_type::MerchantId,
|
||||
payment_intent: &PaymentIntent,
|
||||
process: &storage::ProcessTracker,
|
||||
pcr_data: &storage::passive_churn_recovery::PcrPaymentData,
|
||||
pcr_data: &storage::revenue_recovery::PcrPaymentData,
|
||||
revenue_recovery_metadata: &PaymentRevenueRecoveryMetadata,
|
||||
) -> RecoveryResult<Self> {
|
||||
let db = &*state.store;
|
||||
@ -171,7 +171,7 @@ impl Action {
|
||||
state: &SessionState,
|
||||
payment_intent: &PaymentIntent,
|
||||
execute_task_process: &storage::ProcessTracker,
|
||||
pcr_data: &storage::passive_churn_recovery::PcrPaymentData,
|
||||
pcr_data: &storage::revenue_recovery::PcrPaymentData,
|
||||
revenue_recovery_metadata: &mut PaymentRevenueRecoveryMetadata,
|
||||
) -> Result<(), errors::ProcessTrackerError> {
|
||||
let db = &*state.store;
|
||||
@ -290,7 +290,7 @@ impl Action {
|
||||
async fn call_proxy_api(
|
||||
state: &SessionState,
|
||||
payment_intent: &PaymentIntent,
|
||||
pcr_data: &storage::passive_churn_recovery::PcrPaymentData,
|
||||
pcr_data: &storage::revenue_recovery::PcrPaymentData,
|
||||
revenue_recovery: &PaymentRevenueRecoveryMetadata,
|
||||
) -> RouterResult<PaymentConfirmData<api_types::Authorize>> {
|
||||
let operation = payments::operations::proxy_payments_intent::PaymentProxyIntent;
|
||||
@ -349,7 +349,7 @@ async fn call_proxy_api(
|
||||
pub async fn update_payment_intent_api(
|
||||
state: &SessionState,
|
||||
global_payment_id: id_type::GlobalPaymentId,
|
||||
pcr_data: &storage::passive_churn_recovery::PcrPaymentData,
|
||||
pcr_data: &storage::revenue_recovery::PcrPaymentData,
|
||||
update_req: PaymentsUpdateIntentRequest,
|
||||
) -> RouterResult<PaymentIntentData<api_types::PaymentUpdateIntent>> {
|
||||
// TODO : Use api handler instead of calling payments_intent_operation_core
|
||||
@ -15,8 +15,8 @@ use crate::{
|
||||
db::StorageInterface,
|
||||
routes::{app::ReqState, metrics, SessionState},
|
||||
services::{self, connector_integration_interface},
|
||||
types::{api, domain, storage::passive_churn_recovery as storage_churn_recovery},
|
||||
workflows::passive_churn_recovery_workflow,
|
||||
types::{api, domain, storage::revenue_recovery as storage_churn_recovery},
|
||||
workflows::revenue_recovery as revenue_recovery_flow,
|
||||
};
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
@ -466,22 +466,21 @@ impl RevenueRecoveryAttempt {
|
||||
.and_then(|feature_metadata| feature_metadata.get_retry_count())
|
||||
.unwrap_or(0);
|
||||
|
||||
let schedule_time =
|
||||
passive_churn_recovery_workflow::get_schedule_time_to_retry_mit_payments(
|
||||
db,
|
||||
&merchant_id,
|
||||
(total_retry_count + 1).into(),
|
||||
)
|
||||
.await
|
||||
.map_or_else(
|
||||
|| {
|
||||
Err(
|
||||
report!(errors::RevenueRecoveryError::ScheduleTimeFetchFailed)
|
||||
.attach_printable("Failed to get schedule time for pcr workflow"),
|
||||
)
|
||||
},
|
||||
Ok, // Simply returns `time` wrapped in `Ok`
|
||||
)?;
|
||||
let schedule_time = revenue_recovery_flow::get_schedule_time_to_retry_mit_payments(
|
||||
db,
|
||||
&merchant_id,
|
||||
(total_retry_count + 1).into(),
|
||||
)
|
||||
.await
|
||||
.map_or_else(
|
||||
|| {
|
||||
Err(
|
||||
report!(errors::RevenueRecoveryError::ScheduleTimeFetchFailed)
|
||||
.attach_printable("Failed to get schedule time for pcr workflow"),
|
||||
)
|
||||
},
|
||||
Ok, // Simply returns `time` wrapped in `Ok`
|
||||
)?;
|
||||
|
||||
let payment_attempt_id = payment_attempt_id
|
||||
.ok_or(report!(
|
||||
|
||||
@ -202,6 +202,11 @@ pub fn mk_app(
|
||||
.service(routes::WebhookEvents::server(state.clone()))
|
||||
.service(routes::FeatureMatrix::server(state.clone()));
|
||||
}
|
||||
|
||||
#[cfg(feature = "v2")]
|
||||
{
|
||||
server_app = server_app.service(routes::ProcessTracker::server(state.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "payouts", feature = "v1"))]
|
||||
|
||||
@ -65,6 +65,9 @@ pub mod recovery_webhooks;
|
||||
|
||||
pub mod relay;
|
||||
|
||||
#[cfg(feature = "olap")]
|
||||
pub mod process_tracker;
|
||||
|
||||
#[cfg(feature = "dummy_connector")]
|
||||
pub use self::app::DummyConnector;
|
||||
#[cfg(feature = "v2")]
|
||||
@ -75,7 +78,8 @@ pub use self::app::{
|
||||
ApiKeys, AppState, ApplePayCertificatesMigration, Cache, Cards, Configs, ConnectorOnboarding,
|
||||
Customers, Disputes, EphemeralKey, FeatureMatrix, Files, Forex, Gsm, Health, Hypersense,
|
||||
Mandates, MerchantAccount, MerchantConnectorAccount, PaymentLink, PaymentMethods, Payments,
|
||||
Poll, Profile, ProfileNew, Refunds, Relay, RelayWebhooks, SessionState, User, Webhooks,
|
||||
Poll, ProcessTracker, Profile, ProfileNew, Refunds, Relay, RelayWebhooks, SessionState, User,
|
||||
Webhooks,
|
||||
};
|
||||
#[cfg(feature = "olap")]
|
||||
pub use self::app::{Blocklist, Organization, Routing, Verify, WebhookEvents};
|
||||
|
||||
@ -2496,3 +2496,19 @@ impl FeatureMatrix {
|
||||
.service(web::resource("").route(web::get().to(feature_matrix::fetch_feature_matrix)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "olap")]
|
||||
pub struct ProcessTracker;
|
||||
|
||||
#[cfg(all(feature = "olap", feature = "v2"))]
|
||||
impl ProcessTracker {
|
||||
pub fn server(state: AppState) -> Scope {
|
||||
use super::process_tracker::revenue_recovery;
|
||||
web::scope("/v2/process_tracker/revenue_recovery_workflow")
|
||||
.app_data(web::Data::new(state.clone()))
|
||||
.service(
|
||||
web::resource("/{revenue_recovery_id}")
|
||||
.route(web::get().to(revenue_recovery::revenue_recovery_pt_retrieve_api)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,6 +42,7 @@ pub enum ApiIdentifier {
|
||||
CardNetworkTokenization,
|
||||
Hypersense,
|
||||
PaymentMethodSession,
|
||||
ProcessTracker,
|
||||
}
|
||||
|
||||
impl From<Flow> for ApiIdentifier {
|
||||
@ -333,6 +334,8 @@ impl From<Flow> for ApiIdentifier {
|
||||
| Flow::PaymentMethodSessionUpdateSavedPaymentMethod
|
||||
| Flow::PaymentMethodSessionDeleteSavedPaymentMethod
|
||||
| Flow::PaymentMethodSessionUpdate => Self::PaymentMethodSession,
|
||||
|
||||
Flow::RevenueRecoveryRetrieve => Self::ProcessTracker,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
2
crates/router/src/routes/process_tracker.rs
Normal file
2
crates/router/src/routes/process_tracker.rs
Normal file
@ -0,0 +1,2 @@
|
||||
#[cfg(feature = "v2")]
|
||||
pub mod revenue_recovery;
|
||||
39
crates/router/src/routes/process_tracker/revenue_recovery.rs
Normal file
39
crates/router/src/routes/process_tracker/revenue_recovery.rs
Normal file
@ -0,0 +1,39 @@
|
||||
use actix_web::{web, HttpRequest, HttpResponse};
|
||||
use api_models::process_tracker::revenue_recovery as revenue_recovery_api;
|
||||
use router_env::Flow;
|
||||
|
||||
use crate::{
|
||||
core::{api_locking, revenue_recovery},
|
||||
routes::AppState,
|
||||
services::{api, authentication as auth, authorization::permissions::Permission},
|
||||
};
|
||||
|
||||
pub async fn revenue_recovery_pt_retrieve_api(
|
||||
state: web::Data<AppState>,
|
||||
req: HttpRequest,
|
||||
path: web::Path<common_utils::id_type::GlobalPaymentId>,
|
||||
) -> HttpResponse {
|
||||
let flow = Flow::RevenueRecoveryRetrieve;
|
||||
let id = path.into_inner();
|
||||
let payload = revenue_recovery_api::RevenueRecoveryId {
|
||||
revenue_recovery_id: id,
|
||||
};
|
||||
|
||||
Box::pin(api::server_wrap(
|
||||
flow,
|
||||
state,
|
||||
&req,
|
||||
payload,
|
||||
|state, _: (), id, _| {
|
||||
revenue_recovery::retrieve_revenue_recovery_process_tracker(
|
||||
state,
|
||||
id.revenue_recovery_id,
|
||||
)
|
||||
},
|
||||
&auth::JWTAuth {
|
||||
permission: Permission::ProfileRevenueRecoveryRead,
|
||||
},
|
||||
api_locking::LockAction::NotApplicable,
|
||||
))
|
||||
.await
|
||||
}
|
||||
@ -167,11 +167,12 @@ pub static OPERATIONS: [Resource; 8] = [
|
||||
|
||||
pub static CONNECTORS: [Resource; 2] = [Resource::Connector, Resource::Account];
|
||||
|
||||
pub static WORKFLOWS: [Resource; 4] = [
|
||||
pub static WORKFLOWS: [Resource; 5] = [
|
||||
Resource::Routing,
|
||||
Resource::ThreeDsDecisionManager,
|
||||
Resource::SurchargeDecisionManager,
|
||||
Resource::Account,
|
||||
Resource::RevenueRecovery,
|
||||
];
|
||||
|
||||
pub static ANALYTICS: [Resource; 3] = [Resource::Analytics, Resource::Report, Resource::Account];
|
||||
|
||||
@ -95,6 +95,10 @@ generate_permissions! {
|
||||
scopes: [Read, Write],
|
||||
entities: [Merchant]
|
||||
},
|
||||
RevenueRecovery: {
|
||||
scopes: [Read],
|
||||
entities: [Profile]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -109,6 +113,7 @@ pub fn get_resource_name(resource: Resource, entity_type: EntityType) -> &'stati
|
||||
(Resource::ApiKey, _) => "Api Keys",
|
||||
(Resource::Connector, _) => "Payment Processors, Payout Processors, Fraud & Risk Managers",
|
||||
(Resource::Routing, _) => "Routing",
|
||||
(Resource::RevenueRecovery, _) => "Revenue Recovery",
|
||||
(Resource::ThreeDsDecisionManager, _) => "3DS Decision Manager",
|
||||
(Resource::SurchargeDecisionManager, _) => "Surcharge Decision Manager",
|
||||
(Resource::Analytics, _) => "Analytics",
|
||||
|
||||
@ -28,14 +28,14 @@ pub mod mandate;
|
||||
pub mod merchant_account;
|
||||
pub mod merchant_connector_account;
|
||||
pub mod merchant_key_store;
|
||||
#[cfg(feature = "v2")]
|
||||
pub mod passive_churn_recovery;
|
||||
pub mod payment_attempt;
|
||||
pub mod payment_link;
|
||||
pub mod payment_method;
|
||||
pub mod payout_attempt;
|
||||
pub mod payouts;
|
||||
pub mod refund;
|
||||
#[cfg(feature = "v2")]
|
||||
pub mod revenue_recovery;
|
||||
pub mod reverse_lookup;
|
||||
pub mod role;
|
||||
pub mod routing_algorithm;
|
||||
|
||||
@ -10,4 +10,4 @@ pub mod refund_router;
|
||||
|
||||
pub mod tokenized_data;
|
||||
|
||||
pub mod passive_churn_recovery_workflow;
|
||||
pub mod revenue_recovery;
|
||||
|
||||
@ -15,14 +15,14 @@ use scheduler::{types::process_data, utils as scheduler_utils};
|
||||
#[cfg(feature = "v2")]
|
||||
use crate::{
|
||||
core::{
|
||||
passive_churn_recovery::{self as pcr},
|
||||
payments,
|
||||
revenue_recovery::{self as pcr},
|
||||
},
|
||||
db::StorageInterface,
|
||||
errors::StorageError,
|
||||
types::{
|
||||
api::{self as api_types},
|
||||
storage::passive_churn_recovery as pcr_storage_types,
|
||||
storage::revenue_recovery as pcr_storage_types,
|
||||
},
|
||||
};
|
||||
use crate::{routes::SessionState, types::storage};
|
||||
@ -578,6 +578,8 @@ pub enum Flow {
|
||||
CardsInfoMigrate,
|
||||
///Total payment method count for merchant
|
||||
TotalPaymentMethodCount,
|
||||
/// Process Tracker Revenue Recovery Workflow Retrieve
|
||||
RevenueRecoveryRetrieve,
|
||||
}
|
||||
|
||||
/// Trait for providing generic behaviour to flow metric
|
||||
|
||||
Reference in New Issue
Block a user