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(router): add adyen split payments support #6952

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion crates/api_models/src/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4991,7 +4991,7 @@ pub struct PaymentStartRedirectionParams {
pub profile_id: id_type::ProfileId,
}

/// Fee information to be charged on the payment being collected
/// Fee information to be charged on the payment being collected via Stripe
#[derive(Setter, Clone, Debug, PartialEq, serde::Serialize, ToSchema)]
pub struct StripeSplitPaymentsResponse {
/// Identifier for charge created for the payment
Expand All @@ -5009,11 +5009,26 @@ pub struct StripeSplitPaymentsResponse {
pub transfer_account_id: String,
}

/// Fee information to be charged on the payment being collected via Adyen
#[derive(Setter, Clone, Debug, PartialEq, serde::Serialize, ToSchema)]
pub struct AdyenSplitPaymentResponse {
/// Unique Identifier for the split item
pub charge_id: String,
/// The amount of the split item.
#[schema(value_type = i64, example = 6540)]
pub split_amount: MinorUnit,
/// The currency of the split item.
#[schema(example = "USD", value_type = Currency)]
pub split_currency: Option<common_enums::Currency>,
}

#[derive(Clone, Debug, PartialEq, serde::Serialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum SplitPaymentsResponse {
/// StripeSplitPaymentsResponse
StripeSplitPayment(StripeSplitPaymentsResponse),
/// AdyenSplitPaymentsResponse
AdyenSplitPayment(AdyenSplitPaymentResponse),
}

/// Details of external authentication
Expand Down
42 changes: 42 additions & 0 deletions crates/common_enums/src/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3613,3 +3613,45 @@ pub enum FeatureStatus {
NotSupported,
Supported,
}

#[derive(
Clone,
Debug,
Eq,
PartialEq,
serde::Deserialize,
serde::Serialize,
strum::Display,
strum::EnumString,
ToSchema,
Default,
)]
#[strum(serialize_all = "snake_case")]
#[serde(rename_all = "snake_case")]
pub enum AdyenSplitType {
/// Books split amount to the specified account.
BalanceAccount,
/// The aggregated amount of the interchange and scheme fees.
AcquiringFees,
/// The aggregated amount of all transaction fees.
PaymentFee,
/// The aggregated amount of Adyen's commission and markup fees.
AdyenFees,
/// The transaction fees due to Adyen under blended rates.
AdyenCommission,
/// The transaction fees due to Adyen under Interchange ++ pricing.
AdyenMarkup,
/// The fees paid to the issuer for each payment made with the card network.
Interchange,
/// The fees paid to the card scheme for using their network.
SchemeFee,
/// Your platform's commission on the payment (specified in amount), booked to your liable balance account.
Commission,
/// Allows you and your users to top up balance accounts using direct debit, card payments, or other payment methods.
TopUp,
/// The value-added tax charged on the payment, booked to your platforms liable balance account.
Vat,
/// In very specific use cases, allows you to book the specified amount to the specified account.
#[default]
Default,
}
22 changes: 22 additions & 0 deletions crates/common_types/src/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ use utoipa::ToSchema;
pub enum SplitPaymentsRequest {
/// StripeSplitPayment
StripeSplitPayment(StripeSplitPaymentRequest),
/// AdyenSplitPayment
AdyenSplitPayment(AdyenSplitPaymentRequest),
}
impl_to_sql_from_sql_json!(SplitPaymentsRequest);

Expand All @@ -38,3 +40,23 @@ pub struct StripeSplitPaymentRequest {
pub transfer_account_id: String,
}
impl_to_sql_from_sql_json!(StripeSplitPaymentRequest);

