diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index a84cf8d525a0..0c8a0d9d323c 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -582,8 +582,8 @@ pub struct PaymentsRequest { pub amount: Option, /// Total tax amount applicable to the order - #[schema(value_type = Option, example = 6540)] - pub order_tax_amount: Option, + #[schema(value_type = i64, example = 6540)] + pub order_tax_amount: MinorUnit, /// The three letter ISO currency code in uppercase. Eg: 'USD' to charge US Dollars #[schema(example = "USD", value_type = Option)] @@ -1151,6 +1151,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 = i64, 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, @@ -2414,7 +2417,6 @@ pub enum AdditionalPaymentData { }, PayLater { klarna_sdk: Option, - klarna_checkout: Option, }, BankTransfer { #[serde(flatten)] @@ -3677,7 +3679,6 @@ pub struct VoucherResponse { #[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, ToSchema)] pub struct PaylaterResponse { klarna_sdk: Option, - klarna_checkout: Option, } #[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, ToSchema)] @@ -3701,13 +3702,6 @@ pub enum WalletResponseData { pub struct KlarnaSdkPaymentMethodResponse { pub payment_type: Option, } - -#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize, ToSchema)] - -pub struct KlarnaCheckoutPaymentMethodResponse { - pub payment_type: Option, -} - #[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, ToSchema, serde::Serialize)] pub struct PaymentMethodDataResponseWithBilling { // The struct is flattened in order to provide backwards compatibility @@ -5169,17 +5163,6 @@ impl From for PaylaterResponse { klarna_sdk: Some(KlarnaSdkPaymentMethodResponse { payment_type: klarna_sdk.payment_type, }), - klarna_checkout: None, - } - } -} -impl From for PaylaterResponse { - fn from(klarna_checkout: KlarnaCheckoutPaymentMethod) -> Self { - Self { - klarna_checkout: Some(KlarnaCheckoutPaymentMethodResponse { - payment_type: klarna_checkout.payment_type, - }), - klarna_sdk: None, } } } @@ -5188,16 +5171,9 @@ impl From for PaymentMethodDataResponse { fn from(payment_method_data: AdditionalPaymentData) -> Self { match payment_method_data { AdditionalPaymentData::Card(card) => Self::Card(Box::new(CardResponse::from(*card))), - AdditionalPaymentData::PayLater { - klarna_sdk, - klarna_checkout, - } => match (klarna_sdk, klarna_checkout) { - (Some(sdk), _) => Self::PayLater(Box::new(PaylaterResponse::from(sdk))), - (_, Some(checkout)) => Self::PayLater(Box::new(PaylaterResponse::from(checkout))), - (None, None) => Self::PayLater(Box::new(PaylaterResponse { - klarna_sdk: None, - klarna_checkout: None, - })), + AdditionalPaymentData::PayLater { klarna_sdk } => match klarna_sdk { + Some(sdk) => Self::PayLater(Box::new(PaylaterResponse::from(sdk))), + None => Self::PayLater(Box::new(PaylaterResponse { klarna_sdk: None })), }, AdditionalPaymentData::Wallet { @@ -5359,36 +5335,6 @@ pub struct OrderDetailsWithAmount { impl masking::SerializableSecret for OrderDetailsWithAmount {} -#[derive(Debug, Default, 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, - /// tax rate applicable to the product - pub tax_rate: Option, - /// total tax amount applicable to the product - pub total_tax_amount: Option, - // 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/payment_attempt.rs b/crates/diesel_models/src/payment_attempt.rs index 7760ea76c500..d8eb8255f5ef 100644 --- a/crates/diesel_models/src/payment_attempt.rs +++ b/crates/diesel_models/src/payment_attempt.rs @@ -289,6 +289,7 @@ pub struct PaymentAttemptNew { pub attempt_id: String, pub status: storage_enums::AttemptStatus, pub amount: MinorUnit, + pub order_tax_amount: Option, pub currency: Option, // pub auto_capture: Option, pub save_to_locker: Option, @@ -349,7 +350,6 @@ pub struct PaymentAttemptNew { pub organization_id: id_type::OrganizationId, pub card_network: Option, pub shipping_cost: Option, - pub order_tax_amount: Option, pub connector_mandate_detail: Option, } diff --git a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs index ec1463d1b7b5..d13b18392bdb 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs @@ -432,6 +432,7 @@ pub struct PaymentAttempt { pub status: storage_enums::AttemptStatus, pub net_amount: NetAmount, pub currency: Option, + pub order_tax_amount: Option, pub save_to_locker: Option, pub connector: Option, pub error_message: Option, @@ -679,6 +680,7 @@ pub struct PaymentAttemptNew { /// This field will always be derived before updating in the Database pub net_amount: NetAmount, pub currency: Option, + pub order_tax_amount: Option, // pub auto_capture: Option, pub save_to_locker: Option, pub connector: Option, @@ -1465,6 +1467,7 @@ impl behaviour::Conversion for PaymentAttempt { storage_model.tax_amount, ), currency: storage_model.currency, + order_tax_amount: storage_model.order_tax_amount, save_to_locker: storage_model.save_to_locker, connector: storage_model.connector, error_message: storage_model.error_message, diff --git a/crates/hyperswitch_domain_models/src/router_data.rs b/crates/hyperswitch_domain_models/src/router_data.rs index b23036e7c0df..59953d3cec46 100644 --- a/crates/hyperswitch_domain_models/src/router_data.rs +++ b/crates/hyperswitch_domain_models/src/router_data.rs @@ -348,7 +348,6 @@ pub enum AdditionalPaymentMethodConnectorResponse { }, PayLater { klarna_sdk: Option, - klarna_checkout: Option, }, } @@ -357,11 +356,6 @@ pub struct KlarnaSdkResponse { pub payment_type: Option, } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -pub struct KlarnaCheckoutResponse { - pub payment_type: Option, -} - #[derive(Clone, Debug, serde::Serialize)] pub struct ErrorResponse { pub code: String, diff --git a/crates/hyperswitch_domain_models/src/router_request_types.rs b/crates/hyperswitch_domain_models/src/router_request_types.rs index c282afa9d0d6..fbc7af732ac6 100644 --- a/crates/hyperswitch_domain_models/src/router_request_types.rs +++ b/crates/hyperswitch_domain_models/src/router_request_types.rs @@ -32,6 +32,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 ad61eb366429..ba0fe957f87e 100644 --- a/crates/openapi/src/openapi.rs +++ b/crates/openapi/src/openapi.rs @@ -363,11 +363,9 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::CardResponse, api_models::payments::PaylaterResponse, api_models::payments::KlarnaSdkPaymentMethodResponse, - api_models::payments::KlarnaCheckoutPaymentMethodResponse, 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 61052765a5ca..3fe690ec4459 100644 --- a/crates/openapi/src/openapi_v2.rs +++ b/crates/openapi/src/openapi_v2.rs @@ -309,11 +309,9 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::CardResponse, api_models::payments::PaylaterResponse, api_models::payments::KlarnaSdkPaymentMethodResponse, - api_models::payments::KlarnaCheckoutPaymentMethodResponse, 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/klarna.rs b/crates/router/src/connector/klarna.rs index 26e0ef77841e..c2bd8da8cc4f 100644 --- a/crates/router/src/connector/klarna.rs +++ b/crates/router/src/connector/klarna.rs @@ -824,7 +824,7 @@ impl req.request.currency, )?; let connector_router_data = klarna::KlarnaRouterData::from((amount, req)); - let connector_req = klarna::KlarnaAuthRequest::try_from(&connector_router_data)?; + let connector_req = klarna::KlarnaPaymentsRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } diff --git a/crates/router/src/connector/klarna/transformers.rs b/crates/router/src/connector/klarna/transformers.rs index 10511aa7a7db..5809314c550d 100644 --- a/crates/router/src/connector/klarna/transformers.rs +++ b/crates/router/src/connector/klarna/transformers.rs @@ -1,10 +1,8 @@ use api_models::payments; use common_utils::{pii, types::MinorUnit}; -use diesel_models::types::OrderDetailsWithAmount; use error_stack::{report, ResultExt}; use hyperswitch_domain_models::{ - router_data::{KlarnaCheckoutResponse, KlarnaSdkResponse}, - router_response_types::RedirectForm, + router_data::KlarnaSdkResponse, router_response_types::RedirectForm, }; use masking::{ExposeInterface, Secret}; use serde::{Deserialize, Serialize}; @@ -65,35 +63,36 @@ impl TryFrom<&Option> for KlarnaConnectorMetadataObject { } } -#[derive(Debug, Deserialize, Serialize)] -#[serde(untagged)] -pub enum KlarnaAuthRequest { - KlarnaPaymentsAuthRequest(PaymentsRequest), - KlarnaCheckoutAuthRequest(CheckoutRequest), + +#[derive(Default, Debug, Serialize, Deserialize)] +pub struct MerchantURLs { + terms: String, + checkout: String, + confirmation: String, + push: String, } + #[derive(Default, Debug, Serialize, Deserialize)] -pub struct PaymentsRequest { - auto_capture: bool, - order_lines: Vec, +pub struct CheckoutMerchantURLs { + merchant_urls: MerchantURLs, +} + +#[derive(Default, Debug, Deserialize, Serialize)] +pub struct KlarnaPaymentsRequest { order_amount: MinorUnit, purchase_country: enums::CountryAlpha2, purchase_currency: enums::Currency, + order_lines: Vec, merchant_reference1: Option, merchant_reference2: Option, shipping_address: Option, + auto_capture: Option, + order_tax_amount: Option, + #[serde(flatten)] + checkout_merchant_urls: Option, + options: Option, } -#[derive(Default, Debug, Serialize, Deserialize)] -pub struct CheckoutRequest { - auto_capture: bool, - order_lines: Vec, - order_amount: MinorUnit, - purchase_country: enums::CountryAlpha2, - purchase_currency: enums::Currency, - shipping_address: Option, - order_tax_amount: MinorUnit, - merchant_urls: MerchantURLs, -} #[derive(Debug, Deserialize, Serialize)] #[serde(untagged)] @@ -113,8 +112,7 @@ pub struct PaymentsResponse { pub struct CheckoutResponse { order_id: String, status: KlarnaCheckoutStatus, - html_snippet: String, - authorized_payment_method: Option, + html_snippet: String } #[derive(Debug, Clone, Deserialize, Serialize)] @@ -125,27 +123,13 @@ pub struct AuthorizedPaymentMethod { impl From for types::AdditionalPaymentMethodConnectorResponse { fn from(item: AuthorizedPaymentMethod) -> Self { - match item.payment_type.as_str() { - "klarna_sdk" => Self::PayLater { - klarna_sdk: Some(KlarnaSdkResponse { - payment_type: Some(item.payment_type), - }), - klarna_checkout: None, - }, - "klarna_checkout" => Self::PayLater { - klarna_checkout: Some(KlarnaCheckoutResponse { - payment_type: Some(item.payment_type), - }), - klarna_sdk: None, - }, - _ => Self::PayLater { - klarna_sdk: None, - klarna_checkout: None, - }, + Self::PayLater { + klarna_sdk: Some(KlarnaSdkResponse { + payment_type: Some(item.payment_type), + }), } } } - #[derive(Debug, Serialize)] pub struct KlarnaSessionRequest { intent: KlarnaSessionIntent, @@ -171,11 +155,8 @@ pub struct KlarnaShippingAddress { } #[derive(Default, Debug, Serialize, Deserialize)] -pub struct MerchantURLs { - terms: String, - checkout: String, - confirmation: String, - push: String, +pub struct CheckoutOptions { + auto_capture: bool, } #[derive(Deserialize, Serialize, Debug)] @@ -207,6 +188,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()) @@ -241,7 +224,7 @@ impl TryFrom> } } -impl TryFrom<&KlarnaRouterData<&types::PaymentsAuthorizeRouterData>> for KlarnaAuthRequest { +impl TryFrom<&KlarnaRouterData<&types::PaymentsAuthorizeRouterData>> for KlarnaPaymentsRequest { type Error = error_stack::Report; fn try_from( @@ -250,11 +233,10 @@ impl TryFrom<&KlarnaRouterData<&types::PaymentsAuthorizeRouterData>> for KlarnaA let request = &item.router_data.request; let payment_method_data = request.payment_method_data.clone(); let return_url = item.router_data.request.get_return_url()?; - match payment_method_data { domain::PaymentMethodData::PayLater(domain::PayLaterData::KlarnaSdk { .. }) => { match request.order_details.clone() { - Some(order_details) => Ok(Self::KlarnaPaymentsAuthRequest(PaymentsRequest { + Some(order_details) => Ok(Self { purchase_country: item.router_data.get_billing_country()?, purchase_currency: request.currency, order_amount: item.amount, @@ -265,6 +247,8 @@ impl TryFrom<&KlarnaRouterData<&types::PaymentsAuthorizeRouterData>> for KlarnaA quantity: data.quantity, unit_price: data.amount, total_amount: data.amount * data.quantity, + total_tax_amount: None, + tax_rate: None, }) .collect(), merchant_reference1: Some( @@ -275,79 +259,70 @@ impl TryFrom<&KlarnaRouterData<&types::PaymentsAuthorizeRouterData>> for KlarnaA .request .merchant_order_reference_id .clone(), - auto_capture: request.is_auto_capture()?, + auto_capture: Some(request.is_auto_capture()?), shipping_address: get_address_info( item.router_data.get_optional_shipping(), ) .transpose()?, + order_tax_amount: None, + checkout_merchant_urls: None, + options: None, + }), + None => Err(report!(errors::ConnectorError::MissingRequiredField { + field_name: "order_details" })), - None => Err(errors::ConnectorError::NotImplemented( - "Order details missing".to_string(), - ) - .into()), } } domain::PaymentMethodData::PayLater(domain::PayLaterData::KlarnaCheckout {}) => { match request.order_details.clone() { - Some(order_details) => { - let calculated_tax_amount = calculate_order_tax_amount(&order_details); - - Ok(Self::KlarnaCheckoutAuthRequest(CheckoutRequest { - purchase_country: item.router_data.get_billing_country()?, - purchase_currency: request.currency, - order_amount: item.amount, - order_tax_amount: calculated_tax_amount, - order_lines: order_details - .iter() - .map(|data| CheckoutOrderLines { - 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(), + Some(order_details) => Ok(Self { + purchase_country: item.router_data.get_billing_country()?, + purchase_currency: request.currency, + order_amount: item.amount, + 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(), + + checkout_merchant_urls: Some(CheckoutMerchantURLs { merchant_urls: MerchantURLs { terms: return_url.clone(), checkout: return_url.clone(), - confirmation: return_url.clone(), - push: return_url, + confirmation: "https://google.com".to_string(), + push: "https://google.com".to_string(), }, + }), + options: Some(CheckoutOptions { auto_capture: request.is_auto_capture()?, - shipping_address: get_address_info( - item.router_data.get_optional_shipping(), - ) - .transpose()?, - })) - } - None => Err(errors::ConnectorError::NotImplemented( - "Order details missing".to_string(), - ) - .into()), + }), + 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" + })), } } - domain::PaymentMethodData::Card(_) - | domain::PaymentMethodData::CardDetailsForNetworkTransactionId(_) - | domain::PaymentMethodData::CardRedirect(_) - | domain::PaymentMethodData::Wallet(_) - | domain::PaymentMethodData::PayLater(_) - | domain::PaymentMethodData::BankRedirect(_) - | domain::PaymentMethodData::BankDebit(_) - | domain::PaymentMethodData::BankTransfer(_) - | domain::PaymentMethodData::Crypto(_) - | domain::PaymentMethodData::MandatePayment - | domain::PaymentMethodData::Reward - | domain::PaymentMethodData::RealTimePayment(_) - | domain::PaymentMethodData::Upi(_) - | domain::PaymentMethodData::Voucher(_) - | domain::PaymentMethodData::GiftCard(_) - | domain::PaymentMethodData::CardToken(_) - | domain::PaymentMethodData::OpenBanking(_) - | domain::PaymentMethodData::NetworkToken(_) - | domain::PaymentMethodData::MobilePayment(_) => { - Err(errors::ConnectorError::NotImplemented("Payment method".to_string()).into()) - } + _ => Err(errors::ConnectorError::NotImplemented("Payment method".to_string()).into()), } } } @@ -375,13 +350,6 @@ fn get_address_info( }) } -fn calculate_order_tax_amount(order_lines: &[OrderDetailsWithAmount]) -> MinorUnit { - order_lines - .iter() - .map(|line| line.total_tax_amount.map_or(MinorUnit::zero(), |tax| tax)) - .sum() -} - impl TryFrom> for types::PaymentsAuthorizeRouterData { @@ -390,88 +358,77 @@ impl TryFrom> fn try_from( item: types::PaymentsResponseRouterData, ) -> Result { - let connector_response = types::ConnectorResponseData::with_additional_payment_method_data( - match item.response { - KlarnaAuthResponse::KlarnaPaymentsAuthResponse(ref response) => { - match &response.authorized_payment_method { - Some(authorized_payment_method) => { - types::AdditionalPaymentMethodConnectorResponse::from( - authorized_payment_method.clone(), - ) - } - None => types::AdditionalPaymentMethodConnectorResponse::PayLater { - klarna_sdk: None, - klarna_checkout: None, - }, - } - } - KlarnaAuthResponse::KlarnaCheckoutAuthResponse(ref response) => { - match &response.authorized_payment_method { - Some(authorized_payment_method) => { + match item.response { + KlarnaAuthResponse::KlarnaPaymentsAuthResponse(ref response) => { + let connector_response = match &response.authorized_payment_method { + Some(authorized_payment_method) => { + Some(types::ConnectorResponseData::with_additional_payment_method_data( types::AdditionalPaymentMethodConnectorResponse::from( authorized_payment_method.clone(), - ) - } - None => types::AdditionalPaymentMethodConnectorResponse::PayLater { - klarna_sdk: None, - klarna_checkout: None, - }, + ), + )) } - } - }, - ); + None => None, + }; - match item.response { - KlarnaAuthResponse::KlarnaPaymentsAuthResponse(ref response) => 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: Some(connector_response), - ..item.data - }), + 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::from(response.status.clone()), - connector_response: Some(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()?, + )), + ..item.data + }) + } } } } + #[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(Default, Debug, Serialize, Deserialize)] @@ -543,6 +500,21 @@ 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, + } + } +} + impl From for enums::AttemptStatus { fn from(klarna_status: KlarnaCheckoutStatus) -> Self { match klarna_status { @@ -570,6 +542,7 @@ pub struct KlarnaSDKSyncResponse { pub struct KlarnaCheckoutSyncResponse { pub order_id: String, pub status: KlarnaCheckoutStatus, + pub options: CheckoutOptions, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -624,7 +597,10 @@ impl ..item.data }), KlarnaPsyncResponse::KlarnaCheckoutPSyncResponse(response) => Ok(Self { - status: enums::AttemptStatus::from(response.status), + 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(), diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index a570f051c687..91125d3cc5a0 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -32,7 +32,7 @@ use hyperswitch_domain_models::{ payment_attempt::PaymentAttempt, payment_intent::PaymentIntentFetchConstraints, PaymentIntent, }, - router_data::{KlarnaCheckoutResponse, KlarnaSdkResponse}, + router_data::KlarnaSdkResponse, }; use hyperswitch_interfaces::integrity::{CheckIntegrity, FlowIntegrity, GetIntegrityObject}; use josekit::jwe; @@ -4083,6 +4083,7 @@ impl AttemptType { status: payment_attempt_status_fsm(payment_method_data, Some(true)), currency: old_payment_attempt.currency, + order_tax_amount: old_payment_attempt.order_tax_amount, save_to_locker: old_payment_attempt.save_to_locker, connector: None, @@ -4547,10 +4548,7 @@ pub async fn get_additional_payment_data( })), }, domain::PaymentMethodData::PayLater(_) => Ok(Some( - api_models::payments::AdditionalPaymentData::PayLater { - klarna_sdk: None, - klarna_checkout: None, - }, + api_models::payments::AdditionalPaymentData::PayLater { klarna_sdk: None }, )), domain::PaymentMethodData::BankTransfer(bank_transfer) => Ok(Some( api_models::payments::AdditionalPaymentData::BankTransfer { @@ -5623,23 +5621,9 @@ pub fn add_connector_response_to_additional_payment_data( api_models::payments::AdditionalPaymentData::PayLater { .. }, AdditionalPaymentMethodConnectorResponse::PayLater { klarna_sdk: Some(KlarnaSdkResponse { payment_type }), - klarna_checkout: None, }, ) => api_models::payments::AdditionalPaymentData::PayLater { klarna_sdk: Some(api_models::payments::KlarnaSdkPaymentMethod { payment_type }), - klarna_checkout: None, - }, - ( - api_models::payments::AdditionalPaymentData::PayLater { .. }, - AdditionalPaymentMethodConnectorResponse::PayLater { - klarna_sdk: None, - klarna_checkout: Some(KlarnaCheckoutResponse { payment_type }), - }, - ) => api_models::payments::AdditionalPaymentData::PayLater { - klarna_sdk: None, - klarna_checkout: Some(api_models::payments::KlarnaCheckoutPaymentMethod { - payment_type, - }), }, _ => additional_payment_data, diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index dcc2ba6a289a..832d6753890d 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -326,7 +326,6 @@ impl GetTracker, api::PaymentsRequest> for Pa &customer_acceptance, ) .await?; - let payment_intent = db .insert_payment_intent( key_manager_state, @@ -1207,6 +1206,7 @@ impl PaymentCreate { attempt_id, status, currency, + order_tax_amount: Some(request.order_tax_amount), payment_method, capture_method: request.capture_method, capture_on: request.capture_on, @@ -1477,7 +1477,12 @@ impl PaymentCreate { is_payment_processor_token_flow, organization_id: merchant_account.organization_id.clone(), shipping_cost: request.shipping_cost, - tax_details: None, + tax_details: Some(diesel_models::TaxDetails { + default: Some(diesel_models::DefaultTax { + order_tax_amount: request.order_tax_amount, + }), + ..Default::default() + }), skip_external_tax_calculation, psd2_sca_exemption_type: request.psd2_sca_exemption_type, }) diff --git a/crates/router/src/core/payments/retry.rs b/crates/router/src/core/payments/retry.rs index fed28b680110..b073631f998a 100644 --- a/crates/router/src/core/payments/retry.rs +++ b/crates/router/src/core/payments/retry.rs @@ -599,6 +599,7 @@ pub fn make_new_payment_attempt( payment_id: old_payment_attempt.payment_id, merchant_id: old_payment_attempt.merchant_id, status: old_payment_attempt.status, + order_tax_amount: old_payment_attempt.order_tax_amount, currency: old_payment_attempt.currency, save_to_locker: old_payment_attempt.save_to_locker, offer_amount: old_payment_attempt.offer_amount, diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index ee750c1bc499..ce189b100a69 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -260,6 +260,7 @@ pub async fn construct_payment_router_data_for_authorize<'a>( .get_amount_as_i64(), minor_amount: payment_data.payment_attempt.amount_details.net_amount, currency: payment_data.payment_intent.amount_details.currency, + order_tax_amount: None, browser_info: None, email: None, customer_name: None, @@ -2240,27 +2241,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, - tax_rate: order_details.tax_rate, - total_tax_amount: order_details.total_tax_amount, - }]) -} - impl ForeignFrom for api_models::payments::NextActionData { fn foreign_from(qr_info: api_models::payments::QrCodeInformation) -> Self { match qr_info { @@ -2444,6 +2424,15 @@ 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: Some( + payment_data + .payment_intent + .tax_details + .as_ref() + .and_then(|td| td.default.as_ref()) + .map(|default_tax| default_tax.order_tax_amount) + .unwrap_or_default(), + ), minor_amount: amount, currency: payment_data.currency, browser_info, diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index 467ae31f7cf1..471693963c4b 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -865,6 +865,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::new(0)), 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 c368a3fb37d0..cc621981a636 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/storage/payment_attempt.rs b/crates/router/src/types/storage/payment_attempt.rs index 0291374d54f6..f4cc63c74011 100644 --- a/crates/router/src/types/storage/payment_attempt.rs +++ b/crates/router/src/types/storage/payment_attempt.rs @@ -169,6 +169,7 @@ mod tests { attempt_id: Default::default(), status: Default::default(), net_amount: Default::default(), + order_tax_amount: Default::default(), currency: Default::default(), save_to_locker: Default::default(), error_message: Default::default(), @@ -253,6 +254,7 @@ mod tests { attempt_id: attempt_id.clone(), status: Default::default(), net_amount: Default::default(), + order_tax_amount: Default::default(), currency: Default::default(), save_to_locker: Default::default(), error_message: Default::default(), @@ -351,6 +353,7 @@ mod tests { attempt_id: uuid.clone(), status: Default::default(), net_amount: Default::default(), + order_tax_amount: Default::default(), currency: Default::default(), save_to_locker: Default::default(), error_message: Default::default(), diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index c8a9cbea1ddd..dce77455a046 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -1229,6 +1229,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.order_tax_amount, currency: payment_attempt.currency, connector: payment_attempt.connector, error_message: payment_attempt.error_reason, diff --git a/crates/router/tests/connectors/utils.rs b/crates/router/tests/connectors/utils.rs index a03148956ba2..825c84c28d31 100644 --- a/crates/router/tests/connectors/utils.rs +++ b/crates/router/tests/connectors/utils.rs @@ -919,6 +919,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::new(0)), currency: enums::Currency::USD, confirm: true, statement_descriptor_suffix: None, diff --git a/crates/storage_impl/src/mock_db/payment_attempt.rs b/crates/storage_impl/src/mock_db/payment_attempt.rs index 83691f46129b..1207955e33a1 100644 --- a/crates/storage_impl/src/mock_db/payment_attempt.rs +++ b/crates/storage_impl/src/mock_db/payment_attempt.rs @@ -143,6 +143,7 @@ impl PaymentAttemptInterface for MockDb { status: payment_attempt.status, net_amount: payment_attempt.net_amount, currency: payment_attempt.currency, + order_tax_amount: payment_attempt.order_tax_amount, save_to_locker: payment_attempt.save_to_locker, connector: payment_attempt.connector, error_message: payment_attempt.error_message, diff --git a/crates/storage_impl/src/payments/payment_attempt.rs b/crates/storage_impl/src/payments/payment_attempt.rs index 9b9121952b16..b3a28388c816 100644 --- a/crates/storage_impl/src/payments/payment_attempt.rs +++ b/crates/storage_impl/src/payments/payment_attempt.rs @@ -506,6 +506,7 @@ impl PaymentAttemptInterface for KVRouterStore { status: payment_attempt.status, net_amount: payment_attempt.net_amount.clone(), currency: payment_attempt.currency, + order_tax_amount: payment_attempt.order_tax_amount, save_to_locker: payment_attempt.save_to_locker, connector: payment_attempt.connector.clone(), error_message: payment_attempt.error_message.clone(), @@ -1530,6 +1531,7 @@ impl DataModelExt for PaymentAttempt { attempt_id: storage_model.attempt_id, status: storage_model.status, currency: storage_model.currency, + order_tax_amount: storage_model.order_tax_amount, save_to_locker: storage_model.save_to_locker, connector: storage_model.connector, error_message: storage_model.error_message, @@ -1686,6 +1688,7 @@ impl DataModelExt for PaymentAttemptNew { attempt_id: storage_model.attempt_id, status: storage_model.status, currency: storage_model.currency, + order_tax_amount: storage_model.order_tax_amount, save_to_locker: storage_model.save_to_locker, connector: storage_model.connector, error_message: storage_model.error_message,