Skip to content

Commit

Permalink
feat(router): add support for payment_type field in payment intent (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
vspecky authored Oct 5, 2023
1 parent db7f9fa commit f116728
Show file tree
Hide file tree
Showing 16 changed files with 126 additions and 2 deletions.
3 changes: 3 additions & 0 deletions crates/api_models/src/payment_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,9 @@ pub struct PaymentMethodListResponse {

#[schema(value_type = Option<String>)]
pub merchant_name: OptionalEncryptableName,

#[schema(value_type = Option<PaymentType>)]
pub payment_type: Option<api_enums::PaymentType>,
}

#[derive(Eq, PartialEq, Hash, Debug, serde::Deserialize, ToSchema)]
Expand Down
5 changes: 5 additions & 0 deletions crates/api_models/src/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,11 @@ pub struct PaymentsRequest {
/// The business profile to use for this payment, if not passed the default business profile
/// associated with the merchant account will be used.
pub profile_id: Option<String>,

/// The type of the payment that differentiates between normal and various types of mandate payments
#[schema(value_type = Option<PaymentType>)]
#[serde(default)]
pub payment_type: api_enums::PaymentType,
}

#[derive(Default, Debug, Clone, Copy)]
Expand Down
26 changes: 25 additions & 1 deletion crates/common_enums/src/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub mod diesel_exports {
DbDisputeStage as DisputeStage, DbDisputeStatus as DisputeStatus, DbEventType as EventType,
DbFutureUsage as FutureUsage, DbIntentStatus as IntentStatus,
DbMandateStatus as MandateStatus, DbPaymentMethodIssuerCode as PaymentMethodIssuerCode,
DbRefundStatus as RefundStatus,
DbPaymentType as PaymentType, DbRefundStatus as RefundStatus,
};
}

Expand Down Expand Up @@ -1065,6 +1065,30 @@ pub enum PaymentMethod {
GiftCard,
}

#[derive(
Clone,
Copy,
Debug,
Default,
Eq,
PartialEq,
serde::Deserialize,
serde::Serialize,
strum::Display,
strum::EnumString,
ToSchema,
)]
#[router_derive::diesel_enum(storage_type = "pg_enum")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum PaymentType {
#[default]
Normal,
NewMandate,
SetupMandate,
RecurringMandate,
}

#[derive(
Clone,
Copy,
Expand Down
2 changes: 2 additions & 0 deletions crates/data_models/src/payments/payment_intent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ pub struct PaymentIntent {
// Manual review can occur when the transaction is marked as risky by the frm_processor, payment processor or when there is underpayment/over payment incase of crypto payment
pub merchant_decision: Option<String>,
pub payment_confirm_source: Option<storage_enums::PaymentSource>,
pub payment_type: Option<storage_enums::PaymentType>,
}

