Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): api ,domain and diesel model changes for extended authorization #6607

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
56 changes: 56 additions & 0 deletions api-reference/openapi_spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -17009,6 +17009,12 @@
],
"nullable": true
},
"request_extended_authorization": {
"type": "boolean",
"description": "Optional boolean value to extent authorization period of this payment\n\ncapture method must be manual or manual_multiple",
"default": false,
"nullable": true
},
"merchant_order_reference_id": {
"type": "string",
"description": "Merchant's identifier for the payment/invoice. This will be sent to the connector\nif the connector provides support to accept multiple reference ids.\nIn case the connector supports only one reference id, Hyperswitch's Payment ID will be sent as reference.",
Expand Down Expand Up @@ -17387,6 +17393,12 @@
],
"nullable": true
},
"request_extended_authorization": {
"type": "boolean",
"description": "Optional boolean value to extent authorization period of this payment\n\ncapture method must be manual or manual_multiple",
"default": false,
"nullable": true
},
"merchant_order_reference_id": {
"type": "string",
"description": "Merchant's identifier for the payment/invoice. This will be sent to the connector\nif the connector provides support to accept multiple reference ids.\nIn case the connector supports only one reference id, Hyperswitch's Payment ID will be sent as reference.",
Expand Down Expand Up @@ -17926,6 +17938,17 @@
"description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. FRM Metadata is useful for storing additional, structured information on an object related to FRM.",
"nullable": true
},
"extended_authorization_applied": {
"type": "boolean",
"description": "flag that indicates if extended authorization is applied on this payment or not",
"nullable": true
},
"capture_before": {
"type": "string",
"format": "date-time",
"description": "date and time after which this payment cannot be captured",
"nullable": true
},
"merchant_order_reference_id": {
"type": "string",
"description": "Merchant's identifier for the payment/invoice. This will be sent to the connector\nif the connector provides support to accept multiple reference ids.\nIn case the connector supports only one reference id, Hyperswitch's Payment ID will be sent as reference.",
Expand Down Expand Up @@ -18589,6 +18612,12 @@
],
"nullable": true
},
"request_extended_authorization": {
"type": "boolean",
"description": "Optional boolean value to extent authorization period of this payment\n\ncapture method must be manual or manual_multiple",
"default": false,
"nullable": true
},
"merchant_order_reference_id": {
"type": "string",
"description": "Merchant's identifier for the payment/invoice. This will be sent to the connector\nif the connector provides support to accept multiple reference ids.\nIn case the connector supports only one reference id, Hyperswitch's Payment ID will be sent as reference.",
Expand Down Expand Up @@ -19154,6 +19183,17 @@
"description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. FRM Metadata is useful for storing additional, structured information on an object related to FRM.",
"nullable": true
},
"extended_authorization_applied": {
"type": "boolean",
"description": "flag that indicates if extended authorization is applied on this payment or not",
"nullable": true
},
"capture_before": {
"type": "string",
"format": "date-time",
"description": "date and time after which this payment cannot be captured",
"nullable": true
},
"merchant_order_reference_id": {
"type": "string",
"description": "Merchant's identifier for the payment/invoice. This will be sent to the connector\nif the connector provides support to accept multiple reference ids.\nIn case the connector supports only one reference id, Hyperswitch's Payment ID will be sent as reference.",
Expand Down Expand Up @@ -19630,6 +19670,12 @@
],
"nullable": true
},
"request_extended_authorization": {
"type": "boolean",
"description": "Optional boolean value to extent authorization period of this payment\n\ncapture method must be manual or manual_multiple",
"default": false,
"nullable": true
},
"merchant_order_reference_id": {
"type": "string",
"description": "Merchant's identifier for the payment/invoice. This will be sent to the connector\nif the connector provides support to accept multiple reference ids.\nIn case the connector supports only one reference id, Hyperswitch's Payment ID will be sent as reference.",
Expand Down Expand Up @@ -21606,6 +21652,11 @@
"description": "Maximum number of auto retries allowed for a payment",
"nullable": true,
"minimum": 0
},
"always_request_extended_authorization": {
"type": "boolean",
"description": "Bool indicating if extended authentication must be requested for all payments",
"nullable": true
}
},
"additionalProperties": false
Expand Down Expand Up @@ -21835,6 +21886,11 @@
"format": "int32",
"description": "Maximum number of auto retries allowed for a payment",
"nullable": true
},
"always_request_extended_authorization": {
"type": "boolean",
"description": "Bool indicating if extended authentication must be requested for all payments",
"nullable": true
}
}
},
Expand Down
13 changes: 12 additions & 1 deletion crates/api_models/src/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ use common_utils::{
id_type, link_utils, pii,
};
#[cfg(feature = "v1")]
use common_utils::{crypto::OptionalEncryptableName, ext_traits::ValueExt};
use common_utils::{
crypto::OptionalEncryptableName, ext_traits::ValueExt,
types::AlwaysRequestExtendedAuthorization,
};
#[cfg(feature = "v2")]
use masking::ExposeInterface;
use masking::Secret;
Expand Down Expand Up @@ -1967,6 +1970,10 @@ pub struct ProfileCreate {

/// Maximum number of auto retries allowed for a payment
pub max_auto_retries_enabled: Option<u8>,

/// Bool indicating if extended authentication must be requested for all payments
#[schema(value_type = Option<bool>)]
pub always_request_extended_authorization: Option<AlwaysRequestExtendedAuthorization>,
}

