Bug: feat(core): consume card details from billing connectors and first error codes and store them in payment intent table



Consume the card network and card iin from billing connectors and add them ton payment intent feature metadata
diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs
index c37690a9f5a..ef4d417ddc6 100644
--- a/crates/api_models/src/payments.rs
+++ b/crates/api_models/src/payments.rs
@@ -8694,9 +8694,41 @@ pub struct PaymentRevenueRecoveryMetadata {
     /// The name of the payment connector through which the payment attempt was made.
     #[schema(value_type = Connector, example = "stripe")]
     pub connector: common_enums::connector_enums::Connector,
+    #[schema(value_type = BillingConnectorPaymentMethodDetails)]
+    /// Extra Payment Method Details that are needed to be stored
+    pub billing_connector_payment_method_details: Option<BillingConnectorPaymentMethodDetails>,
     /// Invoice Next billing time
+    #[serde(default, with = "common_utils::custom_serde::iso8601::option")]
     pub invoice_next_billing_time: Option<PrimitiveDateTime>,
+    /// First Payment Attempt Payment Gateway Error Code
+    #[schema(value_type = Option<String>, example = "card_declined")]
+    pub first_payment_attempt_pg_error_code: Option<String>,
+    /// First Payment Attempt Network Error Code
+    #[schema(value_type = Option<String>, example = "05")]
+    pub first_payment_attempt_network_decline_code: Option<String>,
+    /// First Payment Attempt Network Advice Code
+    #[schema(value_type = Option<String>, example = "02")]
+    pub first_payment_attempt_network_advice_code: Option<String>,
+}
+
+#[cfg(feature = "v2")]
+#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ToSchema)]
+#[serde(rename_all = "snake_case", tag = "type", content = "value")]
+pub enum BillingConnectorPaymentMethodDetails {
+    Card(BillingConnectorAdditionalCardInfo),
+}
+
+#[cfg(feature = "v2")]
+#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ToSchema)]
+pub struct BillingConnectorAdditionalCardInfo {
+    #[schema(value_type = CardNetwork, example = "Visa")]
+    /// Card Network
+    pub card_network: Option<common_enums::enums::CardNetwork>,
+    #[schema(value_type = Option<String>, example = "JP MORGAN CHASE")]
+    /// Card Issuer
+    pub card_issuer: Option<String>,
 }
+
 #[cfg(feature = "v2")]
 impl PaymentRevenueRecoveryMetadata {
     pub fn set_payment_transmission_field_for_api_request(
@@ -8810,6 +8842,14 @@ pub struct PaymentsAttemptRecordRequest {
     /// source where the payment was triggered by
     #[schema(value_type = TriggeredBy, example = "internal" )]
     pub triggered_by: common_enums::TriggeredBy,
+
+    #[schema(value_type = CardNetwork, example = "Visa" )]
+    /// card_network
+    pub card_network: Option<common_enums::CardNetwork>,
+
+    #[schema(example = "Chase")]
+    /// Card Issuer
+    pub card_issuer: Option<String>,
 }
 
 /// Error details for the payment
diff --git a/crates/diesel_models/src/types.rs b/crates/diesel_models/src/types.rs
index 696cc22783d..e3efd3dae2d 100644
--- a/crates/diesel_models/src/types.rs
+++ b/crates/diesel_models/src/types.rs
@@ -174,6 +174,14 @@ pub struct PaymentRevenueRecoveryMetadata {
     pub connector: common_enums::connector_enums::Connector,
     /// Time at which next invoice will be created
     pub invoice_next_billing_time: Option<time::PrimitiveDateTime>,
+    /// Extra Payment Method Details that are needed to be stored
+    pub billing_connector_payment_method_details: Option<BillingConnectorPaymentMethodDetails>,
+    /// First Payment Attempt Payment Gateway Error Code
+    pub first_payment_attempt_pg_error_code: Option<String>,
+    /// First Payment Attempt Network Error Code
+    pub first_payment_attempt_network_decline_code: Option<String>,
+    /// First Payment Attempt Network Advice Code
+    pub first_payment_attempt_network_advice_code: Option<String>,
 }
 
 #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
@@ -184,3 +192,19 @@ pub struct BillingConnectorPaymentDetails {
     /// Billing Connector's Customer Id
     pub connector_customer_id: String,
 }
+
+#[cfg(feature = "v2")]
+#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
+#[serde(rename_all = "snake_case", tag = "type", content = "value")]
+pub enum BillingConnectorPaymentMethodDetails {
+    Card(BillingConnectorAdditionalCardInfo),
+}
+
+#[cfg(feature = "v2")]
+#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
+pub struct BillingConnectorAdditionalCardInfo {
+    /// Card Network
+    pub card_network: Option<common_enums::enums::CardNetwork>,
+    /// Card Issuer
+    pub card_issuer: Option<String>,
+}
diff --git a/crates/hyperswitch_connectors/src/connectors/chargebee/transformers.rs b/crates/hyperswitch_connectors/src/connectors/chargebee/transformers.rs
index ed978d84903..6436cd952e7 100644
--- a/crates/hyperswitch_connectors/src/connectors/chargebee/transformers.rs
+++ b/crates/hyperswitch_connectors/src/connectors/chargebee/transformers.rs
@@ -335,6 +335,8 @@ pub struct ChargebeePaymentMethodDetails {
 #[derive(Serialize, Deserialize, Debug)]
 pub struct ChargebeeCardDetails {
     funding_type: ChargebeeFundingType,
+    brand: common_enums::CardNetwork,
+    iin: String,
 }
 
 #[derive(Serialize, Deserialize, Debug)]
@@ -505,6 +507,8 @@ impl TryFrom<ChargebeeWebhookBody> for revenue_recovery::RevenueRecoveryAttemptD
             network_error_message: None,
             retry_count,
             invoice_next_billing_time,
+            card_network: Some(payment_method_details.card.brand),
+            card_isin: Some(payment_method_details.card.iin),
         })
     }
 }
