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;
use super::payments::AddressDetails;
use crate::enums as api_enums;
use crate::{enums as api_enums, payment_methods};
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
@ -55,7 +55,7 @@ pub struct WebhookDetails {
#[derive(Default, Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
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_method_types_incl: 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 recurring_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)]

View File

@ -33,14 +33,9 @@ pub struct PaymentMethodResponse {
pub payment_method_issuer: Option<String>,
pub payment_method_issuer_code: Option<api_enums::PaymentMethodIssuerCode>,
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 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>,
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
pub created: Option<time::PrimitiveDateTime>,
@ -174,7 +169,7 @@ pub struct ListPaymentMethodResponse {
pub maximum_amount: Option<i32>,
pub recurring_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)]
@ -197,20 +192,27 @@ pub struct CustomerPaymentMethod {
pub payment_method_type: Option<api_enums::PaymentMethodSubType>,
pub payment_method_issuer: Option<String>,
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 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 metadata: Option<serde_json::Value>,
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
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)]
pub struct PaymentMethodId {
pub payment_method_id: String,
@ -243,7 +245,7 @@ pub struct DeleteTokenizeByTokenRequest {
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 buffer_minutes: i32,
pub service_name: String,

View File

@ -399,7 +399,7 @@ pub struct PaymentsResponse {
pub statement_descriptor_suffix: Option<String>,
pub next_action: Option<NextAction>,
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>,
}

View File

@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
use crate::enums;
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[derive(Default, Debug, Clone, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct RefundRequest {
pub refund_id: Option<String>,
@ -10,11 +10,18 @@ pub struct RefundRequest {
pub merchant_id: Option<String>,
pub amount: Option<i32>,
pub reason: Option<String>,
//FIXME: Make it refund_type instant or scheduled refund
pub force_process: Option<bool>,
pub refund_type: Option<RefundType>,
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)]
pub struct RefundResponse {
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:
```rust,ignore
```rust
expiry_year: ccard.map(|x| Secret::new(x.card_exp_year.to_string())),
// output: "expiry_year: *** alloc::string::String ***"
```
To get value from secret use `expose()`. Sample:
```rust,ignore
```rust
last4_digits: Some(card_number.expose())
```
Most fields are under `Option`. To simplify dealing with `Option`, use `expose_option()`. Sample:
```rust,ignore
```rust
card_info.push_str(
&card_detail
.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: fill missing -->
## Files Tree Layout
<!-- ```text
├── src : source code
└── tests : unit and integration tests
```bash
.
├── src # : source code
└── tests # : unit and integration tests
``` -->
```
<!--
command to generate the tree `tree -L 3 -d`

View File

@ -40,18 +40,3 @@ where
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,
recurring_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),
recurring_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),
};
vec.push(pma);
@ -676,7 +680,9 @@ pub async fn retrieve_payment_method(
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!["redirect_to_url".to_string()]), //TODO,
payment_experience: Some(vec![
api_models::payment_methods::PaymentExperience::RedirectToUrl,
]), //TODO,
}))
}

View File

@ -116,7 +116,9 @@ pub fn mk_add_card_response(
payment_method_issuer_code: req.payment_method_issuer_code,
recurring_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()),
status: storage::enums::AttemptStatus::Failure,
error_message: Some(err.message),
error_code: Some(err.code),
}),
Some(storage::ConnectorResponseUpdate::ErrorUpdate {
connector_name: Some(router_data.connector.clone()),

View File

@ -356,6 +356,7 @@ where
.capture_method
.map(ForeignInto::foreign_into),
error_message: payment_attempt.error_message,
error_code: payment_attempt.error_code,
payment_method_data: payment_method_data.map(api::PaymentMethodDataResponse::from),
email: customer
.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);
// 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.
@ -435,7 +435,7 @@ pub async fn validate_and_create_refund(
schedule_refund_execution(
state,
refund,
force_process, // *force_process,
refund_type,
merchant_account,
payment_attempt,
payment_intent,
@ -535,8 +535,7 @@ impl From<Foreign<storage::Refund>> for Foreign<api::RefundResponse> {
pub async fn schedule_refund_execution(
state: &AppState,
refund: storage::Refund,
//FIXME: change to refund_Type here
force_process: bool,
refund_type: api_models::refunds::RefundType,
merchant_account: &storage::merchant_account::MerchantAccount,
payment_attempt: &storage::PaymentAttempt,
payment_intent: &storage::PaymentIntent,
@ -556,8 +555,16 @@ pub async fn schedule_refund_execution(
enums::RefundStatus::Pending | enums::RefundStatus::ManualReview => {
match (refund.sent_to_gateway, refund_process) {
(false, None) => {
//execute
if force_process {
// Execute the refund task based on refund_type
match refund_type {
api_models::refunds::RefundType::Scheduled => {
add_refund_execute_task(db, &refund, runner)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)?;
Ok(refund)
}
api_models::refunds::RefundType::Instant => {
trigger_refund_to_gateway(
state,
&refund,
@ -566,25 +573,26 @@ pub async fn schedule_refund_execution(
payment_intent,
)
.await
} else {
add_refund_execute_task(db, &refund, runner)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)?;
Ok(refund)
}
}
}
_ => {
//sync status
// Sync the refund for status check
//TODO: return refund status response
if force_process {
// sync_refund_with_gateway(data, &refund).await
Ok(refund)
} else {
match refund_type {
api_models::refunds::RefundType::Scheduled => {
add_refund_sync_task(db, &refund, runner)
.await
.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,
mandate_id: None,
browser_info: None,
error_code: payment_attempt.error_code,
};
payment_attempts.push(payment_attempt.clone());
Ok(payment_attempt)
@ -370,6 +371,7 @@ mod storage {
cancellation_reason: payment_attempt.cancellation_reason.clone(),
mandate_id: payment_attempt.mandate_id.clone(),
browser_info: payment_attempt.browser_info.clone(),
error_code: payment_attempt.error_code.clone(),
};
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> {
fn from(status: F<storage_enums::MandateStatus>) -> Self {
Foreign(frunk::labelled_convert_from(status.0))

View File

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

View File

@ -212,6 +212,7 @@ diesel::table! {
amount_to_capture -> Nullable<Int4>,
mandate_id -> Nullable<Varchar>,
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;