#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
Expand Down Expand Up @@ -144,6 +145,7 @@ pub struct PaymentIntentNew {
pub profile_id: Option<String>,
pub merchant_decision: Option<String>,
pub payment_confirm_source: Option<storage_enums::PaymentSource>,
pub payment_type: Option<storage_enums::PaymentType>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down
2 changes: 1 addition & 1 deletion crates/diesel_models/src/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub mod diesel_exports {
DbMandateStatus as MandateStatus, DbMandateType as MandateType,
DbMerchantStorageScheme as MerchantStorageScheme,
DbPaymentMethodIssuerCode as PaymentMethodIssuerCode, DbPaymentSource as PaymentSource,
DbPayoutStatus as PayoutStatus, DbPayoutType as PayoutType,
DbPaymentType as PaymentType, DbPayoutStatus as PayoutStatus, DbPayoutType as PayoutType,
DbProcessTrackerStatus as ProcessTrackerStatus, DbReconStatus as ReconStatus,
DbRefundStatus as RefundStatus, DbRefundType as RefundType,
};
Expand Down
2 changes: 2 additions & 0 deletions crates/diesel_models/src/payment_intent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pub struct PaymentIntent {
// Manual review can occur when the transaction is marked as risky by the frm_processor, payment processor or when there is underpayment/over payment incase of crypto payment
pub merchant_decision: Option<String>,
pub payment_confirm_source: Option<storage_enums::PaymentSource>,
pub payment_type: Option<storage_enums::PaymentType>,
}

#[derive(
Expand Down Expand Up @@ -98,6 +99,7 @@ pub struct PaymentIntentNew {
pub profile_id: Option<String>,
pub merchant_decision: Option<String>,
pub payment_confirm_source: Option<storage_enums::PaymentSource>,
pub payment_type: Option<storage_enums::PaymentType>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down
1 change: 1 addition & 0 deletions crates/diesel_models/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,7 @@ diesel::table! {
#[max_length = 64]
merchant_decision -> Nullable<Varchar>,
payment_confirm_source -> Nullable<PaymentSource>,
payment_type -> Nullable<PaymentType>,
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/router/src/core/payment_methods/cards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1281,6 +1281,7 @@ pub async fn list_payment_methods(
redirect_url: merchant_account.return_url,
merchant_name: merchant_account.merchant_name,
payment_methods: payment_method_responses,
payment_type: payment_intent.as_ref().and_then(|pi| pi.payment_type),
mandate_payment: payment_attempt.and_then(|inner| inner.mandate_details).map(
|d| match d {
data_models::mandates::MandateDataType::SingleUse(i) => {
Expand Down
24 changes: 24 additions & 0 deletions crates/router/src/core/payments/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,27 @@ pub fn validate_card_data(
Ok(())
}

pub fn infer_payment_type(
amount: &api::Amount,
mandate_type: Option<&api::MandateTransactionType>,
) -> api_enums::PaymentType {
match mandate_type {
Some(api::MandateTransactionType::NewMandateTransaction) => {
if let api::Amount::Value(_) = amount {
api_enums::PaymentType::NewMandate
} else {
api_enums::PaymentType::SetupMandate
}
}

Some(api::MandateTransactionType::RecurringMandateTransaction) => {
api_enums::PaymentType::RecurringMandate
}

None => api_enums::PaymentType::Normal,
}
}

pub fn validate_mandate(
req: impl Into<api::MandateValidationFields>,
is_confirm_operation: bool,
Expand Down Expand Up @@ -2377,6 +2398,7 @@ mod tests {
profile_id: None,
merchant_decision: None,
payment_confirm_source: None,
payment_type: Some(api_enums::PaymentType::Normal),
};
let req_cs = Some("1".to_string());
let merchant_fulfillment_time = Some(900);
Expand Down Expand Up @@ -2424,6 +2446,7 @@ mod tests {
profile_id: None,
merchant_decision: None,
payment_confirm_source: None,
payment_type: Some(api_enums::PaymentType::Normal),
};
let req_cs = Some("1".to_string());
let merchant_fulfillment_time = Some(10);
Expand Down Expand Up @@ -2471,6 +2494,7 @@ mod tests {
profile_id: None,
merchant_decision: None,
payment_confirm_source: None,
payment_type: Some(api_enums::PaymentType::Normal),
};
let req_cs = Some("1".to_string());
let merchant_fulfillment_time = Some(10);
Expand Down
5 changes: 5 additions & 0 deletions crates/router/src/core/payments/operations/payment_create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
core_utils::validate_and_get_business_profile(db, request.profile_id.as_ref(), merchant_id)
.await?;

let payment_type = helpers::infer_payment_type(&amount, mandate_type.as_ref());

let (
token,
payment_method,
Expand Down Expand Up @@ -145,6 +147,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
request,
shipping_address.clone().map(|x| x.address_id),
billing_address.clone().map(|x| x.address_id),
payment_type,
attempt_id,
state,
)
Expand Down Expand Up @@ -603,6 +606,7 @@ impl PaymentCreate {
request: &api::PaymentsRequest,
shipping_address_id: Option<String>,
billing_address_id: Option<String>,
payment_type: enums::PaymentType,
active_attempt_id: String,
state: &AppState,
) -> RouterResult<storage::PaymentIntentNew> {
Expand Down Expand Up @@ -677,6 +681,7 @@ impl PaymentCreate {
profile_id: Some(profile_id),
merchant_decision: None,
payment_confirm_source: None,
payment_type: Some(payment_type),
})
}

Expand Down
1 change: 1 addition & 0 deletions crates/router/src/openapi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ Never share your secret api keys. Keep them guarded and secure.
api_models::admin::AcceptedCountries,
api_models::admin::AcceptedCurrencies,
api_models::enums::RoutingAlgorithm,
api_models::enums::PaymentType,
api_models::enums::PaymentMethod,
api_models::enums::PaymentMethodType,
api_models::enums::ConnectorType,
Expand Down
1 change: 1 addition & 0 deletions crates/storage_impl/src/mock_db/payment_intent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ impl PaymentIntentInterface for MockDb {
profile_id: new.profile_id,
merchant_decision: new.merchant_decision,
payment_confirm_source: new.payment_confirm_source,
payment_type: new.payment_type,
};
payment_intents.push(payment_intent.clone());
Ok(payment_intent)
Expand Down
5 changes: 5 additions & 0 deletions crates/storage_impl/src/payments/payment_intent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ impl<T: DatabaseStore> PaymentIntentInterface for KVRouterStore<T> {
profile_id: new.profile_id.clone(),
merchant_decision: new.merchant_decision.clone(),
payment_confirm_source: new.payment_confirm_source,
payment_type: new.payment_type,
};

match self
Expand Down Expand Up @@ -707,6 +708,7 @@ impl DataModelExt for PaymentIntentNew {
profile_id: self.profile_id,
merchant_decision: self.merchant_decision,
payment_confirm_source: self.payment_confirm_source,
payment_type: self.payment_type,
}
}

Expand Down Expand Up @@ -744,6 +746,7 @@ impl DataModelExt for PaymentIntentNew {
profile_id: storage_model.profile_id,
merchant_decision: storage_model.merchant_decision,
payment_confirm_source: storage_model.payment_confirm_source,
payment_type: storage_model.payment_type,
}
}
}
Expand Down Expand Up @@ -786,6 +789,7 @@ impl DataModelExt for PaymentIntent {
profile_id: self.profile_id,
merchant_decision: self.merchant_decision,
payment_confirm_source: self.payment_confirm_source,
payment_type: self.payment_type,
}
}

Expand Down Expand Up @@ -824,6 +828,7 @@ impl DataModelExt for PaymentIntent {
profile_id: storage_model.profile_id,
merchant_decision: storage_model.merchant_decision,
payment_confirm_source: storage_model.payment_confirm_source,
payment_type: storage_model.payment_type,
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- This file should undo anything in `up.sql`

ALTER TABLE payment_intent
DROP COLUMN payment_type;

DROP TYPE "PaymentType";
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-- Your SQL goes here

CREATE TYPE "PaymentType" AS ENUM (
'normal',
'new_mandate',
'setup_mandate',
'recurring_mandate'
);

ALTER TABLE payment_intent
ADD COLUMN payment_type "PaymentType";
33 changes: 33 additions & 0 deletions openapi/openapi_spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -8080,6 +8080,14 @@
"merchant_name": {
"type": "string",
"nullable": true
},
"payment_type": {
"allOf": [
{
"$ref": "#/components/schemas/PaymentType"
}
],
"nullable": true
}
}
},
Expand Down Expand Up @@ -8329,6 +8337,15 @@
}
}
},
"PaymentType": {
"type": "string",
"enum": [
"normal",
"new_mandate",
"setup_mandate",
"recurring_mandate"
]
},
"PaymentsCancelRequest": {
"type": "object",
"required": [
Expand Down Expand Up @@ -8731,6 +8748,14 @@
"type": "string",
"description": "The business profile to use for this payment, if not passed the default business profile\nassociated with the merchant account will be used.",
"nullable": true
},
"payment_type": {
"allOf": [
{
"$ref": "#/components/schemas/PaymentType"
}
],
"nullable": true
}
}
},
Expand Down Expand Up @@ -9070,6 +9095,14 @@
"type": "string",
"description": "The business profile to use for this payment, if not passed the default business profile\nassociated with the merchant account will be used.",
"nullable": true
},
"payment_type": {
"allOf": [
{
"$ref": "#/components/schemas/PaymentType"
}
],
"nullable": true
}
}
},
Expand Down

0 comments on commit f116728

Please sign in to comment.