diff --git a/crates/hyperswitch_connectors/src/connectors/recurly/transformers.rs b/crates/hyperswitch_connectors/src/connectors/recurly/transformers.rs
index 673ba9d432f..9ffd900dc45 100644
--- a/crates/hyperswitch_connectors/src/connectors/recurly/transformers.rs
+++ b/crates/hyperswitch_connectors/src/connectors/recurly/transformers.rs
@@ -136,6 +136,8 @@ pub struct PaymentMethod {
     pub gateway_token: String,
     pub funding_source: RecurlyFundingTypes,
     pub object: RecurlyPaymentObject,
+    pub card_type: common_enums::CardNetwork,
+    pub first_six: String,
 }
 
 #[derive(Debug, Serialize, Deserialize)]
@@ -204,6 +206,8 @@ impl
                     payment_method_type: common_enums::PaymentMethod::from(
                         item.response.payment_method.object,
                     ),
+                    card_network: Some(item.response.payment_method.card_type),
+                    card_isin: Some(item.response.payment_method.first_six),
                 },
             ),
             ..item.data
diff --git a/crates/hyperswitch_connectors/src/connectors/stripebilling/transformers.rs b/crates/hyperswitch_connectors/src/connectors/stripebilling/transformers.rs
index ffefb74e7ee..1352b874c8a 100644
--- a/crates/hyperswitch_connectors/src/connectors/stripebilling/transformers.rs
+++ b/crates/hyperswitch_connectors/src/connectors/stripebilling/transformers.rs
@@ -439,6 +439,7 @@ pub struct StripebillingLatestChargeData {
     pub payment_method_details: StripePaymentMethodDetails,
     #[serde(rename = "invoice")]
     pub invoice_id: String,
+    pub payment_intent: String,
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
@@ -446,7 +447,7 @@ pub struct StripePaymentMethodDetails {
     #[serde(rename = "type")]
     pub type_of_payment_method: StripebillingPaymentMethod,
     #[serde(rename = "card")]
-    pub card_funding_type: StripeCardFundingTypeDetails,
+    pub card_details: StripeBillingCardDetails,
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone, Copy)]
@@ -456,10 +457,31 @@ pub enum StripebillingPaymentMethod {
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
-pub struct StripeCardFundingTypeDetails {
+pub struct StripeBillingCardDetails {
+    pub network: StripebillingCardNetwork,
     pub funding: StripebillingFundingTypes,
 }
 
+#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
+#[serde(rename_all = "snake_case")]
+pub enum StripebillingCardNetwork {
+    Visa,
+    Mastercard,
+    AmericanExpress,
+    JCB,
+    DinersClub,
+    Discover,
+    CartesBancaires,
+    UnionPay,
+    Interac,
+    RuPay,
+    Maestro,
+    Star,
+    Pulse,
+    Accel,
+    Nyce,
+}
+
 #[derive(Serialize, Deserialize, Debug, Clone, Copy)]
 #[serde(rename = "snake_case")]
 pub enum StripebillingFundingTypes {
@@ -509,7 +531,7 @@ impl
                     field_name: "invoice_id",
                 })?;
         let connector_transaction_id = Some(common_utils::types::ConnectorTransactionId::from(
-            charge_details.charge_id,
+            charge_details.payment_intent,
         ));
 
         Ok(Self {
@@ -529,14 +551,16 @@ impl
                     connector_customer_id: charge_details.customer,
                     transaction_created_at: Some(charge_details.created),
                     payment_method_sub_type: common_enums::PaymentMethodType::from(
-                        charge_details
-                            .payment_method_details
-                            .card_funding_type
-                            .funding,
+                        charge_details.payment_method_details.card_details.funding,
                     ),
                     payment_method_type: common_enums::PaymentMethod::from(
                         charge_details.payment_method_details.type_of_payment_method,
                     ),
+                    card_network: Some(common_enums::CardNetwork::from(
+                        charge_details.payment_method_details.card_details.network,
+                    )),
+                    // Todo: Fetch Card issuer details. Generally in the other billing connector we are getting card_issuer using the card bin info. But stripe dosent provide any such details. We should find a way for stripe billing case
+                    card_isin: None,
                 },
             ),
             ..item.data
@@ -611,3 +635,25 @@ impl
         })
     }
 }
