refactor: Replace Bach with Application on every naming (#292)

This commit is contained in:
Kartikeya Hegde
2023-01-10 18:07:32 +05:30
committed by GitHub
parent aaf7088afc
commit 3cdf50c942
36 changed files with 218 additions and 209 deletions

View File

@ -1,12 +1,12 @@
use router::{
configs::settings::{CmdLineConf, Settings, Subcommand},
core::errors::{BachError, BachResult},
core::errors::{ApplicationError, ApplicationResult},
logger,
};
use structopt::StructOpt;
#[actix_web::main]
async fn main() -> BachResult<()> {
async fn main() -> ApplicationResult<()> {
// get commandline config before initializing config
let cmd_line = CmdLineConf::from_args();
@ -41,7 +41,7 @@ async fn main() -> BachResult<()> {
state.store.close().await;
Err(BachError::from(std::io::Error::new(
Err(ApplicationError::from(std::io::Error::new(
std::io::ErrorKind::Other,
"Server shut down",
)))

View File

@ -21,7 +21,7 @@ pub async fn compatibility_api_wrap<'a, 'b, U, T, Q, F, Fut, S, E>(
) -> HttpResponse
where
F: Fn(&'b routes::AppState, U, T) -> Fut,
Fut: Future<Output = RouterResult<api::BachResponse<Q>>>,
Fut: Future<Output = RouterResult<api::ApplicationResponse<Q>>>,
Q: Serialize + std::fmt::Debug + 'a,
S: From<Q> + Serialize,
E: From<errors::ApiErrorResponse> + Serialize + error_stack::Context + actix_web::ResponseError,
@ -29,7 +29,7 @@ where
{
let resp = api::server_wrap_util(state, request, payload, func, api_authentication).await;
match resp {
Ok(api::BachResponse::Json(router_resp)) => {
Ok(api::ApplicationResponse::Json(router_resp)) => {
let pg_resp = S::try_from(router_resp);
match pg_resp {
Ok(pg_resp) => match serde_json::to_string(&pg_resp) {
@ -51,9 +51,9 @@ where
),
}
}
Ok(api::BachResponse::StatusOk) => api::http_response_ok(),
Ok(api::BachResponse::TextPlain(text)) => api::http_response_plaintext(text),
Ok(api::BachResponse::JsonForRedirection(response)) => {
Ok(api::ApplicationResponse::StatusOk) => api::http_response_ok(),
Ok(api::ApplicationResponse::TextPlain(text)) => api::http_response_plaintext(text),
Ok(api::ApplicationResponse::JsonForRedirection(response)) => {
match serde_json::to_string(&response) {
Ok(res) => api::http_redirect_response(res, response),
Err(_) => api::http_response_err(
@ -65,7 +65,7 @@ where
),
}
}
Ok(api::BachResponse::Form(form_data)) => api::build_redirection_form(&form_data)
Ok(api::ApplicationResponse::Form(form_data)) => api::build_redirection_form(&form_data)
.respond_to(request)
.map_into_boxed_body(),
Err(error) => {

View File

@ -42,6 +42,10 @@ jwt_secret="secret"
[eph_key]
validity = 1
[refund]
max_attempts = 10
max_age = 365
[scheduler]
stream = "SCHEDULER_STREAM"
consumer_group = "SCHEDULER_GROUP"

View File

@ -7,7 +7,7 @@ use serde::Deserialize;
use structopt::StructOpt;
use crate::{
core::errors::{BachError, BachResult},
core::errors::{ApplicationError, ApplicationResult},
env::{self, logger, Env},
};
@ -42,6 +42,7 @@ pub struct Settings {
pub keys: Keys, //remove this during refactoring
pub locker: Locker,
pub connectors: Connectors,
pub refund: Refund,
pub eph_key: EphemeralConfig,
pub scheduler: Option<SchedulerSettings>,
#[cfg(feature = "kv_store")]
@ -67,6 +68,12 @@ pub struct Locker {
pub basilisk_host: String,
}
#[derive(Debug, Deserialize, Clone)]
pub struct Refund {
pub max_attempts: usize,
pub max_age: i64,
}
#[derive(Debug, Deserialize, Clone)]
pub struct EphemeralConfig {
pub validity: i64,
@ -163,11 +170,11 @@ pub struct DrainerSettings {
}
impl Settings {
pub fn new() -> BachResult<Self> {
pub fn new() -> ApplicationResult<Self> {
Self::with_config_path(None)
}
pub fn with_config_path(config_path: Option<PathBuf>) -> BachResult<Self> {
pub fn with_config_path(config_path: Option<PathBuf>) -> ApplicationResult<Self> {
let environment = env::which();
let config_path = router_env::Config::config_path(&environment.to_string(), config_path);
@ -199,7 +206,7 @@ impl Settings {
serde_path_to_error::deserialize(config).map_err(|error| {
logger::error!(%error, "Unable to deserialize application configuration");
eprintln!("Unable to deserialize application configuration: {error}");
BachError::from(error.into_inner())
ApplicationError::from(error.into_inner())
})
}
}

View File

@ -720,8 +720,9 @@ impl api::IncomingWebhook for Adyen {
fn get_webhook_api_response(
&self,
) -> CustomResult<services::api::BachResponse<serde_json::Value>, errors::ConnectorError> {
Ok(services::api::BachResponse::TextPlain(
) -> CustomResult<services::api::ApplicationResponse<serde_json::Value>, errors::ConnectorError>
{
Ok(services::api::ApplicationResponse::TextPlain(
"[accepted]".to_string(),
))
}

View File

@ -78,7 +78,7 @@ pub async fn create_merchant_account(
.map_err(|error| {
error.to_duplicate_response(errors::ApiErrorResponse::DuplicateMerchantAccount)
})?;
Ok(service_api::BachResponse::Json(response))
Ok(service_api::ApplicationResponse::Json(response))
}
pub async fn get_merchant_account(
@ -128,7 +128,7 @@ pub async fn get_merchant_account(
publishable_key: merchant_account.publishable_key,
locker_id: merchant_account.locker_id,
};
Ok(service_api::BachResponse::Json(response))
Ok(service_api::ApplicationResponse::Json(response))
}
pub async fn merchant_account_update(
@ -226,7 +226,7 @@ pub async fn merchant_account_update(
db.update_merchant(merchant_account, updated_merchant_account)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)?;
Ok(service_api::BachResponse::Json(response))
Ok(service_api::ApplicationResponse::Json(response))
}
pub async fn merchant_account_delete(
@ -243,7 +243,7 @@ pub async fn merchant_account_delete(
merchant_id,
deleted: is_deleted,
};
Ok(service_api::BachResponse::Json(response))
Ok(service_api::ApplicationResponse::Json(response))
}
async fn get_parent_merchant(
@ -340,7 +340,7 @@ pub async fn create_payment_connector(
})?;
response.merchant_connector_id = Some(mca.merchant_connector_id);
Ok(service_api::BachResponse::Json(response))
Ok(service_api::ApplicationResponse::Json(response))
}
pub async fn retrieve_payment_connector(
@ -365,7 +365,9 @@ pub async fn retrieve_payment_connector(
error.to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound)
})?;
Ok(service_api::BachResponse::Json(mca.foreign_try_into()?))
Ok(service_api::ApplicationResponse::Json(
mca.foreign_try_into()?,
))
}
pub async fn list_payment_connectors(
@ -393,7 +395,7 @@ pub async fn list_payment_connectors(
response.push(mca.foreign_try_into()?);
}
Ok(service_api::BachResponse::Json(response))
Ok(service_api::ApplicationResponse::Json(response))
}
pub async fn update_payment_connector(
@ -460,7 +462,7 @@ pub async fn update_payment_connector(
payment_methods_enabled: req.payment_methods_enabled,
metadata: req.metadata,
};
Ok(service_api::BachResponse::Json(response))
Ok(service_api::ApplicationResponse::Json(response))
}
pub async fn delete_payment_connector(
@ -489,5 +491,5 @@ pub async fn delete_payment_connector(
merchant_connector_id,
deleted: is_deleted,
};
Ok(service_api::BachResponse::Json(response))
Ok(service_api::ApplicationResponse::Json(response))
}

View File

@ -80,7 +80,7 @@ pub async fn create_customer(
let mut customer_response: customers::CustomerResponse = customer.into();
customer_response.address = customer_data.address;
Ok(services::BachResponse::Json(customer_response))
Ok(services::ApplicationResponse::Json(customer_response))
}
#[instrument(skip(db))]
@ -94,7 +94,7 @@ pub async fn retrieve_customer(
.await
.map_err(|error| error.to_not_found_response(errors::ApiErrorResponse::CustomerNotFound))?;
Ok(services::BachResponse::Json(response.into()))
Ok(services::ApplicationResponse::Json(response.into()))
}
#[instrument(skip_all)]
@ -190,7 +190,7 @@ pub async fn delete_customer(
address_deleted: true,
payment_methods_deleted: true,
};
Ok(services::BachResponse::Json(response))
Ok(services::ApplicationResponse::Json(response))
}
#[instrument(skip(db))]
@ -247,5 +247,7 @@ pub async fn update_customer(
let mut customer_update_response: customers::CustomerResponse = response.into();
customer_update_response.address = update_customer.address;
Ok(services::BachResponse::Json(customer_update_response))
Ok(services::ApplicationResponse::Json(
customer_update_response,
))
}

View File

@ -16,11 +16,10 @@ pub use self::api_error_response::ApiErrorResponse;
pub(crate) use self::utils::{ConnectorErrorExt, StorageErrorExt};
use crate::services;
pub type RouterResult<T> = CustomResult<T, ApiErrorResponse>;
pub type RouterResponse<T> = CustomResult<services::BachResponse<T>, ApiErrorResponse>;
pub type RouterResponse<T> = CustomResult<services::ApplicationResponse<T>, ApiErrorResponse>;
// FIXME: Phase out BachResult and BachResponse
pub type BachResult<T> = Result<T, BachError>;
pub type BachResponse<T> = BachResult<services::BachResponse<T>>;
pub type ApplicationResult<T> = Result<T, ApplicationError>;
pub type ApplicationResponse<T> = ApplicationResult<services::ApplicationResponse<T>>;
macro_rules! impl_error_display {
($st: ident, $arg: tt) => {
@ -50,7 +49,7 @@ macro_rules! impl_error_type {
// FIXME: Make this a derive macro instead
macro_rules! router_error_error_stack_specific {
($($path: ident)::+ < $st: ident >, $($path2:ident)::* ($($inner_path2:ident)::+ <$st2:ident>) ) => {
impl From<$($path)::+ <$st>> for BachError {
impl From<$($path)::+ <$st>> for ApplicationError {
fn from(err: $($path)::+ <$st> ) -> Self {
$($path2)::*(err)
}
@ -58,7 +57,7 @@ macro_rules! router_error_error_stack_specific {
};
($($path: ident)::+ <$($inner_path:ident)::+>, $($path2:ident)::* ($($inner_path2:ident)::+ <$st2:ident>) ) => {
impl<'a> From< $($path)::+ <$($inner_path)::+> > for BachError {
impl<'a> From< $($path)::+ <$($inner_path)::+> > for ApplicationError {
fn from(err: $($path)::+ <$($inner_path)::+> ) -> Self {
$($path2)::*(err)
}
@ -114,7 +113,7 @@ impl_error_type!(EncryptionError, "Encryption error");
impl_error_type!(UnexpectedError, "Unexpected error");
#[derive(Debug, thiserror::Error)]
pub enum BachError {
pub enum ApplicationError {
// Display's impl can be overridden by the attribute error marco.
// Don't use Debug here, Debug gives error stack in response.
#[error("{{ error_description: Error while Authenticating, error_message: {0} }}")]
@ -150,32 +149,32 @@ pub enum BachError {
router_error_error_stack_specific!(
error_stack::Report<storage_errors::DatabaseError>,
BachError::EDatabaseError(error_stack::Report<DatabaseError>)
ApplicationError::EDatabaseError(error_stack::Report<DatabaseError>)
);
router_error_error_stack_specific!(
error_stack::Report<AuthenticationError>,
BachError::EAuthenticationError(error_stack::Report<AuthenticationError>)
ApplicationError::EAuthenticationError(error_stack::Report<AuthenticationError>)
);
router_error_error_stack_specific!(
error_stack::Report<UnexpectedError>,
BachError::EUnexpectedError(error_stack::Report<UnexpectedError>)
ApplicationError::EUnexpectedError(error_stack::Report<UnexpectedError>)
);
router_error_error_stack_specific!(
error_stack::Report<ParsingError>,
BachError::EParsingError(error_stack::Report<ParsingError>)
ApplicationError::EParsingError(error_stack::Report<ParsingError>)
);
router_error_error_stack_specific!(
error_stack::Report<EncryptionError>,
BachError::EEncryptionError(error_stack::Report<EncryptionError>)
ApplicationError::EEncryptionError(error_stack::Report<EncryptionError>)
);
impl From<MetricsError> for BachError {
impl From<MetricsError> for ApplicationError {
fn from(err: MetricsError) -> Self {
Self::EMetrics(err)
}
}
impl From<std::io::Error> for BachError {
impl From<std::io::Error> for ApplicationError {
fn from(err: std::io::Error) -> Self {
Self::EIo(err)
}
@ -187,7 +186,7 @@ impl From<ring::error::Unspecified> for EncryptionError {
}
}
impl From<ConfigError> for BachError {
impl From<ConfigError> for ApplicationError {
fn from(err: ConfigError) -> Self {
Self::ConfigurationError(err)
}
@ -202,7 +201,7 @@ fn error_response<T: Display>(err: &T) -> actix_web::HttpResponse {
))
}
impl ResponseError for BachError {
impl ResponseError for ApplicationError {
fn status_code(&self) -> StatusCode {
match self {
Self::EParsingError(_)

View File

@ -30,7 +30,7 @@ pub async fn get_mandate(
.find_mandate_by_merchant_id_mandate_id(&merchant_account.merchant_id, &req.mandate_id)
.await
.map_err(|error| error.to_not_found_response(errors::ApiErrorResponse::MandateNotFound))?;
Ok(services::BachResponse::Json(
Ok(services::ApplicationResponse::Json(
mandates::MandateResponse::from_db_mandate(state, mandate, &merchant_account).await?,
))
}
@ -52,7 +52,7 @@ pub async fn revoke_mandate(
.await
.map_err(|error| error.to_not_found_response(errors::ApiErrorResponse::MandateNotFound))?;
Ok(services::BachResponse::Json(
Ok(services::ApplicationResponse::Json(
mandates::MandateRevokedResponse {
mandate_id: mandate.mandate_id,
status: mandate.mandate_status.foreign_into(),
@ -82,7 +82,7 @@ pub async fn get_customer_mandates(
.await?,
);
}
Ok(services::BachResponse::Json(response_vec))
Ok(services::ApplicationResponse::Json(response_vec))
}
}

View File

@ -92,7 +92,7 @@ pub async fn add_payment_method(
})
}
}
.map(services::BachResponse::Json)
.map(services::ApplicationResponse::Json)
}
#[instrument(skip_all)]
@ -383,7 +383,7 @@ pub async fn list_payment_methods(
response
.is_empty()
.then(|| Err(report!(errors::ApiErrorResponse::PaymentMethodNotFound)))
.unwrap_or(Ok(services::BachResponse::Json(response)))
.unwrap_or(Ok(services::ApplicationResponse::Json(response)))
}
fn filter_payment_methods(
@ -568,7 +568,7 @@ pub async fn list_customer_payment_method(
customer_payment_methods: vec,
};
Ok(services::BachResponse::Json(response))
Ok(services::ApplicationResponse::Json(response))
}
pub async fn get_lookup_key_from_locker(
@ -751,23 +751,27 @@ pub async fn retrieve_payment_method(
} else {
None
};
Ok(services::BachResponse::Json(api::PaymentMethodResponse {
merchant_id: pm.merchant_id,
customer_id: Some(pm.customer_id),
payment_method_id: pm.payment_method_id,
payment_method: pm.payment_method.foreign_into(),
payment_method_type: pm.payment_method_type.map(ForeignInto::foreign_into),
payment_method_issuer: pm.payment_method_issuer,
card,
metadata: pm.metadata,
created: Some(pm.created_at),
payment_method_issuer_code: pm.payment_method_issuer_code.map(ForeignInto::foreign_into),
recurring_enabled: false, //TODO
installment_payment_enabled: false, //TODO
payment_experience: Some(vec![
api_models::payment_methods::PaymentExperience::RedirectToUrl,
]), //TODO,
}))
Ok(services::ApplicationResponse::Json(
api::PaymentMethodResponse {
merchant_id: pm.merchant_id,
customer_id: Some(pm.customer_id),
payment_method_id: pm.payment_method_id,
payment_method: pm.payment_method.foreign_into(),
payment_method_type: pm.payment_method_type.map(ForeignInto::foreign_into),
payment_method_issuer: pm.payment_method_issuer,
card,
metadata: pm.metadata,
created: Some(pm.created_at),
payment_method_issuer_code: pm
.payment_method_issuer_code
.map(ForeignInto::foreign_into),
recurring_enabled: false, //TODO
installment_payment_enabled: false, //TODO
payment_experience: Some(vec![
api_models::payment_methods::PaymentExperience::RedirectToUrl,
]), //TODO,
},
))
}
#[instrument(skip_all)]
@ -801,7 +805,7 @@ pub async fn delete_payment_method(
}
};
Ok(services::BachResponse::Json(
Ok(services::ApplicationResponse::Json(
api::DeletePaymentMethodResponse {
payment_method_id: pm.payment_method_id,
deleted: true,

View File

@ -247,7 +247,7 @@ where
let payments_response =
match response.change_context(errors::ApiErrorResponse::NotImplemented)? {
services::BachResponse::Json(response) => Ok(response),
services::ApplicationResponse::Json(response) => Ok(response),
_ => Err(errors::ApiErrorResponse::InternalServerError)
.into_report()
.attach_printable("Failed to get the response in json"),
@ -261,7 +261,7 @@ where
)
.attach_printable("No redirection response")?;
Ok(services::BachResponse::JsonForRedirection(result))
Ok(services::ApplicationResponse::JsonForRedirection(result))
}
pub async fn payments_response_for_redirection_flows<'a>(
@ -562,10 +562,12 @@ pub async fn list_payments(
.into_iter()
.map(ForeignInto::foreign_into)
.collect();
Ok(services::BachResponse::Json(api::PaymentListResponse {
size: data.len(),
data,
}))
Ok(services::ApplicationResponse::Json(
api::PaymentListResponse {
size: data.len(),
data,
},
))
}
pub async fn add_process_sync_task(

View File

@ -547,7 +547,7 @@ pub(crate) async fn call_payment_method(
.await
.attach_printable("Error on adding payment method")?;
match resp {
crate::services::BachResponse::Json(payment_method) => {
crate::services::ApplicationResponse::Json(payment_method) => {
Ok(payment_method)
}
_ => Err(report!(errors::ApiErrorResponse::InternalServerError)
@ -575,7 +575,9 @@ pub(crate) async fn call_payment_method(
.await
.attach_printable("Error on adding payment method")?;
match resp {
crate::services::BachResponse::Json(payment_method) => Ok(payment_method),
crate::services::ApplicationResponse::Json(payment_method) => {
Ok(payment_method)
}
_ => Err(report!(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Error on adding payment method")),
}
@ -1156,7 +1158,7 @@ pub async fn make_ephemeral_key(
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Unable to create ephemeral key")?;
Ok(services::BachResponse::Json(ek))
Ok(services::ApplicationResponse::Json(ek))
}
pub async fn delete_ephemeral_key(
@ -1168,7 +1170,7 @@ pub async fn delete_ephemeral_key(
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Unable to delete ephemeral key")?;
Ok(services::BachResponse::Json(ek))
Ok(services::ApplicationResponse::Json(ek))
}
pub fn make_pg_redirect_response(

View File

@ -160,7 +160,7 @@ where
_server: &Server,
_operation: Op,
) -> RouterResponse<Self> {
Ok(services::BachResponse::Json(Self {
Ok(services::ApplicationResponse::Json(Self {
session_token: payment_data.sessions_token,
payment_id: payment_data.payment_attempt.payment_id,
client_secret: payment_data
@ -186,7 +186,7 @@ where
_server: &Server,
_operation: Op,
) -> RouterResponse<Self> {
Ok(services::BachResponse::Json(Self {
Ok(services::ApplicationResponse::Json(Self {
verify_id: Some(data.payment_intent.payment_id),
merchant_id: Some(data.payment_intent.merchant_id),
client_secret: data.payment_intent.client_secret.map(masking::Secret::new),
@ -254,7 +254,7 @@ where
let redirection_data = redirection_data.get_required_value("redirection_data")?;
let form: RedirectForm = serde_json::from_value(redirection_data)
.map_err(|_| errors::ApiErrorResponse::InternalServerError)?;
services::BachResponse::Form(form)
services::ApplicationResponse::Form(form)
} else {
let mut response: api::PaymentsResponse = request
.try_into()
@ -271,7 +271,7 @@ where
})
}
services::BachResponse::Json(
services::ApplicationResponse::Json(
response
.set_payment_id(Some(payment_attempt.payment_id))
.set_merchant_id(Some(payment_attempt.merchant_id))
@ -341,7 +341,7 @@ where
)
}
}
None => services::BachResponse::Json(api::PaymentsResponse {
None => services::ApplicationResponse::Json(api::PaymentsResponse {
payment_id: Some(payment_attempt.payment_id),
merchant_id: Some(payment_attempt.merchant_id),
status: payment_intent.status.foreign_into(),

View File

@ -2,9 +2,9 @@ pub mod validator;
use error_stack::{report, IntoReport, ResultExt};
use router_env::{instrument, tracing};
use uuid::Uuid;
use crate::{
consts,
core::{
errors::{self, ConnectorErrorExt, RouterResponse, RouterResult, StorageErrorExt},
payments, utils as core_utils,
@ -45,9 +45,9 @@ pub async fn refund_create_core(
.change_context(errors::ApiErrorResponse::SuccessfulPaymentNotFound)?;
// Amount is not passed in request refer from payment attempt.
amount = req.amount.unwrap_or(payment_attempt.amount); // FIXME: Need to that capture amount
amount = req.amount.unwrap_or(payment_attempt.amount); // [#298]: Need to that capture amount
//TODO: Can we change the flow based on some workflow idea
//[#299]: Can we change the flow based on some workflow idea
utils::when(amount <= 0, || {
Err(report!(errors::ApiErrorResponse::InvalidDataFormat {
field_name: "amount".to_string(),
@ -82,7 +82,7 @@ pub async fn refund_create_core(
req,
)
.await
.map(services::BachResponse::Json)
.map(services::ApplicationResponse::Json)
}
#[instrument(skip_all)]
@ -180,7 +180,7 @@ where
Fut: futures::Future<Output = RouterResult<T>>,
T: ForeignInto<refunds::RefundResponse>,
{
Ok(services::BachResponse::Json(
Ok(services::ApplicationResponse::Json(
f(state, merchant_account, refund_id).await?.foreign_into(),
))
}
@ -337,7 +337,7 @@ pub async fn refund_update_core(
.await
.change_context(errors::ApiErrorResponse::InternalServerError)?;
Ok(services::BachResponse::Json(response.foreign_into()))
Ok(services::ApplicationResponse::Json(response.foreign_into()))
}
// ********************************************** VALIDATIONS **********************************************
@ -402,37 +402,52 @@ pub async fn validate_and_create_refund(
.attach_printable("Failed to fetch refund")?;
currency = payment_attempt.currency.get_required_value("currency")?;
// TODO: Add Connector Based Validation here.
validator::validate_payment_order_age(&payment_intent.created_at).change_context(
errors::ApiErrorResponse::InvalidDataFormat {
field_name: "created_at".to_string(),
expected_format: format!(
"created_at not older than {} days",
validator::REFUND_MAX_AGE
),
},
)?;
//[#249]: Add Connector Based Validation here.
validator::validate_payment_order_age(
&payment_intent.created_at,
state.conf.refund.max_age,
)
.change_context(errors::ApiErrorResponse::InvalidDataFormat {
field_name: "created_at".to_string(),
expected_format: format!(
"created_at not older than {} days",
state.conf.refund.max_age,
),
})?;
validator::validate_refund_amount(payment_attempt.amount, &all_refunds, refund_amount)
.change_context(errors::ApiErrorResponse::RefundAmountExceedsPaymentAmount)?;
validator::validate_maximum_refund_against_payment_attempt(&all_refunds)
.change_context(errors::ApiErrorResponse::MaximumRefundCount)?;
validator::validate_maximum_refund_against_payment_attempt(
&all_refunds,
state.conf.refund.max_attempts,
)
.change_context(errors::ApiErrorResponse::MaximumRefundCount)?;
let connector = payment_attempt.connector.clone().ok_or_else(|| {
report!(errors::ApiErrorResponse::InternalServerError)
.attach_printable("connector not populated in payment attempt.")
})?;
refund_create_req = mk_new_refund(
req,
connector,
payment_attempt,
currency,
&refund_id,
&merchant_account.merchant_id,
refund_amount,
);
refund_create_req = storage::RefundNew::default()
.set_refund_id(refund_id.to_string())
.set_internal_reference_id(utils::generate_id(consts::ID_LENGTH, "refid"))
.set_external_reference_id(Some(refund_id))
.set_payment_id(req.payment_id)
.set_merchant_id(merchant_account.merchant_id.clone())
.set_connector_transaction_id(connecter_transaction_id.to_string())
.set_connector(connector)
.set_refund_type(enums::RefundType::RegularRefund)
.set_total_amount(refund_amount)
.set_currency(currency)
.set_created_at(Some(common_utils::date_time::now()))
.set_modified_at(Some(common_utils::date_time::now()))
.set_refund_status(enums::RefundStatus::Pending)
.set_metadata(req.metadata)
.set_description(req.reason.clone())
.set_attempt_id(payment_attempt.attempt_id.clone())
.set_refund_reason(req.reason)
.to_owned();
refund = db
.insert_refund(refund_create_req, merchant_account.storage_scheme)
@ -484,53 +499,11 @@ pub async fn refund_list(
utils::when(data.is_empty(), || {
Err(errors::ApiErrorResponse::RefundNotFound)
})?;
Ok(services::BachResponse::Json(
Ok(services::ApplicationResponse::Json(
api_models::refunds::RefundListResponse { data },
))
}
// ********************************************** UTILS **********************************************
// FIXME: function should not have more than 3 arguments.
// Consider to use builder pattern.
#[instrument]
fn mk_new_refund(
request: refunds::RefundRequest,
connector: String,
payment_attempt: &storage::PaymentAttempt,
currency: enums::Currency,
refund_id: &str,
merchant_id: &str,
refund_amount: i64,
) -> storage::RefundNew {
let current_time = common_utils::date_time::now();
let connecter_transaction_id = match &payment_attempt.connector_transaction_id {
Some(id) => id,
None => "",
};
storage::RefundNew {
refund_id: refund_id.to_string(),
internal_reference_id: Uuid::new_v4().to_string(),
external_reference_id: Some(refund_id.to_string()),
payment_id: request.payment_id,
merchant_id: merchant_id.to_string(),
// FIXME: remove the default.
connector_transaction_id: connecter_transaction_id.to_string(),
connector,
refund_type: enums::RefundType::RegularRefund,
total_amount: refund_amount,
currency,
refund_amount,
created_at: Some(current_time),
modified_at: Some(current_time),
refund_status: enums::RefundStatus::Pending,
metadata: request.metadata,
description: request.reason,
attempt_id: payment_attempt.attempt_id.clone(),
..storage::RefundNew::default()
}
}
impl<F> TryFrom<types::RefundsRouterData<F>> for refunds::RefundResponse {
type Error = error_stack::Report<errors::ApiErrorResponse>;
@ -548,7 +521,7 @@ impl<F> TryFrom<types::RefundsRouterData<F>> for refunds::RefundResponse {
refund_id,
amount: data.request.amount / 100,
currency: data.request.currency.to_string(),
reason: Some("TODO: Not propagated".to_string()), // TODO: Not propagated
reason: data.request.reason,
status,
metadata: None,
error_message,
@ -622,7 +595,7 @@ pub async fn schedule_refund_execution(
}
_ => {
// Sync the refund for status check
//TODO: return refund status response
//[#300]: return refund status response
match refund_type {
api_models::refunds::RefundType::Scheduled => {
add_refund_sync_task(db, &refund, runner)
@ -661,25 +634,6 @@ pub async fn sync_refund_with_gateway_workflow(
)
})?;
let merchant_account = state
.store
.find_merchant_account_by_merchant_id(&refund_core.merchant_id)
.await
.map_err(|error| {
error.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)
})?;
// FIXME we actually don't use this?
let _refund = state
.store
.find_refund_by_internal_reference_id_merchant_id(
&refund_core.refund_internal_reference_id,
&refund_core.merchant_id,
merchant_account.storage_scheme,
)
.await
.map_err(|error| error.to_not_found_response(errors::ApiErrorResponse::RefundNotFound))?;
let merchant_account = state
.store
.find_merchant_account_by_merchant_id(&refund_core.merchant_id)
@ -763,7 +717,6 @@ pub async fn trigger_refund_execute_workflow(
.await
.map_err(|error| error.to_not_found_response(errors::ApiErrorResponse::RefundNotFound))?;
match (&refund.sent_to_gateway, &refund.refund_status) {
//FIXME: Conversion should come from trait
(false, enums::RefundStatus::Pending) => {
let merchant_account = db
.find_merchant_account_by_merchant_id(&refund.merchant_id)

View File

@ -10,9 +10,6 @@ use crate::{
utils,
};
pub(super) const REFUND_MAX_AGE: i64 = 365;
pub(super) const REFUND_MAX_ATTEMPTS: usize = 10;
#[derive(Debug, thiserror::Error)]
pub enum RefundValidationError {
#[error("The payment attempt was not successful")]
@ -38,7 +35,6 @@ pub fn validate_success_transaction(
Ok(())
}
//todo: max refund request count
#[instrument(skip_all)]
pub fn validate_refund_amount(
payment_attempt_amount: i64, // &storage::PaymentAttempt,
@ -71,11 +67,12 @@ pub fn validate_refund_amount(
#[instrument(skip_all)]
pub fn validate_payment_order_age(
created_at: &PrimitiveDateTime,
refund_max_age: i64,
) -> CustomResult<(), RefundValidationError> {
let current_time = common_utils::date_time::now();
utils::when(
(current_time - *created_at).whole_days() > REFUND_MAX_AGE,
(current_time - *created_at).whole_days() > refund_max_age,
|| Err(report!(RefundValidationError::OrderExpired)),
)
}
@ -83,9 +80,9 @@ pub fn validate_payment_order_age(
#[instrument(skip_all)]
pub fn validate_maximum_refund_against_payment_attempt(
all_refunds: &[storage::Refund],
refund_max_attempts: usize,
) -> CustomResult<(), RefundValidationError> {
// TODO: Make this configurable
utils::when(all_refunds.len() > REFUND_MAX_ATTEMPTS, || {
utils::when(all_refunds.len() > refund_max_attempts, || {
Err(report!(RefundValidationError::MaxRefundCountReached))
})
}

View File

@ -28,7 +28,6 @@ pub async fn construct_refund_router_data<'a, F>(
refund: &'a storage::Refund,
) -> RouterResult<types::RefundsRouterData<F>> {
let db = &*state.store;
//TODO: everytime parsing the json may have impact?
let merchant_connector_account = db
.find_merchant_connector_account_by_merchant_id_connector(
&merchant_account.merchant_id,
@ -86,6 +85,7 @@ pub async fn construct_refund_router_data<'a, F>(
refund_amount: refund.refund_amount,
currency,
amount,
reason: refund.refund_reason.clone(),
},
response: Ok(types::RefundsResponseData {

View File

@ -59,7 +59,7 @@ async fn payments_incoming_webhook_flow(
.change_context(errors::WebhooksFlowError::PaymentsCoreFailed)?;
match payments_response {
services::BachResponse::Json(payments_response) => {
services::ApplicationResponse::Json(payments_response) => {
let payment_id = payments_response
.payment_id
.clone()

View File

@ -290,6 +290,7 @@ mod storage {
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(),
refund_reason: new.refund_reason.clone(),
};
let field = format!(
@ -640,6 +641,7 @@ impl RefundInterface for MockDb {
created_at: new.created_at.unwrap_or(current_time),
updated_at: current_time,
description: new.description,
refund_reason: new.refund_reason.clone(),
};
refunds.push(refund.clone());
Ok(refund)

View File

@ -32,7 +32,7 @@ use routes::AppState;
pub use self::env::logger;
use crate::{
configs::settings::Settings,
core::errors::{self, BachResult},
core::errors::{self, ApplicationResult},
};
#[cfg(feature = "mimalloc")]
@ -110,7 +110,7 @@ pub fn mk_app(
/// # Panics
///
/// Unwrap used because without the value we can't start the server
pub async fn start_server(conf: Settings) -> BachResult<(Server, AppState)> {
pub async fn start_server(conf: Settings) -> ApplicationResult<(Server, AppState)> {
logger::debug!(startup_config=?conf);
let server = conf.server.clone();
let state = routes::AppState::new(conf).await;

View File

@ -320,7 +320,7 @@ async fn handle_response(
}
#[derive(Debug, Eq, PartialEq)]
pub enum BachResponse<R> {
pub enum ApplicationResponse<R> {
Json(R),
StatusOk,
TextPlain(String),
@ -329,11 +329,11 @@ pub enum BachResponse<R> {
}
#[derive(Debug, Eq, PartialEq, Serialize)]
pub struct BachRedirectResponse {
pub struct ApplicationRedirectResponse {
pub url: String,
}
impl From<&storage::PaymentAttempt> for BachRedirectResponse {
impl From<&storage::PaymentAttempt> for ApplicationRedirectResponse {
fn from(payment_attempt: &storage::PaymentAttempt) -> Self {
Self {
url: format!(
@ -376,7 +376,7 @@ pub async fn server_wrap_util<'a, 'b, U, T, Q, F, Fut>(
payload: T,
func: F,
api_auth: &dyn auth::AuthenticateAndFetch<U>,
) -> RouterResult<BachResponse<Q>>
) -> RouterResult<ApplicationResponse<Q>>
where
F: Fn(&'b AppState, U, T) -> Fut,
Fut: Future<Output = RouterResponse<Q>>,
@ -402,7 +402,7 @@ pub async fn server_wrap<'a, 'b, T, U, Q, F, Fut>(
) -> HttpResponse
where
F: Fn(&'b AppState, U, T) -> Fut,
Fut: Future<Output = RouterResult<BachResponse<Q>>>,
Fut: Future<Output = RouterResult<ApplicationResponse<Q>>>,
Q: Serialize + Debug + 'a,
T: Debug,
{
@ -415,7 +415,7 @@ where
logger::info!(tag = ?Tag::BeginRequest);
let res = match server_wrap_util(state, request, payload, func, api_auth).await {
Ok(BachResponse::Json(response)) => match serde_json::to_string(&response) {
Ok(ApplicationResponse::Json(response)) => match serde_json::to_string(&response) {
Ok(res) => http_response_json(res),
Err(_) => http_response_err(
r#"{
@ -425,19 +425,21 @@ where
}"#,
),
},
Ok(BachResponse::StatusOk) => http_response_ok(),
Ok(BachResponse::TextPlain(text)) => http_response_plaintext(text),
Ok(BachResponse::JsonForRedirection(response)) => match serde_json::to_string(&response) {
Ok(res) => http_redirect_response(res, response),
Err(_) => http_response_err(
r#"{
Ok(ApplicationResponse::StatusOk) => http_response_ok(),
Ok(ApplicationResponse::TextPlain(text)) => http_response_plaintext(text),
Ok(ApplicationResponse::JsonForRedirection(response)) => {
match serde_json::to_string(&response) {
Ok(res) => http_redirect_response(res, response),
Err(_) => http_response_err(
r#"{
"error": {
"message": "Error serializing response from connector"
}
}"#,
),
},
Ok(BachResponse::Form(response)) => build_redirection_form(&response)
),
}
}
Ok(ApplicationResponse::Form(response)) => build_redirection_form(&response)
.respond_to(request)
.map_into_boxed_body(),

View File

@ -200,6 +200,7 @@ pub struct RefundsData {
pub currency: storage_enums::Currency,
/// Amount for the payment against which this refund is issued
pub amount: i64,
pub reason: Option<String>,
/// Amount to be refunded
pub refund_amount: i64,
}

View File

@ -136,7 +136,8 @@ pub trait IncomingWebhook: ConnectorCommon + Sync {
fn get_webhook_api_response(
&self,
) -> CustomResult<services::api::BachResponse<serde_json::Value>, errors::ConnectorError> {
Ok(services::api::BachResponse::StatusOk)
) -> CustomResult<services::api::ApplicationResponse<serde_json::Value>, errors::ConnectorError>
{
Ok(services::api::ApplicationResponse::StatusOk)
}
}