#[derive(
Serialize, Deserialize, Debug, Clone, PartialEq, Eq, FromSqlRow, AsExpression, ToSchema,
)]
#[diesel(sql_type = Jsonb)]
#[serde(deny_unknown_fields)]
/// Fee information for Split Payments to be charged on the payment being collected for Adyen
pub struct AdyenSplitPaymentRequest {
/// The unique identifier of the account to which the split amount is booked
pub account: String,
/// The amount of the split item.
#[schema(value_type = i64, example = 6540)]
pub split_amount: MinorUnit,
/// Defines the part of the payment that one wants to book to the specified account.
#[schema(value_type = AdyenSplitType, example = "balance_account")]
pub split_type: enums::AdyenSplitType,
/// Unique Identifier for the split item
pub charge_id: String,
}
impl_to_sql_from_sql_json!(AdyenSplitPaymentRequest);
2 changes: 2 additions & 0 deletions crates/openapi/src/openapi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,11 +216,13 @@ Never share your secret api keys. Keep them guarded and secure.
common_utils::payout_method_utils::VenmoAdditionalData,
common_types::payments::SplitPaymentsRequest,
common_types::payments::StripeSplitPaymentRequest,
common_types::payments::AdyenSplitPaymentRequest,
common_utils::types::ChargeRefunds,
common_types::refunds::SplitRefund,
common_types::refunds::StripeSplitRefundRequest,
api_models::payments::SplitPaymentsResponse,
api_models::payments::StripeSplitPaymentsResponse,
api_models::payments::AdyenSplitPaymentsResponse,
api_models::refunds::RefundRequest,
api_models::refunds::RefundType,
api_models::refunds::RefundResponse,
Expand Down
2 changes: 2 additions & 0 deletions crates/openapi/src/openapi_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,14 @@ Never share your secret api keys. Keep them guarded and secure.
common_utils::payout_method_utils::VenmoAdditionalData,
common_types::payments::SplitPaymentsRequest,
common_types::payments::StripeSplitPaymentRequest,
common_types::payments::AdyenSplitPaymentRequest,
common_types::refunds::StripeSplitRefundRequest,
common_utils::types::ChargeRefunds,
common_types::payment_methods::PaymentMethodsEnabled,
common_types::refunds::SplitRefund,
api_models::payments::SplitPaymentsResponse,
api_models::payments::StripeSplitPaymentsResponse,
api_models::payments::AdyenSplitPaymentsResponse,
api_models::refunds::RefundRequest,
api_models::refunds::RefundsCreateRequest,
api_models::refunds::RefundErrorDetails,
Expand Down
2 changes: 2 additions & 0 deletions crates/router/src/connector/stripe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,7 @@ impl
&mut header,
);
}
common_types::payments::SplitPaymentsRequest::AdyenSplitPayment(_) => (),
}
}
Ok(header)
Expand Down Expand Up @@ -963,6 +964,7 @@ impl
header.append(&mut customer_account_header);
}
}
_ => (),
}
}
Ok(header)
Expand Down
4 changes: 3 additions & 1 deletion crates/router/src/connector/stripe/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1953,7 +1953,9 @@ impl TryFrom<(&types::PaymentsAuthorizeRouterData, MinorUnit)> for PaymentIntent
};
(charges, None)
}
None => (None, item.connector_customer.to_owned().map(Secret::new)),
Some(common_types::payments::SplitPaymentsRequest::AdyenSplitPayment(_)) | None => {
(None, item.connector_customer.to_owned().map(Secret::new))
}
};

Ok(Self {
Expand Down
51 changes: 34 additions & 17 deletions crates/router/src/core/payments/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6246,24 +6246,41 @@ pub fn validate_platform_fees_for_marketplace(
amount: api::Amount,
split_payments: Option<common_types::payments::SplitPaymentsRequest>,
) -> Result<(), errors::ApiErrorResponse> {
if let Some(common_types::payments::SplitPaymentsRequest::StripeSplitPayment(
stripe_split_payment,
)) = split_payments
{
match amount {
api::Amount::Zero => {
if stripe_split_payment.application_fees.get_amount_as_i64() != 0 {
return Err(errors::ApiErrorResponse::InvalidDataValue {
field_name: "split_payments.stripe_split_payment.application_fees",
});
}
if let Some(split_payment) = split_payments {
let (field_name, split_amount_i64) = match split_payment {
common_types::payments::SplitPaymentsRequest::StripeSplitPayment(
stripe_split_payment,
) => (
"split_payments.stripe_split_payment.application_fees",
stripe_split_payment.application_fees.get_amount_as_i64(),
),
common_types::payments::SplitPaymentsRequest::AdyenSplitPayment(
adyen_split_payment,
) => (
"split_payments.adyen_split_payment.split_amount",
adyen_split_payment.split_amount.get_amount_as_i64(),
),
};

validate_split_amount(amount, split_amount_i64, field_name)?;
}
Ok(())
}

fn validate_split_amount(
amount: api::Amount,
split_amount_i64: i64,
field_name: &'static str,
) -> Result<(), errors::ApiErrorResponse> {
match amount {
api::Amount::Zero => {
if split_amount_i64 != 0 {
return Err(errors::ApiErrorResponse::InvalidDataValue { field_name });
}
api::Amount::Value(amount) => {
if stripe_split_payment.application_fees.get_amount_as_i64() > amount.into() {
return Err(errors::ApiErrorResponse::InvalidDataValue {
field_name: "split_payments.stripe_split_payment.application_fees",
});
}
}
api::Amount::Value(amount) => {
if split_amount_i64 > amount.into() {
return ErPr(errors::ApiErrorResponse::InvalidDataValue { field_name });
}
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/router/src/core/payments/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2134,6 +2134,7 @@ where
},
),
),
common_types::payments::SplitPaymentsRequest::AdyenSplitPayment(_) => None,
},
};

Expand Down
1 change: 1 addition & 0 deletions crates/router/src/core/refunds/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ impl TryFrom<SplitRefundInput> for router_request_types::SplitRefundsRequest {
},
))
}
common_types::payments::SplitPaymentsRequest::AdyenSplitPayment(_) => todo!(), // todooooo
}
}
}
Expand Down
Loading