+
+impl From<StripebillingCardNetwork> for enums::CardNetwork {
+    fn from(item: StripebillingCardNetwork) -> Self {
+        match item {
+            StripebillingCardNetwork::Visa => Self::Visa,
+            StripebillingCardNetwork::Mastercard => Self::Mastercard,
+            StripebillingCardNetwork::AmericanExpress => Self::AmericanExpress,
+            StripebillingCardNetwork::JCB => Self::JCB,
+            StripebillingCardNetwork::DinersClub => Self::DinersClub,
+            StripebillingCardNetwork::Discover => Self::Discover,
+            StripebillingCardNetwork::CartesBancaires => Self::CartesBancaires,
+            StripebillingCardNetwork::UnionPay => Self::UnionPay,
+            StripebillingCardNetwork::Interac => Self::Interac,
+            StripebillingCardNetwork::RuPay => Self::RuPay,
+            StripebillingCardNetwork::Maestro => Self::Maestro,
+            StripebillingCardNetwork::Star => Self::Star,
+            StripebillingCardNetwork::Pulse => Self::Pulse,
+            StripebillingCardNetwork::Accel => Self::Accel,
+            StripebillingCardNetwork::Nyce => Self::Nyce,
+        }
+    }
+}
diff --git a/crates/hyperswitch_domain_models/src/lib.rs b/crates/hyperswitch_domain_models/src/lib.rs
index 99ef5e3581f..4ee8620e35e 100644
--- a/crates/hyperswitch_domain_models/src/lib.rs
+++ b/crates/hyperswitch_domain_models/src/lib.rs
@@ -55,7 +55,9 @@ use api_models::payments::{
 };
 #[cfg(feature = "v2")]
 use api_models::payments::{
+    BillingConnectorAdditionalCardInfo as ApiBillingConnectorAdditionalCardInfo,
     BillingConnectorPaymentDetails as ApiBillingConnectorPaymentDetails,
+    BillingConnectorPaymentMethodDetails as ApiBillingConnectorPaymentMethodDetails,
     PaymentRevenueRecoveryMetadata as ApiRevenueRecoveryMetadata,
 };
 use diesel_models::types::{
@@ -63,7 +65,10 @@ use diesel_models::types::{
     OrderDetailsWithAmount, RecurringPaymentIntervalUnit, RedirectResponse,
 };
 #[cfg(feature = "v2")]
-use diesel_models::types::{BillingConnectorPaymentDetails, PaymentRevenueRecoveryMetadata};
+use diesel_models::types::{
+    BillingConnectorAdditionalCardInfo, BillingConnectorPaymentDetails,
+    BillingConnectorPaymentMethodDetails, PaymentRevenueRecoveryMetadata,
+};
 
 #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
 pub enum RemoteStorageObject<T: ForeignIDRef> {
@@ -267,6 +272,44 @@ impl ApiModelToDieselModelConvertor<ApiApplePayRecurringDetails> for ApplePayRec
     }
 }
 
+#[cfg(feature = "v2")]
+impl ApiModelToDieselModelConvertor<ApiBillingConnectorAdditionalCardInfo>
+    for BillingConnectorAdditionalCardInfo
+{
+    fn convert_from(from: ApiBillingConnectorAdditionalCardInfo) -> Self {
+        Self {
+            card_issuer: from.card_issuer,
+            card_network: from.card_network,
+        }
+    }
+
+    fn convert_back(self) -> ApiBillingConnectorAdditionalCardInfo {
+        ApiBillingConnectorAdditionalCardInfo {
+            card_issuer: self.card_issuer,
+            card_network: self.card_network,
+        }
+    }
+}
+
+#[cfg(feature = "v2")]
+impl ApiModelToDieselModelConvertor<ApiBillingConnectorPaymentMethodDetails>
+    for BillingConnectorPaymentMethodDetails
+{
+    fn convert_from(from: ApiBillingConnectorPaymentMethodDetails) -> Self {
+        match from {
+            ApiBillingConnectorPaymentMethodDetails::Card(data) => {
+                Self::Card(BillingConnectorAdditionalCardInfo::convert_from(data))
+            }
+        }
+    }
+
+    fn convert_back(self) -> ApiBillingConnectorPaymentMethodDetails {
+        match self {
+            Self::Card(data) => ApiBillingConnectorPaymentMethodDetails::Card(data.convert_back()),
+        }
+    }
+}
+
 #[cfg(feature = "v2")]
 impl ApiModelToDieselModelConvertor<ApiRevenueRecoveryMetadata> for PaymentRevenueRecoveryMetadata {
     fn convert_from(from: ApiRevenueRecoveryMetadata) -> Self {
@@ -282,6 +325,14 @@ impl ApiModelToDieselModelConvertor<ApiRevenueRecoveryMetadata> for PaymentReven
             payment_method_subtype: from.payment_method_subtype,
             connector: from.connector,
             invoice_next_billing_time: from.invoice_next_billing_time,
+            billing_connector_payment_method_details: from
+                .billing_connector_payment_method_details
+                .map(BillingConnectorPaymentMethodDetails::convert_from),
+            first_payment_attempt_network_advice_code: from
+                .first_payment_attempt_network_advice_code,
+            first_payment_attempt_network_decline_code: from
+                .first_payment_attempt_network_decline_code,
+            first_payment_attempt_pg_error_code: from.first_payment_attempt_pg_error_code,
         }
     }
 
