fix: todos and fixmes resolution for api_models (#144)

This commit is contained in:
Nishant Joshi
2022-12-14 17:49:48 +05:30
committed by GitHub
parent 041654eabc
commit 1f0d1deb2b
17 changed files with 117 additions and 80 deletions

View File

@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
pub use self::CreateMerchantAccount as MerchantAccountResponse; pub use self::CreateMerchantAccount as MerchantAccountResponse;
use super::payments::AddressDetails; use super::payments::AddressDetails;
use crate::enums as api_enums; use crate::{enums as api_enums, payment_methods};
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
@ -55,7 +55,7 @@ pub struct WebhookDetails {
#[derive(Default, Clone, Debug, Deserialize, Serialize)] #[derive(Default, Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct CustomRoutingRules { pub struct CustomRoutingRules {
pub payment_methods_incl: Option<Vec<api_enums::PaymentMethodType>>, //FIXME Add enums for all PM enums pub payment_methods_incl: Option<Vec<api_enums::PaymentMethodType>>,
pub payment_methods_excl: Option<Vec<api_enums::PaymentMethodType>>, pub payment_methods_excl: Option<Vec<api_enums::PaymentMethodType>>,
pub payment_method_types_incl: Option<Vec<api_enums::PaymentMethodSubType>>, pub payment_method_types_incl: Option<Vec<api_enums::PaymentMethodSubType>>,
pub payment_method_types_excl: Option<Vec<api_enums::PaymentMethodSubType>>, pub payment_method_types_excl: Option<Vec<api_enums::PaymentMethodSubType>>,
@ -115,7 +115,7 @@ pub struct PaymentMethods {
pub maximum_amount: Option<i32>, pub maximum_amount: Option<i32>,
pub recurring_enabled: bool, pub recurring_enabled: bool,
pub installment_payment_enabled: bool, pub installment_payment_enabled: bool,
pub payment_experience: Option<Vec<String>>, //TODO pub payment_experience: Option<Vec<payment_methods::PaymentExperience>>,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]

View File

@ -33,14 +33,9 @@ pub struct PaymentMethodResponse {
pub payment_method_issuer: Option<String>, pub payment_method_issuer: Option<String>,
pub payment_method_issuer_code: Option<api_enums::PaymentMethodIssuerCode>, pub payment_method_issuer_code: Option<api_enums::PaymentMethodIssuerCode>,
pub card: Option<CardDetailFromLocker>, pub card: Option<CardDetailFromLocker>,
//TODO: Populate this on request?
// pub accepted_country: Option<Vec<String>>,
// pub accepted_currency: Option<Vec<enums::Currency>>,
// pub minimum_amount: Option<i32>,
// pub maximum_amount: Option<i32>,
pub recurring_enabled: bool, pub recurring_enabled: bool,
pub installment_payment_enabled: bool, pub installment_payment_enabled: bool,
pub payment_experience: Option<Vec<String>>, //TODO change it to enum pub payment_experience: Option<Vec<PaymentExperience>>,
pub metadata: Option<serde_json::Value>, pub metadata: Option<serde_json::Value>,
#[serde(default, with = "common_utils::custom_serde::iso8601::option")] #[serde(default, with = "common_utils::custom_serde::iso8601::option")]
pub created: Option<time::PrimitiveDateTime>, pub created: Option<time::PrimitiveDateTime>,
@ -174,7 +169,7 @@ pub struct ListPaymentMethodResponse {
pub maximum_amount: Option<i32>, pub maximum_amount: Option<i32>,
pub recurring_enabled: bool, pub recurring_enabled: bool,
pub installment_payment_enabled: bool, pub installment_payment_enabled: bool,
pub payment_experience: Option<Vec<String>>, //TODO change it to enum pub payment_experience: Option<Vec<PaymentExperience>>,
} }
#[derive(Debug, serde::Serialize)] #[derive(Debug, serde::Serialize)]
@ -197,20 +192,27 @@ pub struct CustomerPaymentMethod {
pub payment_method_type: Option<api_enums::PaymentMethodSubType>, pub payment_method_type: Option<api_enums::PaymentMethodSubType>,
pub payment_method_issuer: Option<String>, pub payment_method_issuer: Option<String>,
pub payment_method_issuer_code: Option<api_enums::PaymentMethodIssuerCode>, pub payment_method_issuer_code: Option<api_enums::PaymentMethodIssuerCode>,
//TODO: Populate this on request?
// pub accepted_country: Option<Vec<String>>,
// pub accepted_currency: Option<Vec<enums::Currency>>,
// pub minimum_amount: Option<i32>,
// pub maximum_amount: Option<i32>,
pub recurring_enabled: bool, pub recurring_enabled: bool,
pub installment_payment_enabled: bool, pub installment_payment_enabled: bool,
pub payment_experience: Option<Vec<String>>, //TODO change it to enum pub payment_experience: Option<Vec<PaymentExperience>>,
pub card: Option<CardDetailFromLocker>, pub card: Option<CardDetailFromLocker>,
pub metadata: Option<serde_json::Value>, pub metadata: Option<serde_json::Value>,
#[serde(default, with = "common_utils::custom_serde::iso8601::option")] #[serde(default, with = "common_utils::custom_serde::iso8601::option")]
pub created: Option<time::PrimitiveDateTime>, pub created: Option<time::PrimitiveDateTime>,
} }
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum PaymentExperience {
RedirectToUrl,
InvokeSdkClient,
DisplayQrCode,
OneClick,
LinkWallet,
InvokePaymentApp,
}
#[derive(Debug, serde::Serialize, serde::Deserialize)] #[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct PaymentMethodId { pub struct PaymentMethodId {
pub payment_method_id: String, pub payment_method_id: String,
@ -243,7 +245,7 @@ pub struct DeleteTokenizeByTokenRequest {
pub lookup_key: String, pub lookup_key: String,
} }
#[derive(Debug, serde::Serialize)] //FIXME yet to be implemented #[derive(Debug, serde::Serialize)] // Blocked: Yet to be implemented by `basilisk`
pub struct DeleteTokenizeByDateRequest { pub struct DeleteTokenizeByDateRequest {
pub buffer_minutes: i32, pub buffer_minutes: i32,
pub service_name: String, pub service_name: String,

View File

@ -399,7 +399,7 @@ pub struct PaymentsResponse {
pub statement_descriptor_suffix: Option<String>, pub statement_descriptor_suffix: Option<String>,
pub next_action: Option<NextAction>, pub next_action: Option<NextAction>,
pub cancellation_reason: Option<String>, pub cancellation_reason: Option<String>,
pub error_code: Option<String>, //TODO: Add error code column to the database pub error_code: Option<String>,
pub error_message: Option<String>, pub error_message: Option<String>,
} }

View File

@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
use crate::enums; use crate::enums;
#[derive(Default, Debug, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone, Deserialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct RefundRequest { pub struct RefundRequest {
pub refund_id: Option<String>, pub refund_id: Option<String>,
@ -10,11 +10,18 @@ pub struct RefundRequest {
pub merchant_id: Option<String>, pub merchant_id: Option<String>,
pub amount: Option<i32>, pub amount: Option<i32>,
pub reason: Option<String>, pub reason: Option<String>,
//FIXME: Make it refund_type instant or scheduled refund pub refund_type: Option<RefundType>,
pub force_process: Option<bool>,
pub metadata: Option<serde_json::Value>, pub metadata: Option<serde_json::Value>,
} }
#[derive(Default, Debug, Clone, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RefundType {
#[default]
Scheduled,
Instant,
}
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
pub struct RefundResponse { pub struct RefundResponse {
pub refund_id: String, pub refund_id: String,

View File

@ -14,20 +14,20 @@ This solution has such advantages over alternatives:
To convert non-secret variable into secret use `new()`. Sample: To convert non-secret variable into secret use `new()`. Sample:
```rust,ignore ```rust
expiry_year: ccard.map(|x| Secret::new(x.card_exp_year.to_string())), expiry_year: ccard.map(|x| Secret::new(x.card_exp_year.to_string())),
// output: "expiry_year: *** alloc::string::String ***" // output: "expiry_year: *** alloc::string::String ***"
``` ```
To get value from secret use `expose()`. Sample: To get value from secret use `expose()`. Sample:
```rust,ignore ```rust
last4_digits: Some(card_number.expose()) last4_digits: Some(card_number.expose())
``` ```
Most fields are under `Option`. To simplify dealing with `Option`, use `expose_option()`. Sample: Most fields are under `Option`. To simplify dealing with `Option`, use `expose_option()`. Sample:
```rust,ignore ```rust
card_info.push_str( card_info.push_str(
&card_detail &card_detail
.card_holder_name .card_holder_name
@ -36,17 +36,17 @@ Most fields are under `Option`. To simplify dealing with `Option`, use `expose_o
); );
``` ```
<!-- ## Files Tree Layout -->
<!-- FIXME: this table should either be generated by a script or smoke test should be introduced checking it agrees with actual structure --> <!-- FIXME: this table should either be generated by a script or smoke test should be introduced checking it agrees with actual structure -->
<!-- FIXME: fill missing --> ## Files Tree Layout
<!-- ```text
├── src : source code ```bash
└── tests : unit and integration tests .
├── src # : source code
└── tests # : unit and integration tests
``` --> ```
<!-- <!--
command to generate the tree `tree -L 3 -d` command to generate the tree `tree -L 3 -d`

View File

@ -40,18 +40,3 @@ where
self.inner_secret self.inner_secret
} }
} }
// impl<S> ExposeInterface<Option<&S>> for Option<Secret<S>>
// where
// S: ZeroizableSecret,
// Secret<S> : ExposeInterface<S>,
// {
// fn expose(&self) -> &Option<&S> {
// if let Some( ref val ) = self {
// &Some( val.peek() )
// } else {
// &None
// }
// // &None
// }
// }

View File

@ -81,7 +81,9 @@ pub async fn add_payment_method(
payment_method_issuer_code: req.payment_method_issuer_code, payment_method_issuer_code: req.payment_method_issuer_code,
recurring_enabled: false, //TODO recurring_enabled: false, //TODO
installment_payment_enabled: false, //TODO installment_payment_enabled: false, //TODO
payment_experience: Some(vec!["redirect_to_url".to_string()]), //TODO payment_experience: Some(vec![
api_models::payment_methods::PaymentExperience::RedirectToUrl,
]), //TODO
}) })
} }
} }
@ -485,7 +487,9 @@ pub async fn list_customer_payment_method(
.map(ForeignInto::foreign_into), .map(ForeignInto::foreign_into),
recurring_enabled: false, recurring_enabled: false,
installment_payment_enabled: false, installment_payment_enabled: false,
payment_experience: Some(vec!["redirect_to_url".to_string()]), //TODO chnage to enum payment_experience: Some(vec![
api_models::payment_methods::PaymentExperience::RedirectToUrl,
]),
created: Some(pm.created_at), created: Some(pm.created_at),
}; };
vec.push(pma); vec.push(pma);
@ -674,9 +678,11 @@ pub async fn retrieve_payment_method(
metadata: None, // TODO add in addCard api metadata: None, // TODO add in addCard api
created: Some(pm.created_at), created: Some(pm.created_at),
payment_method_issuer_code: pm.payment_method_issuer_code.map(ForeignInto::foreign_into), payment_method_issuer_code: pm.payment_method_issuer_code.map(ForeignInto::foreign_into),
recurring_enabled: false, //TODO recurring_enabled: false, //TODO
installment_payment_enabled: false, //TODO installment_payment_enabled: false, //TODO
payment_experience: Some(vec!["redirect_to_url".to_string()]), //TODO, payment_experience: Some(vec![
api_models::payment_methods::PaymentExperience::RedirectToUrl,
]), //TODO,
})) }))
} }

View File

@ -114,9 +114,11 @@ pub fn mk_add_card_response(
metadata: req.metadata, metadata: req.metadata,
created: Some(common_utils::date_time::now()), created: Some(common_utils::date_time::now()),
payment_method_issuer_code: req.payment_method_issuer_code, payment_method_issuer_code: req.payment_method_issuer_code,
recurring_enabled: false, //TODO recurring_enabled: false, //TODO
installment_payment_enabled: false, //TODO installment_payment_enabled: false, //TODO
payment_experience: Some(vec!["redirect_to_url".to_string()]), //TODO, payment_experience: Some(vec![
api_models::payment_methods::PaymentExperience::RedirectToUrl,
]), //TODO,
} }
} }

View File

@ -177,6 +177,7 @@ async fn payment_response_update_tracker<F: Clone, T>(
connector: Some(router_data.connector.clone()), connector: Some(router_data.connector.clone()),
status: storage::enums::AttemptStatus::Failure, status: storage::enums::AttemptStatus::Failure,
error_message: Some(err.message), error_message: Some(err.message),
error_code: Some(err.code),
}), }),
Some(storage::ConnectorResponseUpdate::ErrorUpdate { Some(storage::ConnectorResponseUpdate::ErrorUpdate {
connector_name: Some(router_data.connector.clone()), connector_name: Some(router_data.connector.clone()),

View File

@ -356,6 +356,7 @@ where
.capture_method .capture_method
.map(ForeignInto::foreign_into), .map(ForeignInto::foreign_into),
error_message: payment_attempt.error_message, error_message: payment_attempt.error_message,
error_code: payment_attempt.error_code,
payment_method_data: payment_method_data.map(api::PaymentMethodDataResponse::from), payment_method_data: payment_method_data.map(api::PaymentMethodDataResponse::from),
email: customer email: customer
.as_ref() .as_ref()

View File

@ -346,7 +346,7 @@ pub async fn validate_and_create_refund(
let (refund_id, all_refunds, currency, refund_create_req, refund); let (refund_id, all_refunds, currency, refund_create_req, refund);
// Only for initial dev and testing // Only for initial dev and testing
let force_process = req.force_process.unwrap_or(false); let refund_type = req.refund_type.clone().unwrap_or_default();
// If Refund Id not passed in request Generate one. // If Refund Id not passed in request Generate one.
@ -435,7 +435,7 @@ pub async fn validate_and_create_refund(
schedule_refund_execution( schedule_refund_execution(
state, state,
refund, refund,
force_process, // *force_process, refund_type,
merchant_account, merchant_account,
payment_attempt, payment_attempt,
payment_intent, payment_intent,
@ -535,8 +535,7 @@ impl From<Foreign<storage::Refund>> for Foreign<api::RefundResponse> {
pub async fn schedule_refund_execution( pub async fn schedule_refund_execution(
state: &AppState, state: &AppState,
refund: storage::Refund, refund: storage::Refund,
//FIXME: change to refund_Type here refund_type: api_models::refunds::RefundType,
force_process: bool,
merchant_account: &storage::merchant_account::MerchantAccount, merchant_account: &storage::merchant_account::MerchantAccount,
payment_attempt: &storage::PaymentAttempt, payment_attempt: &storage::PaymentAttempt,
payment_intent: &storage::PaymentIntent, payment_intent: &storage::PaymentIntent,
@ -556,34 +555,43 @@ pub async fn schedule_refund_execution(
enums::RefundStatus::Pending | enums::RefundStatus::ManualReview => { enums::RefundStatus::Pending | enums::RefundStatus::ManualReview => {
match (refund.sent_to_gateway, refund_process) { match (refund.sent_to_gateway, refund_process) {
(false, None) => { (false, None) => {
//execute // Execute the refund task based on refund_type
if force_process { match refund_type {
trigger_refund_to_gateway( api_models::refunds::RefundType::Scheduled => {
state, add_refund_execute_task(db, &refund, runner)
&refund, .await
merchant_account, .change_context(errors::ApiErrorResponse::InternalServerError)?;
payment_attempt,
payment_intent, Ok(refund)
) }
.await api_models::refunds::RefundType::Instant => {
} else { trigger_refund_to_gateway(
add_refund_execute_task(db, &refund, runner) state,
&refund,
merchant_account,
payment_attempt,
payment_intent,
)
.await .await
.change_context(errors::ApiErrorResponse::InternalServerError)?; }
Ok(refund)
} }
} }
_ => { _ => {
//sync status // Sync the refund for status check
//TODO: return refund status response //TODO: return refund status response
if force_process { match refund_type {
// sync_refund_with_gateway(data, &refund).await api_models::refunds::RefundType::Scheduled => {
Ok(refund) add_refund_sync_task(db, &refund, runner)
} else { .await
add_refund_sync_task(db, &refund, runner) .change_context(errors::ApiErrorResponse::InternalServerError)?;
.await Ok(refund)
.change_context(errors::ApiErrorResponse::InternalServerError)?; }
Ok(refund) api_models::refunds::RefundType::Instant => {
// FIXME: This is not possible in schedule_refund_execution as it will always be scheduled
// FIXME: as a part of refactoring
// sync_refund_with_gateway(data, &refund).await
Ok(refund)
}
} }
} }
} }

View File

@ -240,6 +240,7 @@ impl PaymentAttemptInterface for MockDb {
amount_to_capture: payment_attempt.amount_to_capture, amount_to_capture: payment_attempt.amount_to_capture,
mandate_id: None, mandate_id: None,
browser_info: None, browser_info: None,
error_code: payment_attempt.error_code,
}; };
payment_attempts.push(payment_attempt.clone()); payment_attempts.push(payment_attempt.clone());
Ok(payment_attempt) Ok(payment_attempt)
@ -370,6 +371,7 @@ mod storage {
cancellation_reason: payment_attempt.cancellation_reason.clone(), cancellation_reason: payment_attempt.cancellation_reason.clone(),
mandate_id: payment_attempt.mandate_id.clone(), mandate_id: payment_attempt.mandate_id.clone(),
browser_info: payment_attempt.browser_info.clone(), browser_info: payment_attempt.browser_info.clone(),
error_code: payment_attempt.error_code.clone(),
}; };
match self match self

View File

@ -110,6 +110,16 @@ impl From<F<storage_enums::ConnectorType>> for F<api_enums::ConnectorType> {
} }
} }
impl From<F<api_models::refunds::RefundType>> for F<storage_enums::RefundType> {
fn from(item: F<api_models::refunds::RefundType>) -> Self {
match item.0 {
api_models::refunds::RefundType::Instant => storage_enums::RefundType::InstantRefund,
api_models::refunds::RefundType::Scheduled => storage_enums::RefundType::RegularRefund,
}
.into()
}
}
impl From<F<storage_enums::MandateStatus>> for F<api_enums::MandateStatus> { impl From<F<storage_enums::MandateStatus>> for F<api_enums::MandateStatus> {
fn from(status: F<storage_enums::MandateStatus>) -> Self { fn from(status: F<storage_enums::MandateStatus>) -> Self {
Foreign(frunk::labelled_convert_from(status.0)) Foreign(frunk::labelled_convert_from(status.0))

View File

@ -36,6 +36,7 @@ pub struct PaymentAttempt {
pub amount_to_capture: Option<i32>, pub amount_to_capture: Option<i32>,
pub mandate_id: Option<String>, pub mandate_id: Option<String>,
pub browser_info: Option<serde_json::Value>, pub browser_info: Option<serde_json::Value>,
pub error_code: Option<String>,
} }
#[derive(Clone, Debug, Default, Insertable, router_derive::DebugAsDisplay)] #[derive(Clone, Debug, Default, Insertable, router_derive::DebugAsDisplay)]
@ -70,6 +71,7 @@ pub struct PaymentAttemptNew {
pub amount_to_capture: Option<i32>, pub amount_to_capture: Option<i32>,
pub mandate_id: Option<String>, pub mandate_id: Option<String>,
pub browser_info: Option<serde_json::Value>, pub browser_info: Option<serde_json::Value>,
pub error_code: Option<String>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -109,6 +111,7 @@ pub enum PaymentAttemptUpdate {
ErrorUpdate { ErrorUpdate {
connector: Option<String>, connector: Option<String>,
status: storage_enums::AttemptStatus, status: storage_enums::AttemptStatus,
error_code: Option<String>,
error_message: Option<String>, error_message: Option<String>,
}, },
} }
@ -130,6 +133,7 @@ pub struct PaymentAttemptUpdateInternal {
redirect: Option<bool>, redirect: Option<bool>,
mandate_id: Option<String>, mandate_id: Option<String>,
browser_info: Option<serde_json::Value>, browser_info: Option<serde_json::Value>,
error_code: Option<String>,
} }
impl PaymentAttemptUpdate { impl PaymentAttemptUpdate {
@ -226,11 +230,13 @@ impl From<PaymentAttemptUpdate> for PaymentAttemptUpdateInternal {
PaymentAttemptUpdate::ErrorUpdate { PaymentAttemptUpdate::ErrorUpdate {
connector, connector,
status, status,
error_code,
error_message, error_message,
} => Self { } => Self {
connector, connector,
status: Some(status), status: Some(status),
error_message, error_message,
error_code,
modified_at: Some(common_utils::date_time::now()), modified_at: Some(common_utils::date_time::now()),
..Default::default() ..Default::default()
}, },

View File

@ -212,6 +212,7 @@ diesel::table! {
amount_to_capture -> Nullable<Int4>, amount_to_capture -> Nullable<Int4>,
mandate_id -> Nullable<Varchar>, mandate_id -> Nullable<Varchar>,
browser_info -> Nullable<Jsonb>, browser_info -> Nullable<Jsonb>,
error_code -> Nullable<Varchar>,
} }
} }

View File

@ -0,0 +1,3 @@
-- This file should undo anything in `up.sql`
ALTER TABLE payment_attempt
DROP COLUMN IF EXISTS error_code;

View File

@ -0,0 +1,3 @@
-- Your SQL goes here
ALTER TABLE payment_attempt
ADD IF NOT EXISTS error_code VARCHAR(255) DEFAULT NULL;