#[nutype::nutype(
Expand Down Expand Up @@ -2203,6 +2210,10 @@ pub struct ProfileResponse {

/// Maximum number of auto retries allowed for a payment
pub max_auto_retries_enabled: Option<i16>,

/// Bool indicating if extended authentication must be requested for all payments
#[schema(value_type = Option<bool>)]
pub always_request_extended_authorization: Option<AlwaysRequestExtendedAuthorization>,
}

#[cfg(feature = "v2")]
Expand Down
9 changes: 9 additions & 0 deletions crates/api_models/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,12 @@ pub mod verifications;
pub mod verify_connector;
pub mod webhook_events;
pub mod webhooks;

pub trait ValidateFieldAndGet<Request> {
fn validate_field_and_get(
&self,
request: &Request,
) -> common_utils::errors::CustomResult<Self, common_utils::errors::ValidationError>
where
Self: Sized;
}
34 changes: 32 additions & 2 deletions crates/api_models/src/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::{
num::NonZeroI64,
};
pub mod additional_info;
pub mod trait_impls;
use cards::CardNumber;
use common_enums::ProductType;
#[cfg(feature = "v2")]
Expand All @@ -16,7 +17,10 @@ use common_utils::{
hashing::HashedString,
id_type,
pii::{self, Email},
types::{MinorUnit, StringMajorUnit},
types::{
ExtendedAuthorizationAppliedBool, MinorUnit, RequestExtendedAuthorizationBool,
StringMajorUnit,
},
};
use error_stack::ResultExt;
use masking::{PeekInterface, Secret, WithType};
Expand All @@ -32,7 +36,7 @@ use crate::{
disputes, enums as api_enums,
ephemeral_key::EphemeralKeyCreateResponse,
mandates::RecurringDetails,
refunds,
refunds, ValidateFieldAndGet,
};

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
Expand Down Expand Up @@ -847,6 +851,12 @@ pub struct PaymentsRequest {
/// Fee information to be charged on the payment being collected
pub charges: Option<PaymentChargeRequest>,

/// Optional boolean value to extent authorization period of this payment
///
/// capture method must be manual or manual_multiple
#[schema(value_type = Option<bool>, default = false)]
pub request_extended_authorization: Option<RequestExtendedAuthorizationBool>,

/// Merchant's identifier for the payment/invoice. This will be sent to the connector
/// if the connector provides support to accept multiple reference ids.
/// In case the connector supports only one reference id, Hyperswitch's Payment ID will be sent as reference.
Expand Down Expand Up @@ -890,6 +900,18 @@ impl PaymentsRequest {
.or(self.customer.as_ref().map(|customer| &customer.id))
}

pub fn validate_and_get_request_extended_authorization(
&self,
) -> common_utils::errors::CustomResult<Option<RequestExtendedAuthorizationBool>, ValidationError>
{
self.request_extended_authorization
.as_ref()
.map(|request_extended_authorization| {
request_extended_authorization.validate_field_and_get(self)
})
.transpose()
}

/// Checks if the customer details are passed in both places
/// If they are passed in both places, check for both the values to be equal
/// Or else, return the field which has inconsistent data
Expand Down Expand Up @@ -4516,6 +4538,14 @@ pub struct PaymentsResponse {
#[schema(value_type = Option<Object>, example = r#"{ "fulfillment_method" : "deliver", "coverage_request" : "fraud" }"#)]
pub frm_metadata: Option<pii::SecretSerdeValue>,

/// flag that indicates if extended authorization is applied on this payment or not
#[schema(value_type = Option<bool>)]
pub extended_authorization_applied: Option<ExtendedAuthorizationAppliedBool>,

/// date and time after which this payment cannot be captured
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
pub capture_before: Option<PrimitiveDateTime>,

/// Merchant's identifier for the payment/invoice. This will be sent to the connector
/// if the connector provides support to accept multiple reference ids.
/// In case the connector supports only one reference id, Hyperswitch's Payment ID will be sent as reference.
Expand Down
24 changes: 24 additions & 0 deletions crates/api_models/src/payments/trait_impls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use common_enums::enums;
use common_utils::errors;

use crate::payments;

impl crate::ValidateFieldAndGet<payments::PaymentsRequest>
for common_utils::types::RequestExtendedAuthorizationBool
{
fn validate_field_and_get(
&self,
request: &payments::PaymentsRequest,
) -> errors::CustomResult<Self, errors::ValidationError>
where
Self: Sized,
{
match request.capture_method{
Some(enums::CaptureMethod::Automatic)
| Some(enums::CaptureMethod::Scheduled)
| None => Err(error_stack::report!(errors::ValidationError::InvalidValue { message: "request_extended_authorization must be sent only if capture method is manual or manual_multiple".to_string() })),
Some(enums::CaptureMethod::Manual)
| Some(enums::CaptureMethod::ManualMultiple) => Ok(self.clone())
}
}
}
2 changes: 1 addition & 1 deletion crates/common_enums/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ openapi = []
payouts = []

[dependencies]
diesel = { version = "2.2.3", features = ["postgres"] }
diesel = { version = "2.2.3", features = ["postgres", "128-column-tables"] }
serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.115"
strum = { version = "0.26", features = ["derive"] }
Expand Down
7 changes: 7 additions & 0 deletions crates/common_utils/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ pub mod authentication;
/// Enum for Theme Lineage
pub mod theme;

/// types that are wrappers around primitive types
pub mod primitive_wrappers;

use std::{
borrow::Cow,
fmt::Display,
Expand All @@ -26,6 +29,10 @@ use diesel::{
AsExpression, FromSqlRow, Queryable,
};
use error_stack::{report, ResultExt};
pub use primitive_wrappers::bool_wrappers::{
AlwaysRequestExtendedAuthorization, ExtendedAuthorizationAppliedBool,
RequestExtendedAuthorizationBool,
};
use rust_decimal::{
prelude::{FromPrimitive, ToPrimitive},
Decimal,
Expand Down
91 changes: 91 additions & 0 deletions crates/common_utils/src/types/primitive_wrappers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
pub(crate) mod bool_wrappers {
use serde::{Deserialize, Serialize};

/// Bool that represents if Extended Authorization is Applied or not
#[derive(
Clone, Debug, Eq, PartialEq, Serialize, Deserialize, diesel::expression::AsExpression,
)]
#[diesel(sql_type = diesel::sql_types::Bool)]
pub struct ExtendedAuthorizationAppliedBool(bool);
impl<DB> diesel::serialize::ToSql<diesel::sql_types::Bool, DB> for ExtendedAuthorizationAppliedBool
where
DB: diesel::backend::Backend,
bool: diesel::serialize::ToSql<diesel::sql_types::Bool, DB>,
{
fn to_sql<'b>(
&'b self,
out: &mut diesel::serialize::Output<'b, '_, DB>,
) -> diesel::serialize::Result {
self.0.to_sql(out)
}
}
impl<DB> diesel::deserialize::FromSql<diesel::sql_types::Bool, DB>
for ExtendedAuthorizationAppliedBool
where
DB: diesel::backend::Backend,
bool: diesel::deserialize::FromSql<diesel::sql_types::Bool, DB>,
{
fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
bool::from_sql(value).map(Self)
}
}

/// Bool that represents if Extended Authorization is Requested or not
#[derive(
Clone, Debug, Eq, PartialEq, Serialize, Deserialize, diesel::expression::AsExpression,
)]
#[diesel(sql_type = diesel::sql_types::Bool)]
pub struct RequestExtendedAuthorizationBool(bool);
impl<DB> diesel::serialize::ToSql<diesel::sql_types::Bool, DB> for RequestExtendedAuthorizationBool
where
DB: diesel::backend::Backend,
bool: diesel::serialize::ToSql<diesel::sql_types::Bool, DB>,
{
fn to_sql<'b>(
&'b self,
out: &mut diesel::serialize::Output<'b, '_, DB>,
) -> diesel::serialize::Result {
self.0.to_sql(out)
}
}
impl<DB> diesel::deserialize::FromSql<diesel::sql_types::Bool, DB>
for RequestExtendedAuthorizationBool
where
DB: diesel::backend::Backend,
bool: diesel::deserialize::FromSql<diesel::sql_types::Bool, DB>,
{
fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
bool::from_sql(value).map(Self)
}
}