@@ -298,6 +349,14 @@ impl ApiModelToDieselModelConvertor<ApiRevenueRecoveryMetadata> for PaymentReven
             payment_method_subtype: self.payment_method_subtype,
             connector: self.connector,
             invoice_next_billing_time: self.invoice_next_billing_time,
+            billing_connector_payment_method_details: self
+                .billing_connector_payment_method_details
+                .map(|data| data.convert_back()),
+            first_payment_attempt_network_advice_code: self
+                .first_payment_attempt_network_advice_code,
+            first_payment_attempt_network_decline_code: self
+                .first_payment_attempt_network_decline_code,
+            first_payment_attempt_pg_error_code: self.first_payment_attempt_pg_error_code,
         }
     }
 }
diff --git a/crates/hyperswitch_domain_models/src/payments.rs b/crates/hyperswitch_domain_models/src/payments.rs
index e8ec7041f60..d460cfa4662 100644
--- a/crates/hyperswitch_domain_models/src/payments.rs
+++ b/crates/hyperswitch_domain_models/src/payments.rs
@@ -743,6 +743,8 @@ impl PaymentIntent {
             network_error_message: None,
             retry_count: None,
             invoice_next_billing_time: None,
+            card_isin: None,
+            card_network: None,
         })
     }
 
@@ -951,6 +953,8 @@ pub struct RevenueRecoveryData {
     pub retry_count: Option<u16>,
     pub invoice_next_billing_time: Option<PrimitiveDateTime>,
     pub triggered_by: storage_enums::enums::TriggeredBy,
+    pub card_network: Option<common_enums::CardNetwork>,
+    pub card_issuer: Option<String>,
 }
 
 #[cfg(feature = "v2")]
@@ -962,9 +966,57 @@ where
         &self,
     ) -> CustomResult<Option<FeatureMetadata>, errors::api_error_response::ApiErrorResponse> {
         let payment_intent_feature_metadata = self.payment_intent.get_feature_metadata();
-
         let revenue_recovery = self.payment_intent.get_revenue_recovery_metadata();
         let payment_attempt_connector = self.payment_attempt.connector.clone();
+
+        let feature_metadata_first_pg_error_code = revenue_recovery
+            .as_ref()
+            .and_then(|data| data.first_payment_attempt_pg_error_code.clone());
+
+        let (first_pg_error_code, first_network_advice_code, first_network_decline_code) =
+            feature_metadata_first_pg_error_code.map_or_else(
+                || {
+                    let first_pg_error_code = self
+                        .payment_attempt
+                        .error
+                        .as_ref()
+                        .map(|error| error.code.clone());
+                    let first_network_advice_code = self
+                        .payment_attempt
+                        .error
+                        .as_ref()
+                        .and_then(|error| error.network_advice_code.clone());
+                    let first_network_decline_code = self
+                        .payment_attempt
+                        .error
+                        .as_ref()
+                        .and_then(|error| error.network_decline_code.clone());
+                    (
+                        first_pg_error_code,
+                        first_network_advice_code,
+                        first_network_decline_code,
+                    )
+                },
+                |pg_code| {
+                    let advice_code = revenue_recovery
+                        .as_ref()
+                        .and_then(|data| data.first_payment_attempt_network_advice_code.clone());
+                    let decline_code = revenue_recovery
+                        .as_ref()
+                        .and_then(|data| data.first_payment_attempt_network_decline_code.clone());
+                    (Some(pg_code), advice_code, decline_code)
+                },
+            );
+
+        let billing_connector_payment_method_details = Some(
+            diesel_models::types::BillingConnectorPaymentMethodDetails::Card(
+                diesel_models::types::BillingConnectorAdditionalCardInfo {
+                    card_network: self.revenue_recovery_data.card_network.clone(),
+                    card_issuer: self.revenue_recovery_data.card_issuer.clone(),
+                },
+            ),
+        );
+
         let payment_revenue_recovery_metadata = match payment_attempt_connector {
             Some(connector) => Some(diesel_models::types::PaymentRevenueRecoveryMetadata {
                 // Update retry count by one.
@@ -999,6 +1051,10 @@ where
                     errors::api_error_response::ApiErrorResponse::InternalServerError
                 })?,
                 invoice_next_billing_time: self.revenue_recovery_data.invoice_next_billing_time,
+                billing_connector_payment_method_details,
+                first_payment_attempt_network_advice_code: first_network_advice_code,
+                first_payment_attempt_network_decline_code: first_network_decline_code,
+                first_payment_attempt_pg_error_code: first_pg_error_code,
             }),
             None => Err(errors::api_error_response::ApiErrorResponse::InternalServerError)
                 .attach_printable("Connector not found in payment attempt")?,
