diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index 58a81caeed..c8a87f1a61 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -11854,70 +11854,6 @@ } } }, - "OrderDetails": { - "type": "object", - "required": [ - "product_name", - "quantity" - ], - "properties": { - "product_name": { - "type": "string", - "description": "Name of the product that is being purchased", - "example": "shirt", - "maxLength": 255 - }, - "quantity": { - "type": "integer", - "format": "int32", - "description": "The quantity of the product to be purchased", - "example": 1, - "minimum": 0 - }, - "requires_shipping": { - "type": "boolean", - "nullable": true - }, - "product_img_link": { - "type": "string", - "description": "The image URL of the product", - "nullable": true - }, - "product_id": { - "type": "string", - "description": "ID of the product that is being purchased", - "nullable": true - }, - "category": { - "type": "string", - "description": "Category of the product that is being purchased", - "nullable": true - }, - "sub_category": { - "type": "string", - "description": "Sub category of the product that is being purchased", - "nullable": true - }, - "brand": { - "type": "string", - "description": "Brand of the product that is being purchased", - "nullable": true - }, - "product_type": { - "allOf": [ - { - "$ref": "#/components/schemas/ProductType" - } - ], - "nullable": true - }, - "product_tax_code": { - "type": "string", - "description": "The tax code for the product", - "nullable": true - } - } - }, "OrderDetailsWithAmount": { "type": "object", "required": [ @@ -11940,7 +11876,21 @@ "minimum": 0 }, "amount": { - "$ref": "#/components/schemas/MinorUnit" + "type": "integer", + "format": "int64", + "description": "the amount per quantity of product" + }, + "tax_rate": { + "type": "number", + "format": "double", + "description": "tax rate applicable to the product", + "nullable": true + }, + "total_tax_amount": { + "type": "integer", + "format": "int64", + "description": "total tax amount applicable to the product", + "nullable": true }, "requires_shipping": { "type": "boolean", @@ -12353,6 +12303,17 @@ } } }, + { + "type": "object", + "required": [ + "klarna_checkout" + ], + "properties": { + "klarna_checkout": { + "type": "object" + } + } + }, { "type": "object", "required": [ @@ -12486,6 +12447,13 @@ "description": "The payment attempt amount. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc.,", "example": 6540 }, + "order_tax_amount": { + "type": "integer", + "format": "int64", + "description": "The payment attempt tax_amount.", + "example": 6540, + "nullable": true + }, "currency": { "allOf": [ { diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index 33dd5d87a4..57e4ac1948 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -14732,70 +14732,6 @@ } } }, - "OrderDetails": { - "type": "object", - "required": [ - "product_name", - "quantity" - ], - "properties": { - "product_name": { - "type": "string", - "description": "Name of the product that is being purchased", - "example": "shirt", - "maxLength": 255 - }, - "quantity": { - "type": "integer", - "format": "int32", - "description": "The quantity of the product to be purchased", - "example": 1, - "minimum": 0 - }, - "requires_shipping": { - "type": "boolean", - "nullable": true - }, - "product_img_link": { - "type": "string", - "description": "The image URL of the product", - "nullable": true - }, - "product_id": { - "type": "string", - "description": "ID of the product that is being purchased", - "nullable": true - }, - "category": { - "type": "string", - "description": "Category of the product that is being purchased", - "nullable": true - }, - "sub_category": { - "type": "string", - "description": "Sub category of the product that is being purchased", - "nullable": true - }, - "brand": { - "type": "string", - "description": "Brand of the product that is being purchased", - "nullable": true - }, - "product_type": { - "allOf": [ - { - "$ref": "#/components/schemas/ProductType" - } - ], - "nullable": true - }, - "product_tax_code": { - "type": "string", - "description": "The tax code for the product", - "nullable": true - } - } - }, "OrderDetailsWithAmount": { "type": "object", "required": [ @@ -14818,7 +14754,21 @@ "minimum": 0 }, "amount": { - "$ref": "#/components/schemas/MinorUnit" + "type": "integer", + "format": "int64", + "description": "the amount per quantity of product" + }, + "tax_rate": { + "type": "number", + "format": "double", + "description": "tax rate applicable to the product", + "nullable": true + }, + "total_tax_amount": { + "type": "integer", + "format": "int64", + "description": "total tax amount applicable to the product", + "nullable": true }, "requires_shipping": { "type": "boolean", @@ -15224,6 +15174,17 @@ } } }, + { + "type": "object", + "required": [ + "klarna_checkout" + ], + "properties": { + "klarna_checkout": { + "type": "object" + } + } + }, { "type": "object", "required": [ @@ -15357,6 +15318,13 @@ "description": "The payment attempt amount. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc.,", "example": 6540 }, + "order_tax_amount": { + "type": "integer", + "format": "int64", + "description": "The payment attempt tax_amount.", + "example": 6540, + "nullable": true + }, "currency": { "allOf": [ { @@ -17155,6 +17123,13 @@ "nullable": true, "minimum": 0 }, + "order_tax_amount": { + "type": "integer", + "format": "int64", + "description": "Total tax amount applicable to the order", + "example": 6540, + "nullable": true + }, "currency": { "allOf": [ { @@ -17533,6 +17508,13 @@ "description": "The payment amount. Amount for the payment in the lowest denomination of the currency, (i.e) in cents for USD denomination, in yen for JPY denomination etc. E.g., Pass 100 to charge $1.00 and 1 for 1¥ since ¥ is a zero-decimal currency. Read more about [the Decimal and Non-Decimal Currencies](https://github.com/juspay/hyperswitch/wiki/Decimal-and-Non%E2%80%90Decimal-Currencies)", "minimum": 0 }, + "order_tax_amount": { + "type": "integer", + "format": "int64", + "description": "Total tax amount applicable to the order", + "example": 6540, + "nullable": true + }, "currency": { "$ref": "#/components/schemas/Currency" }, @@ -18659,6 +18641,13 @@ "nullable": true, "minimum": 0 }, + "order_tax_amount": { + "type": "integer", + "format": "int64", + "description": "Total tax amount applicable to the order", + "example": 6540, + "nullable": true + }, "currency": { "allOf": [ { @@ -19805,6 +19794,13 @@ "nullable": true, "minimum": 0 }, + "order_tax_amount": { + "type": "integer", + "format": "int64", + "description": "Total tax amount applicable to the order", + "example": 6540, + "nullable": true + }, "currency": { "allOf": [ { diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 0381e347f4..632d40a095 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -741,6 +741,10 @@ pub struct PaymentsRequest { // Makes the field mandatory in PaymentsCreateRequest pub amount: Option, + /// Total tax amount applicable to the order + #[schema(value_type = Option, example = 6540)] + pub order_tax_amount: Option, + /// The three letter ISO currency code in uppercase. Eg: 'USD' to charge US Dollars #[schema(example = "USD", value_type = Option)] #[mandatory_in(PaymentsCreateRequest = Currency)] @@ -1308,6 +1312,9 @@ pub struct PaymentAttemptResponse { /// The payment attempt amount. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., #[schema(value_type = i64, example = 6540)] pub amount: MinorUnit, + /// The payment attempt tax_amount. + #[schema(value_type = Option, example = 6540)] + pub order_tax_amount: Option, /// The currency of the amount of the payment attempt #[schema(value_type = Option, example = "USD")] pub currency: Option, @@ -1858,6 +1865,7 @@ pub enum PayLaterData { /// The token for the sdk workflow token: String, }, + KlarnaCheckout {}, /// For Affirm redirect as PayLater Option AffirmRedirect {}, /// For AfterpayClearpay redirect as PayLater Option @@ -1915,6 +1923,7 @@ impl GetAddressFromPaymentMethodData for PayLaterData { | Self::WalleyRedirect {} | Self::AlmaRedirect {} | Self::KlarnaSdk { .. } + | Self::KlarnaCheckout {} | Self::AffirmRedirect {} | Self::AtomeRedirect {} => None, } @@ -2376,6 +2385,7 @@ impl GetPaymentMethodType for PayLaterData { match self { Self::KlarnaRedirect { .. } => api_enums::PaymentMethodType::Klarna, Self::KlarnaSdk { .. } => api_enums::PaymentMethodType::Klarna, + Self::KlarnaCheckout {} => api_enums::PaymentMethodType::Klarna, Self::AffirmRedirect {} => api_enums::PaymentMethodType::Affirm, Self::AfterpayClearpayRedirect { .. } => api_enums::PaymentMethodType::AfterpayClearpay, Self::PayBrightRedirect {} => api_enums::PaymentMethodType::PayBright, @@ -5471,7 +5481,7 @@ pub struct PaymentsRetrieveRequest { pub expand_attempts: Option, } -#[derive(Debug, Default, Eq, PartialEq, serde::Deserialize, serde::Serialize, Clone, ToSchema)] +#[derive(Debug, Default, PartialEq, serde::Deserialize, serde::Serialize, Clone, ToSchema)] pub struct OrderDetailsWithAmount { /// Name of the product that is being purchased #[schema(max_length = 255, example = "shirt")] @@ -5480,7 +5490,13 @@ pub struct OrderDetailsWithAmount { #[schema(example = 1)] pub quantity: u16, /// the amount per quantity of product + #[schema(value_type = i64)] pub amount: MinorUnit, + /// tax rate applicable to the product + pub tax_rate: Option, + /// total tax amount applicable to the product + #[schema(value_type = Option)] + pub total_tax_amount: Option, // Does the order includes shipping pub requires_shipping: Option, /// The image URL of the product @@ -5501,32 +5517,6 @@ pub struct OrderDetailsWithAmount { impl masking::SerializableSecret for OrderDetailsWithAmount {} -#[derive(Debug, Default, Eq, PartialEq, serde::Deserialize, serde::Serialize, Clone, ToSchema)] -pub struct OrderDetails { - /// Name of the product that is being purchased - #[schema(max_length = 255, example = "shirt")] - pub product_name: String, - /// The quantity of the product to be purchased - #[schema(example = 1)] - pub quantity: u16, - // Does the order include shipping - pub requires_shipping: Option, - /// The image URL of the product - pub product_img_link: Option, - /// ID of the product that is being purchased - pub product_id: Option, - /// Category of the product that is being purchased - pub category: Option, - /// Sub category of the product that is being purchased - pub sub_category: Option, - /// Brand of the product that is being purchased - pub brand: Option, - /// Type of the product that is being purchased - pub product_type: Option, - /// The tax code for the product - pub product_tax_code: Option, -} - #[derive(Default, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, Clone, ToSchema)] pub struct RedirectResponse { #[schema(value_type = Option)] diff --git a/crates/diesel_models/src/types.rs b/crates/diesel_models/src/types.rs index 94f1fa8d26..6562abab4d 100644 --- a/crates/diesel_models/src/types.rs +++ b/crates/diesel_models/src/types.rs @@ -30,6 +30,10 @@ pub struct OrderDetailsWithAmount { pub product_type: Option, /// The tax code for the product pub product_tax_code: Option, + /// tax rate applicable to the product + pub tax_rate: Option, + /// total tax amount applicable to the product + pub total_tax_amount: Option, } impl masking::SerializableSecret for OrderDetailsWithAmount {} diff --git a/crates/hyperswitch_connectors/src/connectors/multisafepay/transformers.rs b/crates/hyperswitch_connectors/src/connectors/multisafepay/transformers.rs index 479abf13b1..a60e8bdc79 100644 --- a/crates/hyperswitch_connectors/src/connectors/multisafepay/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/multisafepay/transformers.rs @@ -746,6 +746,7 @@ impl TryFrom<&MultisafepayRouterData<&types::PaymentsAuthorizeRouterData>> email: Some(match paylater { PayLaterData::KlarnaRedirect {} => item.router_data.get_billing_email()?, PayLaterData::KlarnaSdk { token: _ } + | PayLaterData::KlarnaCheckout {} | PayLaterData::AffirmRedirect {} | PayLaterData::AfterpayClearpayRedirect {} | PayLaterData::PayBrightRedirect {} diff --git a/crates/hyperswitch_connectors/src/connectors/square/transformers.rs b/crates/hyperswitch_connectors/src/connectors/square/transformers.rs index 08ca9a54fa..5abc93b3f8 100644 --- a/crates/hyperswitch_connectors/src/connectors/square/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/square/transformers.rs @@ -85,6 +85,7 @@ impl TryFrom<(&types::TokenizationRouterData, PayLaterData)> for SquareTokenRequ PayLaterData::AfterpayClearpayRedirect { .. } | PayLaterData::KlarnaRedirect { .. } | PayLaterData::KlarnaSdk { .. } + | PayLaterData::KlarnaCheckout {} | PayLaterData::AffirmRedirect { .. } | PayLaterData::PayBrightRedirect { .. } | PayLaterData::WalleyRedirect { .. } diff --git a/crates/hyperswitch_connectors/src/connectors/zen/transformers.rs b/crates/hyperswitch_connectors/src/connectors/zen/transformers.rs index 7a30a434a5..41dc60f824 100644 --- a/crates/hyperswitch_connectors/src/connectors/zen/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/zen/transformers.rs @@ -751,6 +751,7 @@ impl TryFrom<&PayLaterData> for ZenPaymentsRequest { match value { PayLaterData::KlarnaRedirect { .. } | PayLaterData::KlarnaSdk { .. } + | PayLaterData::KlarnaCheckout {} | PayLaterData::AffirmRedirect {} | PayLaterData::AfterpayClearpayRedirect { .. } | PayLaterData::PayBrightRedirect {} diff --git a/crates/hyperswitch_connectors/src/utils.rs b/crates/hyperswitch_connectors/src/utils.rs index 6dce48e699..cf32d966e0 100644 --- a/crates/hyperswitch_connectors/src/utils.rs +++ b/crates/hyperswitch_connectors/src/utils.rs @@ -2092,6 +2092,7 @@ pub enum PaymentMethodDataType { SwishQr, KlarnaRedirect, KlarnaSdk, + KlarnaCheckout, AffirmRedirect, AfterpayClearpayRedirect, PayBrightRedirect, @@ -2216,6 +2217,7 @@ impl From for PaymentMethodDataType { PaymentMethodData::PayLater(pay_later_data) => match pay_later_data { payment_method_data::PayLaterData::KlarnaRedirect { .. } => Self::KlarnaRedirect, payment_method_data::PayLaterData::KlarnaSdk { .. } => Self::KlarnaSdk, + payment_method_data::PayLaterData::KlarnaCheckout {} => Self::KlarnaCheckout, payment_method_data::PayLaterData::AffirmRedirect {} => Self::AffirmRedirect, payment_method_data::PayLaterData::AfterpayClearpayRedirect { .. } => { Self::AfterpayClearpayRedirect diff --git a/crates/hyperswitch_domain_models/src/lib.rs b/crates/hyperswitch_domain_models/src/lib.rs index 0e8722644b..6e353afd39 100644 --- a/crates/hyperswitch_domain_models/src/lib.rs +++ b/crates/hyperswitch_domain_models/src/lib.rs @@ -133,6 +133,8 @@ impl ApiModelToDieselModelConvertor for OrderDetailsW brand, product_type, product_tax_code, + tax_rate, + total_tax_amount, } = from; Self { product_name, @@ -146,6 +148,8 @@ impl ApiModelToDieselModelConvertor for OrderDetailsW brand, product_type, product_tax_code, + tax_rate, + total_tax_amount, } } @@ -162,6 +166,8 @@ impl ApiModelToDieselModelConvertor for OrderDetailsW brand, product_type, product_tax_code, + tax_rate, + total_tax_amount, } = self; ApiOrderDetailsWithAmount { product_name, @@ -175,6 +181,8 @@ impl ApiModelToDieselModelConvertor for OrderDetailsW brand, product_type, product_tax_code, + tax_rate, + total_tax_amount, } } } diff --git a/crates/hyperswitch_domain_models/src/payment_method_data.rs b/crates/hyperswitch_domain_models/src/payment_method_data.rs index 169719cb5d..8c19a20ef3 100644 --- a/crates/hyperswitch_domain_models/src/payment_method_data.rs +++ b/crates/hyperswitch_domain_models/src/payment_method_data.rs @@ -155,6 +155,7 @@ pub enum CardRedirectData { pub enum PayLaterData { KlarnaRedirect {}, KlarnaSdk { token: String }, + KlarnaCheckout {}, AffirmRedirect {}, AfterpayClearpayRedirect {}, PayBrightRedirect {}, @@ -897,6 +898,7 @@ impl From for PayLaterData { match value { api_models::payments::PayLaterData::KlarnaRedirect { .. } => Self::KlarnaRedirect {}, api_models::payments::PayLaterData::KlarnaSdk { token } => Self::KlarnaSdk { token }, + api_models::payments::PayLaterData::KlarnaCheckout {} => Self::KlarnaCheckout {}, api_models::payments::PayLaterData::AffirmRedirect {} => Self::AffirmRedirect {}, api_models::payments::PayLaterData::AfterpayClearpayRedirect { .. } => { Self::AfterpayClearpayRedirect {} @@ -1550,6 +1552,7 @@ impl GetPaymentMethodType for PayLaterData { match self { Self::KlarnaRedirect { .. } => api_enums::PaymentMethodType::Klarna, Self::KlarnaSdk { .. } => api_enums::PaymentMethodType::Klarna, + Self::KlarnaCheckout {} => api_enums::PaymentMethodType::Klarna, Self::AffirmRedirect {} => api_enums::PaymentMethodType::Affirm, Self::AfterpayClearpayRedirect { .. } => api_enums::PaymentMethodType::AfterpayClearpay, Self::PayBrightRedirect {} => api_enums::PaymentMethodType::PayBright, diff --git a/crates/hyperswitch_domain_models/src/router_request_types.rs b/crates/hyperswitch_domain_models/src/router_request_types.rs index 2f68b481d8..0e25e195c7 100644 --- a/crates/hyperswitch_domain_models/src/router_request_types.rs +++ b/crates/hyperswitch_domain_models/src/router_request_types.rs @@ -29,6 +29,7 @@ pub struct PaymentsAuthorizeData { /// get_total_surcharge_amount() // returns surcharge_amount + tax_on_surcharge_amount /// ``` pub amount: i64, + pub order_tax_amount: Option, pub email: Option, pub customer_name: Option>, pub currency: storage_enums::Currency, diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs index 65c76f8929..03c2803186 100644 --- a/crates/openapi/src/openapi.rs +++ b/crates/openapi/src/openapi.rs @@ -381,7 +381,6 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::SwishQrData, api_models::payments::AirwallexData, api_models::payments::NoonData, - api_models::payments::OrderDetails, api_models::payments::OrderDetailsWithAmount, api_models::payments::NextActionType, api_models::payments::WalletData, diff --git a/crates/openapi/src/openapi_v2.rs b/crates/openapi/src/openapi_v2.rs index b5de979b3a..c9e4595ef4 100644 --- a/crates/openapi/src/openapi_v2.rs +++ b/crates/openapi/src/openapi_v2.rs @@ -341,7 +341,6 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::SwishQrData, api_models::payments::AirwallexData, api_models::payments::NoonData, - api_models::payments::OrderDetails, api_models::payments::OrderDetailsWithAmount, api_models::payments::NextActionType, api_models::payments::WalletData, diff --git a/crates/router/src/connector/adyen/transformers.rs b/crates/router/src/connector/adyen/transformers.rs index d0dad91f71..aece1df654 100644 --- a/crates/router/src/connector/adyen/transformers.rs +++ b/crates/router/src/connector/adyen/transformers.rs @@ -2350,7 +2350,8 @@ impl check_required_field(billing_address, "billing")?; Ok(AdyenPaymentMethod::Atome) } - domain::payments::PayLaterData::KlarnaSdk { .. } => { + domain::payments::PayLaterData::KlarnaCheckout {} + | domain::payments::PayLaterData::KlarnaSdk { .. } => { Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("Adyen"), ) diff --git a/crates/router/src/connector/klarna.rs b/crates/router/src/connector/klarna.rs index d2bdaae049..77e2a027d8 100644 --- a/crates/router/src/connector/klarna.rs +++ b/crates/router/src/connector/klarna.rs @@ -448,7 +448,24 @@ impl let endpoint = build_region_specific_endpoint(self.base_url(connectors), &req.connector_meta_data)?; - Ok(format!("{endpoint}ordermanagement/v1/orders/{order_id}")) + let payment_experience = req.request.payment_experience; + + match payment_experience { + Some(common_enums::PaymentExperience::InvokeSdkClient) => { + Ok(format!("{endpoint}ordermanagement/v1/orders/{order_id}")) + } + Some(common_enums::PaymentExperience::RedirectToUrl) => { + Ok(format!("{endpoint}checkout/v3/orders/{order_id}")) + } + None => Err(error_stack::report!(errors::ConnectorError::NotSupported { + message: "payment_experience not supported".to_string(), + connector: "klarna", + })), + _ => Err(error_stack::report!(errors::ConnectorError::NotSupported { + message: "payment_experience not supported".to_string(), + connector: "klarna", + })), + } } fn build_request( @@ -653,6 +670,122 @@ impl })), } } + domain::PaymentMethodData::PayLater(domain::PayLaterData::KlarnaCheckout {}) => { + match (payment_experience, payment_method_type) { + ( + common_enums::PaymentExperience::RedirectToUrl, + common_enums::PaymentMethodType::Klarna, + ) => Ok(format!("{endpoint}checkout/v3/orders",)), + ( + common_enums::PaymentExperience::DisplayQrCode + | common_enums::PaymentExperience::DisplayWaitScreen + | common_enums::PaymentExperience::InvokePaymentApp + | common_enums::PaymentExperience::InvokeSdkClient + | common_enums::PaymentExperience::LinkWallet + | common_enums::PaymentExperience::OneClick + | common_enums::PaymentExperience::RedirectToUrl + | common_enums::PaymentExperience::CollectOtp, + common_enums::PaymentMethodType::Ach + | common_enums::PaymentMethodType::Affirm + | common_enums::PaymentMethodType::AfterpayClearpay + | common_enums::PaymentMethodType::Alfamart + | common_enums::PaymentMethodType::AliPay + | common_enums::PaymentMethodType::AliPayHk + | common_enums::PaymentMethodType::Alma + | common_enums::PaymentMethodType::ApplePay + | common_enums::PaymentMethodType::Atome + | common_enums::PaymentMethodType::Bacs + | common_enums::PaymentMethodType::BancontactCard + | common_enums::PaymentMethodType::Becs + | common_enums::PaymentMethodType::Benefit + | common_enums::PaymentMethodType::Bizum + | common_enums::PaymentMethodType::Blik + | common_enums::PaymentMethodType::Boleto + | common_enums::PaymentMethodType::BcaBankTransfer + | common_enums::PaymentMethodType::BniVa + | common_enums::PaymentMethodType::BriVa + | common_enums::PaymentMethodType::CardRedirect + | common_enums::PaymentMethodType::CimbVa + | common_enums::PaymentMethodType::ClassicReward + | common_enums::PaymentMethodType::Credit + | common_enums::PaymentMethodType::CryptoCurrency + | common_enums::PaymentMethodType::Cashapp + | common_enums::PaymentMethodType::Dana + | common_enums::PaymentMethodType::DanamonVa + | common_enums::PaymentMethodType::Debit + | common_enums::PaymentMethodType::DirectCarrierBilling + | common_enums::PaymentMethodType::Efecty + | common_enums::PaymentMethodType::Eps + | common_enums::PaymentMethodType::Evoucher + | common_enums::PaymentMethodType::Giropay + | common_enums::PaymentMethodType::Givex + | common_enums::PaymentMethodType::GooglePay + | common_enums::PaymentMethodType::GoPay + | common_enums::PaymentMethodType::Gcash + | common_enums::PaymentMethodType::Ideal + | common_enums::PaymentMethodType::Interac + | common_enums::PaymentMethodType::Indomaret + | common_enums::PaymentMethodType::Klarna + | common_enums::PaymentMethodType::KakaoPay + | common_enums::PaymentMethodType::MandiriVa + | common_enums::PaymentMethodType::Knet + | common_enums::PaymentMethodType::MbWay + | common_enums::PaymentMethodType::MobilePay + | common_enums::PaymentMethodType::Momo + | common_enums::PaymentMethodType::MomoAtm + | common_enums::PaymentMethodType::Multibanco + | common_enums::PaymentMethodType::LocalBankRedirect + | common_enums::PaymentMethodType::OnlineBankingThailand + | common_enums::PaymentMethodType::OnlineBankingCzechRepublic + | common_enums::PaymentMethodType::OnlineBankingFinland + | common_enums::PaymentMethodType::OnlineBankingFpx + | common_enums::PaymentMethodType::OnlineBankingPoland + | common_enums::PaymentMethodType::OnlineBankingSlovakia + | common_enums::PaymentMethodType::Oxxo + | common_enums::PaymentMethodType::PagoEfectivo + | common_enums::PaymentMethodType::PermataBankTransfer + | common_enums::PaymentMethodType::OpenBankingUk + | common_enums::PaymentMethodType::PayBright + | common_enums::PaymentMethodType::Paypal + | common_enums::PaymentMethodType::Paze + | common_enums::PaymentMethodType::Pix + | common_enums::PaymentMethodType::PaySafeCard + | common_enums::PaymentMethodType::Przelewy24 + | common_enums::PaymentMethodType::Pse + | common_enums::PaymentMethodType::RedCompra + | common_enums::PaymentMethodType::RedPagos + | common_enums::PaymentMethodType::SamsungPay + | common_enums::PaymentMethodType::Sepa + | common_enums::PaymentMethodType::Sofort + | common_enums::PaymentMethodType::Swish + | common_enums::PaymentMethodType::TouchNGo + | common_enums::PaymentMethodType::Trustly + | common_enums::PaymentMethodType::Twint + | common_enums::PaymentMethodType::UpiCollect + | common_enums::PaymentMethodType::UpiIntent + | common_enums::PaymentMethodType::Venmo + | common_enums::PaymentMethodType::Vipps + | common_enums::PaymentMethodType::Walley + | common_enums::PaymentMethodType::WeChatPay + | common_enums::PaymentMethodType::SevenEleven + | common_enums::PaymentMethodType::Lawson + | common_enums::PaymentMethodType::LocalBankTransfer + | common_enums::PaymentMethodType::MiniStop + | common_enums::PaymentMethodType::FamilyMart + | common_enums::PaymentMethodType::Seicomart + | common_enums::PaymentMethodType::PayEasy + | common_enums::PaymentMethodType::Mifinity + | common_enums::PaymentMethodType::Fps + | common_enums::PaymentMethodType::DuitNow + | common_enums::PaymentMethodType::PromptPay + | common_enums::PaymentMethodType::VietQr + | common_enums::PaymentMethodType::OpenBankingPIS, + ) => Err(error_stack::report!(errors::ConnectorError::NotSupported { + message: payment_method_type.to_string(), + connector: "klarna", + })), + } + } domain::PaymentMethodData::Card(_) | domain::PaymentMethodData::CardRedirect(_) @@ -726,7 +859,7 @@ impl event_builder: Option<&mut ConnectorEvent>, res: Response, ) -> CustomResult { - let response: klarna::KlarnaPaymentsResponse = res + let response: klarna::KlarnaAuthResponse = res .response .parse_struct("KlarnaPaymentsResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; diff --git a/crates/router/src/connector/klarna/transformers.rs b/crates/router/src/connector/klarna/transformers.rs index 803dc4a428..0826b0f266 100644 --- a/crates/router/src/connector/klarna/transformers.rs +++ b/crates/router/src/connector/klarna/transformers.rs @@ -1,7 +1,9 @@ use api_models::payments; use common_utils::{pii, types::MinorUnit}; use error_stack::{report, ResultExt}; -use hyperswitch_domain_models::router_data::KlarnaSdkResponse; +use hyperswitch_domain_models::{ + router_data::KlarnaSdkResponse, router_response_types::RedirectForm, +}; use masking::{ExposeInterface, Secret}; use serde::{Deserialize, Serialize}; @@ -10,7 +12,7 @@ use crate::{ self, AddressData, AddressDetailsData, PaymentsAuthorizeRequestData, RouterData, }, core::errors, - types::{self, api, storage::enums, transformers::ForeignFrom}, + types::{self, api, domain, storage::enums, transformers::ForeignFrom}, }; #[derive(Debug, Serialize)] @@ -61,9 +63,29 @@ impl TryFrom<&Option> for KlarnaConnectorMetadataObject { } } -#[derive(Default, Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] +#[serde(untagged)] +pub enum PaymentMethodSpecifics { + KlarnaCheckout(KlarnaCheckoutRequestData), + KlarnaSdk, +} + +#[derive(Default, Debug, Serialize, Deserialize)] +pub struct MerchantURLs { + terms: String, + checkout: String, + confirmation: String, + push: String, +} + +#[derive(Default, Debug, Serialize, Deserialize)] +pub struct KlarnaCheckoutRequestData { + merchant_urls: MerchantURLs, + options: CheckoutOptions, +} + +#[derive(Default, Debug, Deserialize, Serialize)] pub struct KlarnaPaymentsRequest { - auto_capture: bool, order_lines: Vec, order_amount: MinorUnit, purchase_country: enums::CountryAlpha2, @@ -71,15 +93,32 @@ pub struct KlarnaPaymentsRequest { merchant_reference1: Option, merchant_reference2: Option, shipping_address: Option, + auto_capture: Option, + order_tax_amount: Option, + #[serde(flatten)] + payment_method_specifics: Option, } #[derive(Debug, Deserialize, Serialize)] -pub struct KlarnaPaymentsResponse { +#[serde(untagged)] +pub enum KlarnaAuthResponse { + KlarnaPaymentsAuthResponse(PaymentsResponse), + KlarnaCheckoutAuthResponse(CheckoutResponse), +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct PaymentsResponse { order_id: String, fraud_status: KlarnaFraudStatus, authorized_payment_method: Option, } +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct CheckoutResponse { + order_id: String, + status: KlarnaCheckoutStatus, + html_snippet: String, +} #[derive(Debug, Clone, Deserialize, Serialize)] pub struct AuthorizedPaymentMethod { #[serde(rename = "type")] @@ -106,7 +145,7 @@ pub struct KlarnaSessionRequest { shipping_address: Option, } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct KlarnaShippingAddress { city: String, country: enums::CountryAlpha2, @@ -120,6 +159,10 @@ pub struct KlarnaShippingAddress { street_address2: Option>, } +#[derive(Default, Debug, Serialize, Deserialize)] +pub struct CheckoutOptions { + auto_capture: bool, +} #[derive(Deserialize, Serialize, Debug)] pub struct KlarnaSessionResponse { pub client_token: Secret, @@ -149,6 +192,8 @@ impl TryFrom<&KlarnaRouterData<&types::PaymentsSessionRouterData>> for KlarnaSes quantity: data.quantity, unit_price: data.amount, total_amount: data.amount * data.quantity, + total_tax_amount: None, + tax_rate: None, }) .collect(), shipping_address: get_address_info(item.router_data.get_optional_shipping()) @@ -190,29 +235,100 @@ impl TryFrom<&KlarnaRouterData<&types::PaymentsAuthorizeRouterData>> for KlarnaP item: &KlarnaRouterData<&types::PaymentsAuthorizeRouterData>, ) -> Result { let request = &item.router_data.request; - match request.order_details.clone() { - Some(order_details) => Ok(Self { - purchase_country: item.router_data.get_billing_country()?, - purchase_currency: request.currency, - order_amount: item.amount, - order_lines: order_details - .iter() - .map(|data| OrderLines { - name: data.product_name.clone(), - quantity: data.quantity, - unit_price: data.amount, - total_amount: data.amount * data.quantity, - }) - .collect(), - merchant_reference1: Some(item.router_data.connector_request_reference_id.clone()), - merchant_reference2: item.router_data.request.merchant_order_reference_id.clone(), - auto_capture: request.is_auto_capture()?, - shipping_address: get_address_info(item.router_data.get_optional_shipping()) - .transpose()?, - }), - None => Err(report!(errors::ConnectorError::MissingRequiredField { - field_name: "order_details" - })), + let payment_method_data = request.payment_method_data.clone(); + let return_url = item.router_data.request.get_return_url()?; + let webhook_url = item.router_data.request.get_webhook_url()?; + match payment_method_data { + domain::PaymentMethodData::PayLater(domain::PayLaterData::KlarnaSdk { .. }) => { + match request.order_details.clone() { + Some(order_details) => Ok(Self { + purchase_country: item.router_data.get_billing_country()?, + purchase_currency: request.currency, + order_amount: item.amount, + order_lines: order_details + .iter() + .map(|data| OrderLines { + name: data.product_name.clone(), + quantity: data.quantity, + unit_price: data.amount, + total_amount: data.amount * data.quantity, + total_tax_amount: None, + tax_rate: None, + }) + .collect(), + merchant_reference1: Some( + item.router_data.connector_request_reference_id.clone(), + ), + merchant_reference2: item + .router_data + .request + .merchant_order_reference_id + .clone(), + auto_capture: Some(request.is_auto_capture()?), + shipping_address: get_address_info( + item.router_data.get_optional_shipping(), + ) + .transpose()?, + order_tax_amount: None, + payment_method_specifics: None, + }), + None => Err(report!(errors::ConnectorError::MissingRequiredField { + field_name: "order_details" + })), + } + } + domain::PaymentMethodData::PayLater(domain::PayLaterData::KlarnaCheckout {}) => { + match request.order_details.clone() { + Some(order_details) => Ok(Self { + purchase_country: item.router_data.get_billing_country()?, + purchase_currency: request.currency, + order_amount: item.amount + - request.order_tax_amount.unwrap_or(MinorUnit::zero()), + order_tax_amount: request.order_tax_amount, + order_lines: order_details + .iter() + .map(|data| OrderLines { + name: data.product_name.clone(), + quantity: data.quantity, + unit_price: data.amount, + total_amount: data.amount * data.quantity, + total_tax_amount: data.total_tax_amount, + tax_rate: data.tax_rate, + }) + .collect(), + payment_method_specifics: Some(PaymentMethodSpecifics::KlarnaCheckout( + KlarnaCheckoutRequestData { + merchant_urls: MerchantURLs { + terms: return_url.clone(), + checkout: return_url.clone(), + confirmation: return_url, + push: webhook_url, + }, + options: CheckoutOptions { + auto_capture: request.is_auto_capture()?, + }, + }, + )), + shipping_address: get_address_info( + item.router_data.get_optional_shipping(), + ) + .transpose()?, + merchant_reference1: Some( + item.router_data.connector_request_reference_id.clone(), + ), + merchant_reference2: item + .router_data + .request + .merchant_order_reference_id + .clone(), + auto_capture: None, + }), + None => Err(report!(errors::ConnectorError::MissingRequiredField { + field_name: "order_details" + })), + } + } + _ => Err(errors::ConnectorError::NotImplemented("Payment method".to_string()).into()), } } } @@ -240,53 +356,82 @@ fn get_address_info( }) } -impl TryFrom> +impl TryFrom> for types::PaymentsAuthorizeRouterData { type Error = error_stack::Report; - fn try_from( - item: types::PaymentsResponseRouterData, - ) -> Result { - let connector_response = types::ConnectorResponseData::with_additional_payment_method_data( - match item.response.authorized_payment_method { - Some(authorized_payment_method) => { - types::AdditionalPaymentMethodConnectorResponse::from(authorized_payment_method) - } - None => { - types::AdditionalPaymentMethodConnectorResponse::PayLater { klarna_sdk: None } - } - }, - ); - Ok(Self { - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId( - item.response.order_id.clone(), - ), - redirection_data: Box::new(None), - mandate_reference: Box::new(None), - connector_metadata: None, - network_txn_id: None, - connector_response_reference_id: Some(item.response.order_id.clone()), - incremental_authorization_allowed: None, - charge_id: None, + fn try_from( + item: types::PaymentsResponseRouterData, + ) -> Result { + match item.response { + KlarnaAuthResponse::KlarnaPaymentsAuthResponse(ref response) => { + let connector_response = + response + .authorized_payment_method + .as_ref() + .map(|authorized_payment_method| { + types::ConnectorResponseData::with_additional_payment_method_data( + types::AdditionalPaymentMethodConnectorResponse::from( + authorized_payment_method.clone(), + ), + ) + }); + + Ok(Self { + response: Ok(types::PaymentsResponseData::TransactionResponse { + resource_id: types::ResponseId::ConnectorTransactionId( + response.order_id.clone(), + ), + redirection_data: Box::new(None), + mandate_reference: Box::new(None), + connector_metadata: None, + network_txn_id: None, + connector_response_reference_id: Some(response.order_id.clone()), + incremental_authorization_allowed: None, + charge_id: None, + }), + status: enums::AttemptStatus::foreign_from(( + response.fraud_status.clone(), + item.data.request.is_auto_capture()?, + )), + connector_response, + ..item.data + }) + } + KlarnaAuthResponse::KlarnaCheckoutAuthResponse(ref response) => Ok(Self { + response: Ok(types::PaymentsResponseData::TransactionResponse { + resource_id: types::ResponseId::ConnectorTransactionId( + response.order_id.clone(), + ), + redirection_data: Box::new(Some(RedirectForm::Html { + html_data: response.html_snippet.clone(), + })), + mandate_reference: Box::new(None), + connector_metadata: None, + network_txn_id: None, + connector_response_reference_id: Some(response.order_id.clone()), + incremental_authorization_allowed: None, + charge_id: None, + }), + status: enums::AttemptStatus::foreign_from(( + response.status.clone(), + item.data.request.is_auto_capture()?, + )), + connector_response: None, + ..item.data }), - status: enums::AttemptStatus::foreign_from(( - item.response.fraud_status, - item.data.request.is_auto_capture()?, - )), - connector_response: Some(connector_response), - ..item.data - }) + } } } - -#[derive(Debug, Serialize)] +#[derive(Default, Debug, Serialize, Deserialize)] pub struct OrderLines { name: String, quantity: u16, unit_price: MinorUnit, total_amount: MinorUnit, + total_tax_amount: Option, + tax_rate: Option, } #[derive(Debug, Serialize)] @@ -325,6 +470,13 @@ pub enum KlarnaFraudStatus { Rejected, } +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum KlarnaCheckoutStatus { + CheckoutComplete, + CheckoutIncomplete, +} + impl ForeignFrom<(KlarnaFraudStatus, bool)> for enums::AttemptStatus { fn foreign_from((klarna_status, is_auto_capture): (KlarnaFraudStatus, bool)) -> Self { match klarna_status { @@ -341,13 +493,42 @@ impl ForeignFrom<(KlarnaFraudStatus, bool)> for enums::AttemptStatus { } } +impl ForeignFrom<(KlarnaCheckoutStatus, bool)> for enums::AttemptStatus { + fn foreign_from((klarna_status, is_auto_capture): (KlarnaCheckoutStatus, bool)) -> Self { + match klarna_status { + KlarnaCheckoutStatus::CheckoutIncomplete => { + if is_auto_capture { + Self::AuthenticationPending + } else { + Self::Authorized + } + } + KlarnaCheckoutStatus::CheckoutComplete => Self::Charged, + } + } +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(untagged)] +pub enum KlarnaPsyncResponse { + KlarnaSDKPsyncResponse(KlarnaSDKSyncResponse), + KlarnaCheckoutPSyncResponse(KlarnaCheckoutSyncResponse), +} + #[derive(Debug, Serialize, Deserialize)] -pub struct KlarnaPsyncResponse { +pub struct KlarnaSDKSyncResponse { pub order_id: String, pub status: KlarnaPaymentStatus, pub klarna_reference: Option, } +#[derive(Debug, Serialize, Deserialize)] +pub struct KlarnaCheckoutSyncResponse { + pub order_id: String, + pub status: KlarnaCheckoutStatus, + pub options: CheckoutOptions, +} + #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum KlarnaPaymentStatus { @@ -379,25 +560,45 @@ impl fn try_from( item: types::ResponseRouterData, ) -> Result { - Ok(Self { - status: enums::AttemptStatus::from(item.response.status), - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId( - item.response.order_id.clone(), - ), - redirection_data: Box::new(None), - mandate_reference: Box::new(None), - connector_metadata: None, - network_txn_id: None, - connector_response_reference_id: item - .response - .klarna_reference - .or(Some(item.response.order_id)), - incremental_authorization_allowed: None, - charge_id: None, + match item.response { + KlarnaPsyncResponse::KlarnaSDKPsyncResponse(response) => Ok(Self { + status: enums::AttemptStatus::from(response.status), + response: Ok(types::PaymentsResponseData::TransactionResponse { + resource_id: types::ResponseId::ConnectorTransactionId( + response.order_id.clone(), + ), + redirection_data: Box::new(None), + mandate_reference: Box::new(None), + connector_metadata: None, + network_txn_id: None, + connector_response_reference_id: response + .klarna_reference + .or(Some(response.order_id.clone())), + incremental_authorization_allowed: None, + charge_id: None, + }), + ..item.data }), - ..item.data - }) + KlarnaPsyncResponse::KlarnaCheckoutPSyncResponse(response) => Ok(Self { + status: enums::AttemptStatus::foreign_from(( + response.status.clone(), + response.options.auto_capture, + )), + response: Ok(types::PaymentsResponseData::TransactionResponse { + resource_id: types::ResponseId::ConnectorTransactionId( + response.order_id.clone(), + ), + redirection_data: Box::new(None), + mandate_reference: Box::new(None), + connector_metadata: None, + network_txn_id: None, + connector_response_reference_id: Some(response.order_id.clone()), + incremental_authorization_allowed: None, + charge_id: None, + }), + ..item.data + }), + } } } diff --git a/crates/router/src/connector/nuvei/transformers.rs b/crates/router/src/connector/nuvei/transformers.rs index 121ec1d7b7..a4195655ed 100644 --- a/crates/router/src/connector/nuvei/transformers.rs +++ b/crates/router/src/connector/nuvei/transformers.rs @@ -977,6 +977,7 @@ where get_pay_later_info(AlternativePaymentMethodType::AfterPay, item) } domain::PayLaterData::KlarnaSdk { .. } + | domain::PayLaterData::KlarnaCheckout {} | domain::PayLaterData::AffirmRedirect {} | domain::PayLaterData::PayBrightRedirect {} | domain::PayLaterData::WalleyRedirect {} diff --git a/crates/router/src/connector/paypal/transformers.rs b/crates/router/src/connector/paypal/transformers.rs index 11e01b78e1..600b7ab0e2 100644 --- a/crates/router/src/connector/paypal/transformers.rs +++ b/crates/router/src/connector/paypal/transformers.rs @@ -1256,6 +1256,7 @@ impl TryFrom<&domain::PayLaterData> for PaypalPaymentsRequest { match value { domain::PayLaterData::KlarnaRedirect { .. } | domain::PayLaterData::KlarnaSdk { .. } + | domain::PayLaterData::KlarnaCheckout {} | domain::PayLaterData::AffirmRedirect {} | domain::PayLaterData::AfterpayClearpayRedirect { .. } | domain::PayLaterData::PayBrightRedirect {} diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 2f0b0e0316..262b0348b5 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -992,6 +992,7 @@ impl TryFrom<&domain::payments::PayLaterData> for StripePaymentMethodType { } domain::PayLaterData::KlarnaSdk { .. } + | domain::PayLaterData::KlarnaCheckout {} | domain::PayLaterData::PayBrightRedirect {} | domain::PayLaterData::WalleyRedirect {} | domain::PayLaterData::AlmaRedirect {} diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index 1ea7565f69..171f19bc70 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -2793,6 +2793,7 @@ pub enum PaymentMethodDataType { SwishQr, KlarnaRedirect, KlarnaSdk, + KlarnaCheckout, AffirmRedirect, AfterpayClearpayRedirect, PayBrightRedirect, @@ -2916,6 +2917,7 @@ impl From for PaymentMethodDataType { domain::payments::PaymentMethodData::PayLater(pay_later_data) => match pay_later_data { domain::payments::PayLaterData::KlarnaRedirect { .. } => Self::KlarnaRedirect, domain::payments::PayLaterData::KlarnaSdk { .. } => Self::KlarnaSdk, + domain::payments::PayLaterData::KlarnaCheckout {} => Self::KlarnaCheckout, domain::payments::PayLaterData::AffirmRedirect {} => Self::AffirmRedirect, domain::payments::PayLaterData::AfterpayClearpayRedirect { .. } => { Self::AfterpayClearpayRedirect diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index aa551ce6ff..9640693244 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -1514,6 +1514,7 @@ impl UpdateTracker, api::PaymentsRequest> for surcharge_amount, tax_amount, ), + connector_mandate_detail: payment_data .payment_attempt .connector_mandate_detail, diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index a316d6edc3..36b338f2d5 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -1428,6 +1428,15 @@ impl PaymentCreate { let skip_external_tax_calculation = request.skip_external_tax_calculation; + let tax_details = request + .order_tax_amount + .map(|tax_amount| diesel_models::TaxDetails { + default: Some(diesel_models::DefaultTax { + order_tax_amount: tax_amount, + }), + payment_method_type: None, + }); + Ok(storage::PaymentIntent { payment_id: payment_id.to_owned(), merchant_id: merchant_account.get_id().to_owned(), @@ -1482,7 +1491,7 @@ impl PaymentCreate { is_payment_processor_token_flow, organization_id: merchant_account.organization_id.clone(), shipping_cost: request.shipping_cost, - tax_details: None, + tax_details, skip_external_tax_calculation, psd2_sca_exemption_type: request.psd2_sca_exemption_type, }) diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 85bc51a09a..528eb99e7d 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -259,6 +259,7 @@ pub async fn construct_payment_router_data_for_authorize<'a>( .net_amount .get_amount_as_i64(), minor_amount: payment_data.payment_attempt.amount_details.net_amount, + order_tax_amount: None, currency: payment_data.payment_intent.amount_details.currency, browser_info: None, email: None, @@ -2427,25 +2428,6 @@ pub fn mobile_payment_next_steps_check( Ok(mobile_payment_next_step) } -pub fn change_order_details_to_new_type( - order_amount: MinorUnit, - order_details: api_models::payments::OrderDetails, -) -> Option> { - Some(vec![api_models::payments::OrderDetailsWithAmount { - product_name: order_details.product_name, - quantity: order_details.quantity, - amount: order_amount, - product_img_link: order_details.product_img_link, - requires_shipping: order_details.requires_shipping, - product_id: order_details.product_id, - category: order_details.category, - sub_category: order_details.sub_category, - brand: order_details.brand, - product_type: order_details.product_type, - product_tax_code: order_details.product_tax_code, - }]) -} - impl ForeignFrom for api_models::payments::NextActionData { fn foreign_from(qr_info: api_models::payments::QrCodeInformation) -> Self { match qr_info { @@ -2625,6 +2607,10 @@ impl TryFrom> for types::PaymentsAuthoriz statement_descriptor: payment_data.payment_intent.statement_descriptor_name, capture_method: payment_data.payment_attempt.capture_method, amount: amount.get_amount_as_i64(), + order_tax_amount: payment_data + .payment_attempt + .net_amount + .get_order_tax_amount(), minor_amount: amount, currency: payment_data.currency, browser_info, @@ -2961,7 +2947,6 @@ impl TryFrom> for types::SdkPaymentsSessi #[cfg(feature = "v1")] impl TryFrom> for types::SdkPaymentsSessionUpdateData { type Error = error_stack::Report; - fn try_from(additional_data: PaymentAdditionalData<'_, F>) -> Result { let payment_data = additional_data.payment_data; let order_tax_amount = payment_data diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index 2ab4337851..de4c063c41 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -873,6 +873,7 @@ impl ForeignFrom<&SetupMandateRouterData> for PaymentsAuthorizeData { email: data.request.email.clone(), customer_name: data.request.customer_name.clone(), amount: 0, + order_tax_amount: Some(MinorUnit::zero()), minor_amount: MinorUnit::new(0), statement_descriptor: None, capture_method: None, diff --git a/crates/router/src/types/api/verify_connector.rs b/crates/router/src/types/api/verify_connector.rs index 3bd3187313..bd55bd96b9 100644 --- a/crates/router/src/types/api/verify_connector.rs +++ b/crates/router/src/types/api/verify_connector.rs @@ -29,6 +29,7 @@ impl VerifyConnectorData { amount: 1000, minor_amount: common_utils::types::MinorUnit::new(1000), confirm: true, + order_tax_amount: None, currency: storage_enums::Currency::USD, metadata: None, mandate_id: None, diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index d4cd577543..1f55aa5801 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -1239,6 +1239,7 @@ impl ForeignFrom for payments::PaymentAttemptResponse { attempt_id: payment_attempt.attempt_id, status: payment_attempt.status, amount: payment_attempt.net_amount.get_order_amount(), + order_tax_amount: payment_attempt.net_amount.get_order_tax_amount(), currency: payment_attempt.currency, connector: payment_attempt.connector, error_message: payment_attempt.error_reason, diff --git a/crates/router/tests/connectors/payme.rs b/crates/router/tests/connectors/payme.rs index 1994acb6a6..15f980e242 100644 --- a/crates/router/tests/connectors/payme.rs +++ b/crates/router/tests/connectors/payme.rs @@ -90,6 +90,8 @@ fn payment_method_details() -> Option { brand: None, product_type: None, product_tax_code: None, + tax_rate: None, + total_tax_amount: None, }]), router_return_url: Some("https://hyperswitch.io".to_string()), webhook_url: Some("https://hyperswitch.io".to_string()), @@ -391,6 +393,8 @@ async fn should_fail_payment_for_incorrect_cvc() { brand: None, product_type: None, product_tax_code: None, + tax_rate: None, + total_tax_amount: None, }]), router_return_url: Some("https://hyperswitch.io".to_string()), webhook_url: Some("https://hyperswitch.io".to_string()), @@ -431,6 +435,8 @@ async fn should_fail_payment_for_invalid_exp_month() { brand: None, product_type: None, product_tax_code: None, + tax_rate: None, + total_tax_amount: None, }]), router_return_url: Some("https://hyperswitch.io".to_string()), webhook_url: Some("https://hyperswitch.io".to_string()), @@ -471,6 +477,8 @@ async fn should_fail_payment_for_incorrect_expiry_year() { brand: None, product_type: None, product_tax_code: None, + tax_rate: None, + total_tax_amount: None, }]), router_return_url: Some("https://hyperswitch.io".to_string()), webhook_url: Some("https://hyperswitch.io".to_string()), diff --git a/crates/router/tests/connectors/utils.rs b/crates/router/tests/connectors/utils.rs index f195aeaf7c..489b55a227 100644 --- a/crates/router/tests/connectors/utils.rs +++ b/crates/router/tests/connectors/utils.rs @@ -939,6 +939,7 @@ impl Default for PaymentAuthorizeType { payment_method_data: types::domain::PaymentMethodData::Card(CCardType::default().0), amount: 100, minor_amount: MinorUnit::new(100), + order_tax_amount: Some(MinorUnit::zero()), currency: enums::Currency::USD, confirm: true, statement_descriptor_suffix: None, diff --git a/crates/router/tests/connectors/zen.rs b/crates/router/tests/connectors/zen.rs index de60c5e8d8..a13fe48d25 100644 --- a/crates/router/tests/connectors/zen.rs +++ b/crates/router/tests/connectors/zen.rs @@ -334,6 +334,8 @@ async fn should_fail_payment_for_incorrect_card_number() { brand: None, product_type: None, product_tax_code: None, + tax_rate: None, + total_tax_amount: None, }]), email: Some(Email::from_str("test@gmail.com").unwrap()), webhook_url: Some("https://1635-116-74-253-164.ngrok-free.app".to_string()), @@ -377,6 +379,8 @@ async fn should_fail_payment_for_incorrect_cvc() { brand: None, product_type: None, product_tax_code: None, + tax_rate: None, + total_tax_amount: None, }]), email: Some(Email::from_str("test@gmail.com").unwrap()), webhook_url: Some("https://1635-116-74-253-164.ngrok-free.app".to_string()), @@ -420,6 +424,8 @@ async fn should_fail_payment_for_invalid_exp_month() { brand: None, product_type: None, product_tax_code: None, + tax_rate: None, + total_tax_amount: None, }]), email: Some(Email::from_str("test@gmail.com").unwrap()), webhook_url: Some("https://1635-116-74-253-164.ngrok-free.app".to_string()), @@ -463,6 +469,8 @@ async fn should_fail_payment_for_incorrect_expiry_year() { brand: None, product_type: None, product_tax_code: None, + tax_rate: None, + total_tax_amount: None, }]), email: Some(Email::from_str("test@gmail.com").unwrap()), webhook_url: Some("https://1635-116-74-253-164.ngrok-free.app".to_string()),