/// Bool that represents if Extended Authorization is always Requested or not
#[derive(
Clone, Debug, Eq, PartialEq, diesel::expression::AsExpression, Serialize, Deserialize,
)]
#[diesel(sql_type = diesel::sql_types::Bool)]
pub struct AlwaysRequestExtendedAuthorization(bool);
impl<DB> diesel::serialize::ToSql<diesel::sql_types::Bool, DB>
for AlwaysRequestExtendedAuthorization
where
DB: diesel::backend::Backend,
bool: diesel::serialize::ToSql<diesel::sql_types::Bool, DB>,
{
fn to_sql<'b>(
&'b self,
out: &mut diesel::serialize::Output<'b, '_, DB>,
) -> diesel::serialize::Result {
self.0.to_sql(out)
}
}
impl<DB> diesel::deserialize::FromSql<diesel::sql_types::Bool, DB>
for AlwaysRequestExtendedAuthorization
where
DB: diesel::backend::Backend,
bool: diesel::deserialize::FromSql<diesel::sql_types::Bool, DB>,
{
fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
bool::from_sql(value).map(Self)
}
}
}
3 changes: 2 additions & 1 deletion crates/diesel_models/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ payment_methods_v2 = []

[dependencies]
async-bb8-diesel = { git = "https://github.com/jarnura/async-bb8-diesel", rev = "53b4ab901aab7635c8215fd1c2d542c8db443094" }
diesel = { version = "2.2.3", features = ["postgres", "serde_json", "time", "64-column-tables"] }
diesel = { version = "2.2.3", features = ["postgres", "serde_json", "time", "128-column-tables"] }

error-stack = "0.4.1"
rustc-hash = "1.1.0"
serde = { version = "1.0.197", features = ["derive"] }
Expand Down
Loading
Loading