diff --git a/crates/hyperswitch_domain_models/src/revenue_recovery.rs b/crates/hyperswitch_domain_models/src/revenue_recovery.rs
index 82692047e4b..529c035eebc 100644
--- a/crates/hyperswitch_domain_models/src/revenue_recovery.rs
+++ b/crates/hyperswitch_domain_models/src/revenue_recovery.rs
@@ -48,6 +48,10 @@ pub struct RevenueRecoveryAttemptData {
     pub retry_count: Option<u16>,
     /// Time when next invoice will be generated which will be equal to the end time of the current invoice
     pub invoice_next_billing_time: Option<PrimitiveDateTime>,
+    /// card network type
+    pub card_network: Option<common_enums::CardNetwork>,
+    /// card isin
+    pub card_isin: Option<String>,
 }
 
 /// This is unified struct for Revenue Recovery Invoice Data and it is constructed from billing connectors
@@ -271,6 +275,8 @@ impl
             network_error_message: None,
             retry_count: invoice_details.retry_count,
             invoice_next_billing_time: invoice_details.next_billing_at,
+            card_network: billing_connector_payment_details.card_network.clone(),
+            card_isin: billing_connector_payment_details.card_isin.clone(),
         }
     }
 }
diff --git a/crates/hyperswitch_domain_models/src/router_response_types/revenue_recovery.rs b/crates/hyperswitch_domain_models/src/router_response_types/revenue_recovery.rs
index 598795fa116..8dd6aa2e74c 100644
--- a/crates/hyperswitch_domain_models/src/router_response_types/revenue_recovery.rs
+++ b/crates/hyperswitch_domain_models/src/router_response_types/revenue_recovery.rs
@@ -28,6 +28,10 @@ pub struct BillingConnectorPaymentsSyncResponse {
     pub payment_method_type: common_enums::enums::PaymentMethod,
     /// payment method sub type of the payment attempt.
     pub payment_method_sub_type: common_enums::enums::PaymentMethodType,
+    /// card netword network
+    pub card_network: Option<common_enums::CardNetwork>,
+    /// card isin
+    pub card_isin: Option<String>,
 }
 
 #[derive(Debug, Clone)]
diff --git a/crates/openapi/src/openapi_v2.rs b/crates/openapi/src/openapi_v2.rs
index 5b5ed7a83e4..d8e08a296d1 100644
--- a/crates/openapi/src/openapi_v2.rs
+++ b/crates/openapi/src/openapi_v2.rs
@@ -351,6 +351,8 @@ Never share your secret api keys. Keep them guarded and secure.
         api_models::payments::AliPayQr,
         api_models::payments::PaymentAttemptFeatureMetadata,
         api_models::payments::PaymentAttemptRevenueRecoveryData,
+        api_models::payments::BillingConnectorPaymentMethodDetails,
+        api_models::payments::BillingConnectorAdditionalCardInfo,
         api_models::payments::AliPayRedirection,
         api_models::payments::MomoRedirection,
         api_models::payments::TouchNGoRedirection,
diff --git a/crates/router/src/core/payments/operations/payment_attempt_record.rs b/crates/router/src/core/payments/operations/payment_attempt_record.rs
index 33848e1c39a..b2834f0bfad 100644
--- a/crates/router/src/core/payments/operations/payment_attempt_record.rs
+++ b/crates/router/src/core/payments/operations/payment_attempt_record.rs
@@ -199,6 +199,8 @@ impl<F: Send + Clone + Sync>
             retry_count: request.retry_count,
             invoice_next_billing_time: request.invoice_next_billing_time,
             triggered_by: request.triggered_by,
+            card_network: request.card_network.clone(),
+            card_issuer: request.card_issuer.clone(),
         };
         let payment_address = hyperswitch_domain_models::payment_address::PaymentAddress::new(
             payment_intent
diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs
index 042fb6ba94a..f467eb39dd4 100644
--- a/crates/router/src/core/payments/transformers.rs
+++ b/crates/router/src/core/payments/transformers.rs
@@ -4900,6 +4900,22 @@ impl ForeignFrom<&diesel_models::types::BillingConnectorPaymentDetails>
     }
 }
 
+#[cfg(feature = "v2")]
+impl ForeignFrom<&diesel_models::types::BillingConnectorPaymentMethodDetails>
+    for api_models::payments::BillingConnectorPaymentMethodDetails
+{
+    fn foreign_from(metadata: &diesel_models::types::BillingConnectorPaymentMethodDetails) -> Self {
+        match metadata {
+            diesel_models::types::BillingConnectorPaymentMethodDetails::Card(card_details) => {
+                Self::Card(api_models::payments::BillingConnectorAdditionalCardInfo {
+                    card_issuer: card_details.card_issuer.clone(),
+                    card_network: card_details.card_network.clone(),
+                })
+            }
+        }
+    }
+}
+
 #[cfg(feature = "v2")]
 impl ForeignFrom<&hyperswitch_domain_models::payments::payment_attempt::ErrorDetails>
     for api_models::payments::ErrorDetails
