mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-02 04:04:43 +08:00
fix: todos and fixmes resolution for api_models (#144)
This commit is contained in:
@ -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)]
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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>,
|
||||
}
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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`
|
||||
|
||||
@ -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
|
||||
// }
|
||||
// }
|
||||
|
||||
@ -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,
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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()),
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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()
|
||||
},
|
||||
|
||||
@ -212,6 +212,7 @@ diesel::table! {
|
||||
amount_to_capture -> Nullable<Int4>,
|
||||
mandate_id -> Nullable<Varchar>,
|
||||
browser_info -> Nullable<Jsonb>,
|
||||
error_code -> Nullable<Varchar>,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
-- This file should undo anything in `up.sql`
|
||||
ALTER TABLE payment_attempt
|
||||
DROP COLUMN IF EXISTS error_code;
|
||||
@ -0,0 +1,3 @@
|
||||
-- Your SQL goes here
|
||||
ALTER TABLE payment_attempt
|
||||
ADD IF NOT EXISTS error_code VARCHAR(255) DEFAULT NULL;
|
||||
Reference in New Issue
Block a user