@@ -4965,6 +4981,17 @@ impl ForeignFrom<&diesel_models::types::FeatureMetadata> for api_models::payment
                         ),
                     invoice_next_billing_time: payment_revenue_recovery_metadata
                         .invoice_next_billing_time,
+                        billing_connector_payment_method_details:payment_revenue_recovery_metadata
+                        .billing_connector_payment_method_details.as_ref().map(api_models::payments::BillingConnectorPaymentMethodDetails::foreign_from),
+                    first_payment_attempt_network_advice_code: payment_revenue_recovery_metadata
+                        .first_payment_attempt_network_advice_code
+                        .clone(),
+                    first_payment_attempt_network_decline_code: payment_revenue_recovery_metadata
+                        .first_payment_attempt_network_decline_code
+                        .clone(),
+                    first_payment_attempt_pg_error_code: payment_revenue_recovery_metadata
+                        .first_payment_attempt_pg_error_code
+                        .clone(),
                 }
             });
         let apple_pay_details = feature_metadata
diff --git a/crates/router/src/core/revenue_recovery.rs b/crates/router/src/core/revenue_recovery.rs
index ee22507b8f7..235d57f96d7 100644
--- a/crates/router/src/core/revenue_recovery.rs
+++ b/crates/router/src/core/revenue_recovery.rs
@@ -69,14 +69,14 @@ pub async fn perform_execute_payment(
 
             match record_attempt {
                 Ok(_) => {
-                    let action = types::Action::execute_payment(
+                    let action = Box::pin(types::Action::execute_payment(
                         state,
                         revenue_recovery_payment_data.merchant_account.get_id(),
                         payment_intent,
                         execute_task_process,
                         revenue_recovery_payment_data,
                         &revenue_recovery_metadata,
-                    )
+                    ))
                     .await?;
                     Box::pin(action.execute_payment_task_response_handler(
                         state,
diff --git a/crates/router/src/core/revenue_recovery/api.rs b/crates/router/src/core/revenue_recovery/api.rs
index 60465964856..b58d7166837 100644
--- a/crates/router/src/core/revenue_recovery/api.rs
+++ b/crates/router/src/core/revenue_recovery/api.rs
@@ -183,16 +183,22 @@ pub async fn record_internal_attempt_api(
             message: "get_revenue_recovery_attempt was not constructed".to_string(),
         })?;
 
-    let request_payload = revenue_recovery_attempt_data.create_payment_record_request(
-        &revenue_recovery_payment_data.billing_mca.id,
-        Some(
-            revenue_recovery_metadata
-                .active_attempt_payment_connector_id
-                .clone(),
-        ),
-        Some(revenue_recovery_metadata.connector),
-        common_enums::TriggeredBy::Internal,
-    );
+    let request_payload = revenue_recovery_attempt_data
+        .create_payment_record_request(
+            state,
+            &revenue_recovery_payment_data.billing_mca.id,
+            Some(
+                revenue_recovery_metadata
+                    .active_attempt_payment_connector_id
+                    .clone(),
+            ),
+            Some(revenue_recovery_metadata.connector),
+            common_enums::TriggeredBy::Internal,
+        )
+        .await
+        .change_context(errors::ApiErrorResponse::GenericNotFoundError {
+            message: "Cannot Create the payment record Request".to_string(),
+        })?;
 
     let merchant_context_from_revenue_recovery_payment_data =
         MerchantContext::NormalMerchant(Box::new(Context(
diff --git a/crates/router/src/core/webhooks/recovery_incoming.rs b/crates/router/src/core/webhooks/recovery_incoming.rs
index 87c1a79aa12..18a51c3e9bb 100644
--- a/crates/router/src/core/webhooks/recovery_incoming.rs
+++ b/crates/router/src/core/webhooks/recovery_incoming.rs
@@ -545,14 +545,17 @@ impl RevenueRecoveryAttempt {
         errors::RevenueRecoveryError,
     > {
         let payment_connector_id =   payment_connector_account.as_ref().map(|account: &hyperswitch_domain_models::merchant_connector_account::MerchantConnectorAccount| account.id.clone());
-        let request_payload = self.create_payment_record_request(
-            billing_connector_account_id,
-            payment_connector_id,
-            payment_connector_account
-                .as_ref()
-                .map(|account| account.connector_name),
-            common_enums::TriggeredBy::External,
-        );
+        let request_payload = self
+            .create_payment_record_request(
+                state,
+                billing_connector_account_id,
+                payment_connector_id,
+                payment_connector_account
+                    .as_ref()
+                    .map(|account| account.connector_name),
+                common_enums::TriggeredBy::External,
+            )
+            .await?;
         let attempt_response = Box::pin(payments::record_attempt_core(
             state.clone(),
             req_state.clone(),
@@ -593,13 +596,15 @@ impl RevenueRecoveryAttempt {
         Ok(response)
     }
 
-    pub fn create_payment_record_request(
+    pub async fn create_payment_record_request(
         &self,
+        state: &SessionState,
         billing_merchant_connector_account_id: &id_type::MerchantConnectorAccountId,
         payment_merchant_connector_account_id: Option<id_type::MerchantConnectorAccountId>,
         payment_connector: Option<common_enums::connector_enums::Connector>,
         triggered_by: common_enums::TriggeredBy,
-    ) -> api_payments::PaymentsAttemptRecordRequest {
+    ) -> CustomResult<api_payments::PaymentsAttemptRecordRequest, errors::RevenueRecoveryError>
+    {
         let revenue_recovery_attempt_data = &self.0;
         let amount_details =
             api_payments::PaymentAttemptAmountDetails::from(revenue_recovery_attempt_data);
@@ -609,9 +614,27 @@ impl RevenueRecoveryAttempt {
                 attempt_triggered_by: triggered_by,
             }),
         };
+
+        let card_info = revenue_recovery_attempt_data
+            .card_isin
+            .clone()
+            .async_and_then(|isin| async move {
+                let issuer_identifier_number = isin.clone();
+                state
+                    .store
+                    .get_card_info(issuer_identifier_number.as_str())
+                    .await
+                    .map_err(|error| services::logger::warn!(card_info_error=?error))
+                    .ok()
+            })
+            .await
+            .flatten();
+
+        let card_issuer = card_info.and_then(|info| info.card_issuer);
+
         let error =
             Option::<api_payments::RecordAttemptErrorDetails>::from(revenue_recovery_attempt_data);
-        api_payments::PaymentsAttemptRecordRequest {
+        Ok(api_payments::PaymentsAttemptRecordRequest {
             amount_details,
             status: revenue_recovery_attempt_data.status,
             billing: None,
@@ -637,7 +660,9 @@ impl RevenueRecoveryAttempt {
             retry_count: revenue_recovery_attempt_data.retry_count,
             invoice_next_billing_time: revenue_recovery_attempt_data.invoice_next_billing_time,
             triggered_by,
-        }
+            card_network: revenue_recovery_attempt_data.card_network.clone(),
+            card_issuer,
+        })
     }
 
     pub async fn find_payment_merchant_connector_account(

## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [ ] Bugfix
- [ ] New feature
- [x] Enhancement
- [ ] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
The following details are needed to be stored in the payment intent feature metadata as a part of transaction monitoring system for revenue recovery. 

 1. Card Network
 2. Card Issuer
 3. First Payment Gateway Error Code
 4. First Network Error Code
 5. First Network Advice Code

These will be constant through out the lifecycle of the payment intent in revenue recovery system. We need to use these parameters further in revenue recovery system. We need this as training data and need these while Deciding optimal time for the retry.

These information is stored in payment intent because this information will be constant throughout for payment intent and this information cannot be populated every time we retry this payment.  


### Additional Changes

- [x] This PR modifies the API contract
- [x] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables

<!--
Provide links to the files with corresponding changes.

Following are the paths where you can find config files:
1. `config`
7. `crates/router/src/configs`
8. `loadtest/config`
-->


## Motivation and Context
<!--
Why is this change required? What problem does it solve?
If it fixes an open issue, please link to the issue here.

If you don't have an issue, we'd recommend starting with one first so the PR
can focus on the implementation (unless it is an obvious bug or documentation fix
that will have little conversation).
-->


## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
Can be tested by following the steps mentioned in this PR: #7461. Here are the test results:
```
{
    "redirect_response": null,
    "search_tags": null,
    "apple_pay_recurring_details": null,
    "payment_revenue_recovery_metadata": {
        "total_retry_count": 2,
        "payment_connector_transmission": "ConnectorCallUnsuccessful",
        "billing_connector_id": "mca_MWigDQEKB7Du4L9YqeSe",
        "active_attempt_payment_connector_id": "mca_PY26kh9v0Kiu1hd7lTzL",
        "billing_connector_payment_details": {
            "payment_processor_token": "card_1RXkE8RpLdtbmMLFiOTVtzLI",
            "connector_customer_id": "cus_SSfYcZWkulAsCG"
        },
        "payment_method_type": "card",
        "payment_method_subtype": "credit",
        "connector": "stripe",
        "invoice_next_billing_time": "2025-07-15 18:30:00.0",
        "card_network": "Visa",
        "card_issuer": null,
        "first_payment_attempt_pg_error_code": "card_declined",
        "first_payment_attempt_network_decline_code": "card_declined",
        "first_payment_attempt_network_advice_code": "card_declined"
    }
}
```

Or 

Run this Curl by filling our: 
```
curl --location 'http://localhost:8080/v2/payments/create-intent' \
--header 'Content-Type: application/json' \
--header 'x-profile-id: Profile_id' \
--header 'Authorization: api-key=api-key' \
--header 'api-key: apikey' \
--data-raw '{
    "amount_details": {
        "order_amount": 100,
        "currency": "USD"
    },
    "capture_method":"manual",
    "authentication_type": "no_three_ds",
    "billing": {
        "address": {
            "first_name": "John",
            "last_name": "Dough"
        },
        "email": "example@example.com"
    },
    "shipping": {
        "address": {
            "first_name": "John",
            "last_name": "Dough",
            "city": "Karwar",
            "zip": "581301",
            "state": "Karnataka"
        },
        "email": "example@example.com"
    },
    "feature_metadata": {
        "payment_revenue_recovery_metadata": {
            "total_retry_count": 2,
            "payment_connector_transmission": "ConnectorCallUnsuccessful", 
            "billing_connector_id": "bca_12345",
            "active_attempt_payment_connector_id": "pca_67890",
            "billing_connector_payment_details": {
                "payment_processor_token": "tok_abcdef123456",
                "connector_customer_id": "cust_98765"
            },
            "payment_method_type": "card",
            "payment_method_subtype": "credit",
            "connector": "stripe",
            "invoice_next_billing_time": "2025-06-12T15:00:00Z",
            "billing_connector_payment_method_details": {
                    "type": "Card",
                    "value": {
                        "card_network": "Visa",
                        "card_issuer": "HDFC Bank"
                    }
                },
            "first_payment_attempt_pg_error_code": "PG001",
            "first_payment_attempt_network_decline_code": "ND002",
            "first_payment_attempt_network_advice_code": "AD003"
        }

    }
}'
```

This is the expected response

```
{
    "id": "12345_pay_019763e442877b72aaa3b0a5304b2c4e",
    "status": "requires_payment_method",
    "amount_details": {
        "order_amount": 100,
        "currency": "USD",
        "shipping_cost": null,
        "order_tax_amount": null,
        "external_tax_calculation": "skip",
        "surcharge_calculation": "skip",
        "surcharge_amount": null,
        "tax_on_surcharge": null
    },
    "client_secret": "cs_019763e442ad7ff1b735ca04e9810f2c",
    "profile_id": "pro_jhWJnFzJZ4tDqxGRrSbX",
    "merchant_reference_id": null,
    "routing_algorithm_id": null,
    "capture_method": "manual",
    "authentication_type": "no_three_ds",
    "billing": {
        "address": {
            "city": null,
            "country": null,
            "line1": null,
            "line2": null,
            "line3": null,
            "zip": null,
            "state": null,
            "first_name": "John",
            "last_name": "Dough"
        },
        "phone": null,
        "email": "example@example.com"
    },
    "shipping": {
        "address": {
            "city": "Karwar",
            "country": null,
            "line1": null,
            "line2": null,
            "line3": null,
            "zip": "581301",
            "state": "Karnataka",
            "first_name": "John",
            "last_name": "Dough"
        },
        "phone": null,
        "email": "example@example.com"
    },
    "customer_id": null,
    "customer_present": "present",
    "description": null,
    "return_url": null,
    "setup_future_usage": "on_session",
    "apply_mit_exemption": "Skip",
    "statement_descriptor": null,
    "order_details": null,
    "allowed_payment_method_types": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": {
        "redirect_response": null,
        "search_tags": null,
        "apple_pay_recurring_details": null,
        "payment_revenue_recovery_metadata": {
            "total_retry_count": 2,
            "payment_connector_transmission": "ConnectorCallUnsuccessful",
            "billing_connector_id": "bca_12345",
            "active_attempt_payment_connector_id": "pca_67890",
            "billing_connector_payment_details": {
                "payment_processor_token": "tok_abcdef123456",
                "connector_customer_id": "cust_98765"
            },
            "payment_method_type": "card",
            "payment_method_subtype": "credit",
            "connector": "stripe",
            "billing_connector_payment_method_details": {
                "type": "Card",
                "value": {
                    "card_network": "Visa",
                    "card_issuer": "HDFC Bank"
                }
            },
            "invoice_next_billing_time": "2025-06-12T15:00:00.000Z",
            "first_payment_attempt_pg_error_code": "PG001",
            "first_payment_attempt_network_decline_code": "ND002",
            "first_payment_attempt_network_advice_code": "AD003"
        }
    },
    "payment_link_enabled": "Skip",
    "payment_link_config": null,
    "request_incremental_authorization": "default",
    "expires_on": "2025-06-12T11:41:33.123Z",
    "frm_metadata": null,
    "request_external_three_ds_authentication": "Skip"
}

```
Check the DB for feature metadata and verify the data. 
 
Sample log: 
<img width="1205" alt="Screenshot 2025-06-12 at 5 02 26 PM" src="https://github.com/user-attachments/assets/b93cdf63-b8fb-4ae8-be1e-8a11d8c66a96" />


## Checklist
<!-- Put an `x` in the boxes that apply -->

- [x] I formatted the code `cargo +nightly fmt --all`
- [x] I addressed lints thrown by `cargo clippy`
- [x] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible


<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

- **New Features**
  - Added support for capturing and displaying additional card metadata, including card network, card issuer, and card ISIN, in payment and revenue recovery data.
  - Enhanced error reporting by including detailed error codes from the first payment attempt, such as payment gateway error codes, network decline codes, and advice codes.
- **Bug Fixes**
  - Improved propagation and mapping of card and error information across payment and revenue recovery processes.
- **Chores**
  - Updated internal processes to fetch and enrich card issuer information asynchronously during revenue recovery operations.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->