Bug: [FEATURE] Add original authorized amount in router data



### Feature Description

Add original authorized amount in router data for recurring mandate payments. This field is required in Cybersource for Discover cards recurring mandate payments.

### Possible Implementation

Add fields `original_payment_authorized_amount` and `original_payment_authorized_currency` in struct `RecurringMandatePaymentData`.

### Have you spent some time checking if this feature request has been raised before?

- [X] I checked and didn't find a similar issue

### Have you read the Contributing Guidelines?

- [X] I have read the [Contributing Guidelines](https://github.com/juspay/hyperswitch/blob/main/docs/CONTRIBUTING.md)

### Are you willing to submit a PR?

None
diff --git a/crates/router/src/connector/bankofamerica/transformers.rs b/crates/router/src/connector/bankofamerica/transformers.rs
index 72e3de0bf77..db96ff62f6c 100644
--- a/crates/router/src/connector/bankofamerica/transformers.rs
+++ b/crates/router/src/connector/bankofamerica/transformers.rs
@@ -442,7 +442,7 @@ pub struct ClientRiskInformationRules {
 #[serde(rename_all = "camelCase")]
 pub struct Avs {
     code: String,
-    code_raw: String,
+    code_raw: Option<String>,
 }
 
 impl
diff --git a/crates/router/src/connector/cybersource/transformers.rs b/crates/router/src/connector/cybersource/transformers.rs
index 8beb81d9236..7ef47912744 100644
--- a/crates/router/src/connector/cybersource/transformers.rs
+++ b/crates/router/src/connector/cybersource/transformers.rs
@@ -10,7 +10,7 @@ use crate::{
     connector::utils::{
         self, AddressDetailsData, ApplePayDecrypt, CardData, PaymentsAuthorizeRequestData,
         PaymentsCompleteAuthorizeRequestData, PaymentsPreProcessingData,
-        PaymentsSetupMandateRequestData, PaymentsSyncRequestData, RouterData,
+        PaymentsSetupMandateRequestData, PaymentsSyncRequestData, RecurringMandateData, RouterData,
     },
     consts,
     core::errors,
@@ -47,6 +47,7 @@ impl<T>
             T,
         ),
     ) -> Result<Self, Self::Error> {
+        // This conversion function is used at different places in the file, if updating this, keep a check for those
         let amount = utils::get_amount_as_string(currency_unit, amount, currency)?;
         Ok(Self {
             amount,
@@ -81,11 +82,11 @@ impl TryFrom<&types::SetupMandateRouterData> for CybersourceZeroMandateRequest {
             Some(vec![CybersourceActionsList::TokenCreate]),
             Some(vec![CybersourceActionsTokenType::PaymentInstrument]),
             Some(CybersourceAuthorizationOptions {
-                initiator: CybersourcePaymentInitiator {
+                initiator: Some(CybersourcePaymentInitiator {
                     initiator_type: Some(CybersourcePaymentInitiatorTypes::Customer),
                     credential_stored_on_file: Some(true),
                     stored_credential_used: None,
-                },
+                }),
                 merchant_intitiated_transaction: None,
             }),
         );
@@ -272,14 +273,16 @@ pub enum CybersourceActionsTokenType {
 #[derive(Debug, Serialize)]
 #[serde(rename_all = "camelCase")]
 pub struct CybersourceAuthorizationOptions {
-    initiator: CybersourcePaymentInitiator,
+    initiator: Option<CybersourcePaymentInitiator>,
     merchant_intitiated_transaction: Option<MerchantInitiatedTransaction>,
 }
 
 #[derive(Debug, Serialize)]
 #[serde(rename_all = "camelCase")]
 pub struct MerchantInitiatedTransaction {
-    reason: String,
+    reason: Option<String>,
+    //Required for recurring mandates payment
+    original_authorized_amount: Option<String>,
 }
 
 #[derive(Debug, Serialize)]
@@ -470,35 +473,60 @@ impl From<&CybersourceRouterData<&types::PaymentsCompleteAuthorizeRouterData>>
 }
 
 impl
-    From<(
+    TryFrom<(
         &CybersourceRouterData<&types::PaymentsAuthorizeRouterData>,
         Option<PaymentSolution>,
     )> for ProcessingInformation
 {
-    fn from(
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(
         (item, solution): (
             &CybersourceRouterData<&types::PaymentsAuthorizeRouterData>,
             Option<PaymentSolution>,
         ),
-    ) -> Self {
+    ) -> Result<Self, Self::Error> {
         let (action_list, action_token_types, authorization_options) =
             if item.router_data.request.setup_mandate_details.is_some() {
                 (
                     Some(vec![CybersourceActionsList::TokenCreate]),
                     Some(vec![CybersourceActionsTokenType::PaymentInstrument]),
                     Some(CybersourceAuthorizationOptions {
-                        initiator: CybersourcePaymentInitiator {
+                        initiator: Some(CybersourcePaymentInitiator {
                             initiator_type: Some(CybersourcePaymentInitiatorTypes::Customer),
                             credential_stored_on_file: Some(true),
                             stored_credential_used: None,
-                        },
+                        }),
                         merchant_intitiated_transaction: None,
                     }),
                 )
+            } else if item.router_data.request.connector_mandate_id().is_some() {
+                let original_amount = item
+                    .router_data
+                    .get_recurring_mandate_payment_data()?
+                    .get_original_payment_amount()?;
+                let original_currency = item
+                    .router_data
+                    .get_recurring_mandate_payment_data()?
+                    .get_original_payment_currency()?;
+                (
+                    None,
+                    None,
+                    Some(CybersourceAuthorizationOptions {
+                        initiator: None,
+                        merchant_intitiated_transaction: Some(MerchantInitiatedTransaction {
+                            reason: None,
+                            original_authorized_amount: Some(utils::get_amount_as_string(
+                                &types::api::CurrencyUnit::Base,
+                                original_amount,
+                                original_currency,
+                            )?),
+                        }),
+                    }),
+                )
             } else {
                 (None, None, None)
             };
-        Self {
+        Ok(Self {
             capture: Some(matches!(
                 item.router_data.request.capture_method,
                 Some(enums::CaptureMethod::Automatic) | None
@@ -509,7 +537,7 @@ impl
             authorization_options,
             capture_options: None,
             commerce_indicator: String::from("internet"),
-        }
+        })
     }
 }
 
@@ -533,11 +561,11 @@ impl
                     Some(vec![CybersourceActionsList::TokenCreate]),
                     Some(vec![CybersourceActionsTokenType::PaymentInstrument]),
                     Some(CybersourceAuthorizationOptions {
-                        initiator: CybersourcePaymentInitiator {
+                        initiator: Some(CybersourcePaymentInitiator {
                             initiator_type: Some(CybersourcePaymentInitiatorTypes::Customer),
                             credential_stored_on_file: Some(true),
                             stored_credential_used: None,
-                        },
+                        }),
                         merchant_intitiated_transaction: None,
                     }),
                 )
@@ -680,7 +708,7 @@ impl
             },
         });
 
-        let processing_information = ProcessingInformation::from((item, None));
+        let processing_information = ProcessingInformation::try_from((item, None))?;
         let client_reference_information = ClientReferenceInformation::from(item);
         let merchant_defined_information =
             item.router_data.request.metadata.clone().map(|metadata| {
@@ -792,7 +820,7 @@ impl
         let bill_to = build_bill_to(item.router_data.get_billing()?, email)?;
         let order_information = OrderInformationWithBill::from((item, bill_to));
         let processing_information =
-            ProcessingInformation::from((item, Some(PaymentSolution::ApplePay)));
+            ProcessingInformation::try_from((item, Some(PaymentSolution::ApplePay)))?;
         let client_reference_information = ClientReferenceInformation::from(item);
         let expiration_month = apple_pay_data.get_expiry_month()?;
         let expiration_year = apple_pay_data.get_four_digit_expiry_year()?;
@@ -846,7 +874,7 @@ impl
             },
         });
         let processing_information =
-            ProcessingInformation::from((item, Some(PaymentSolution::GooglePay)));
+            ProcessingInformation::try_from((item, Some(PaymentSolution::GooglePay)))?;
         let client_reference_information = ClientReferenceInformation::from(item);
         let merchant_defined_information =
             item.router_data.request.metadata.clone().map(|metadata| {
@@ -893,10 +921,9 @@ impl TryFrom<&CybersourceRouterData<&types::PaymentsAuthorizeRouterData>>
                                         build_bill_to(item.router_data.get_billing()?, email)?;
                                     let order_information =
                                         OrderInformationWithBill::from((item, bill_to));
-                                    let processing_information = ProcessingInformation::from((
-                                        item,
-                                        Some(PaymentSolution::ApplePay),
-                                    ));
+                                    let processing_information = ProcessingInformation::try_from(
+                                        (item, Some(PaymentSolution::ApplePay)),
+                                    )?;
                                     let client_reference_information =
                                         ClientReferenceInformation::from(item);
                                     let payment_information = PaymentInformation::ApplePayToken(
@@ -1008,7 +1035,7 @@ impl
             String,
         ),
     ) -> Result<Self, Self::Error> {
-        let processing_information = ProcessingInformation::from((item, None));
+        let processing_information = ProcessingInformation::try_from((item, None))?;
         let payment_instrument = CybersoucrePaymentInstrument {
             id: connector_mandate_id,
         };
@@ -1159,13 +1186,14 @@ impl TryFrom<&CybersourceRouterData<&types::PaymentsIncrementalAuthorizationRout
                 action_list: None,
                 action_token_types: None,
                 authorization_options: Some(CybersourceAuthorizationOptions {
-                    initiator: CybersourcePaymentInitiator {
+                    initiator: Some(CybersourcePaymentInitiator {
                         initiator_type: None,
                         credential_stored_on_file: None,
                         stored_credential_used: Some(true),
-                    },
+                    }),
                     merchant_intitiated_transaction: Some(MerchantInitiatedTransaction {
-                        reason: "5".to_owned(),
+                        reason: Some("5".to_owned()),
+                        original_authorized_amount: None,
                     }),
                 }),
                 commerce_indicator: String::from("internet"),
@@ -1339,18 +1367,6 @@ impl From<CybersourceIncrementalAuthorizationStatus> for common_enums::Authoriza
     }
 }
 
-impl From<CybersourcePaymentStatus> for enums::RefundStatus {
-    fn from(item: CybersourcePaymentStatus) -> Self {
-        match item {
-            CybersourcePaymentStatus::Succeeded | CybersourcePaymentStatus::Transmitted => {
-                Self::Success
-            }
-            CybersourcePaymentStatus::Failed => Self::Failure,
-            _ => Self::Pending,
-        }
-    }
-}
-
 #[derive(Debug, Deserialize)]
 #[serde(untagged)]
 pub enum CybersourcePaymentsResponse {
@@ -1430,7 +1446,7 @@ pub struct ClientProcessorInformation {
 #[serde(rename_all = "camelCase")]
 pub struct Avs {
     code: String,
-    code_raw: String,
+    code_raw: Option<String>,
 }
 
 #[derive(Debug, Clone, Deserialize)]
diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs
index 8f028e37a9e..c59fea47612 100644
--- a/crates/router/src/connector/utils.rs
+++ b/crates/router/src/connector/utils.rs
@@ -24,7 +24,7 @@ use crate::{
     consts,
     core::{
         errors::{self, ApiErrorResponse, CustomResult},
-        payments::PaymentData,
+        payments::{PaymentData, RecurringMandatePaymentData},
     },
     pii::PeekInterface,
     types::{
@@ -80,6 +80,7 @@ pub trait RouterData {
     fn get_customer_id(&self) -> Result<String, Error>;
     fn get_connector_customer_id(&self) -> Result<String, Error>;
     fn get_preprocessing_id(&self) -> Result<String, Error>;
+    fn get_recurring_mandate_payment_data(&self) -> Result<RecurringMandatePaymentData, Error>;
     #[cfg(feature = "payouts")]
     fn get_payout_method_data(&self) -> Result<api::PayoutMethodData, Error>;
     #[cfg(feature = "payouts")]
@@ -249,6 +250,12 @@ impl<Flow, Request, Response> RouterData for types::RouterData<Flow, Request, Re
             .to_owned()
             .ok_or_else(missing_field_err("preprocessing_id"))
     }
+    fn get_recurring_mandate_payment_data(&self) -> Result<RecurringMandatePaymentData, Error> {
+        self.recurring_mandate_payment_data
+            .to_owned()
+            .ok_or_else(missing_field_err("recurring_mandate_payment_data"))
+    }
+
     #[cfg(feature = "payouts")]
     fn get_payout_method_data(&self) -> Result<api::PayoutMethodData, Error> {
         self.payout_method_data
@@ -1132,6 +1139,22 @@ impl MandateData for payments::MandateAmountData {
     }
 }
 
+pub trait RecurringMandateData {
+    fn get_original_payment_amount(&self) -> Result<i64, Error>;
+    fn get_original_payment_currency(&self) -> Result<diesel_models::enums::Currency, Error>;
+}
+
+impl RecurringMandateData for RecurringMandatePaymentData {
+    fn get_original_payment_amount(&self) -> Result<i64, Error> {
+        self.original_payment_authorized_amount
+            .ok_or_else(missing_field_err("original_payment_authorized_amount"))
+    }
+    fn get_original_payment_currency(&self) -> Result<diesel_models::enums::Currency, Error> {
+        self.original_payment_authorized_currency
+            .ok_or_else(missing_field_err("original_payment_authorized_currency"))
+    }
+}
+
 pub trait MandateReferenceData {
     fn get_connector_mandate_id(&self) -> Result<String, Error>;
 }
diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs
index 043863a98fa..c9e1f6137b7 100644
--- a/crates/router/src/core/payments.rs
+++ b/crates/router/src/core/payments.rs
@@ -2045,6 +2045,8 @@ pub struct IncrementalAuthorizationDetails {
 #[derive(Debug, Default, Clone)]
 pub struct RecurringMandatePaymentData {
     pub payment_method_type: Option<storage_enums::PaymentMethodType>, //required for making recurring payment using saved payment method through stripe
+    pub original_payment_authorized_amount: Option<i64>,
+    pub original_payment_authorized_currency: Option<storage_enums::Currency>,
 }
 
 #[derive(Debug, Default, Clone)]
diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs
index 213adc79fb0..0cbed255348 100644
--- a/crates/router/src/core/payments/helpers.rs
+++ b/crates/router/src/core/payments/helpers.rs
@@ -479,6 +479,27 @@ pub async fn get_token_for_recurring_mandate(
         .await
         .to_not_found_response(errors::ApiErrorResponse::MandateNotFound)?;
 
+    let original_payment_intent = mandate
+        .original_payment_id
+        .as_ref()
+        .async_map(|payment_id| async {
+            db.find_payment_intent_by_payment_id_merchant_id(
+                payment_id,
+                &mandate.merchant_id,
+                merchant_account.storage_scheme,
+            )
+            .await
+            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)
+            .map_err(|err| logger::error!(mandate_original_payment_not_found=?err))
+            .ok()
+        })
+        .await
+        .flatten();
+
+    let original_payment_authorized_amount = original_payment_intent.clone().map(|pi| pi.amount);
+    let original_payment_authorized_currency =
+        original_payment_intent.clone().and_then(|pi| pi.currency);
+
     let customer = req.customer_id.clone().get_required_value("customer_id")?;
 
     let payment_method_id = {
@@ -540,6 +561,8 @@ pub async fn get_token_for_recurring_mandate(
             Some(payment_method.payment_method),
             Some(payments::RecurringMandatePaymentData {
                 payment_method_type,
+                original_payment_authorized_amount,
+                original_payment_authorized_currency,
             }),
             payment_method.payment_method_type,
             Some(mandate_connector_details),
@@ -550,6 +573,8 @@ pub async fn get_token_for_recurring_mandate(
             Some(payment_method.payment_method),
             Some(payments::RecurringMandatePaymentData {
                 payment_method_type,
+                original_payment_authorized_amount,
+                original_payment_authorized_currency,
             }),
             payment_method.payment_method_type,
             Some(mandate_connector_details),

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

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

## Description
<!-- Describe your changes in detail -->
Add original authorized amount in router data for recurring mandate payments.

### Additional Changes

- [ ] This PR modifies the API contract
- [ ] 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`
2. `crates/router/src/configs`
3. `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).
-->
https://github.com/juspay/hyperswitch/issues/3418

## 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)?
-->
Testing can be done by creating a recurring mandate payment in cybersource and using the following discover cards: 6011111111111117, 6011000991300009

Curls:

- Payment Intent Create:
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: API_KEY_HERE' \
--data-raw '{
    "amount": 0,
    "order_details": null,
    "currency": "USD",
    "confirm": false,
    "capture_method": "automatic",
    "authentication_type": "no_three_ds",
    "customer_id": "cut2",
    "email": "johndoe@gmail.com",
    "description": "Hello this is description",
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "joseph",
            "last_name": "Doe"
        }   
    },
    "metadata": {},
    "setup_future_usage": "off_session"
}'
```

- Payments - Confirm: 
`curl --location 'http://localhost:8080/payments/{payment_id}/confirm' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: API_KEY_HERE' \
--data '{
    "setup_future_usage": "off_session",
    "payment_method": "card",
    "payment_method_type": "credit",
    "payment_type": "setup_mandate",
    "off_session": true,
    "payment_method_data": {
        "card": {
            "card_number": "6011000991300009",
            "card_exp_month": "12",
            "card_exp_year": "30",
            "card_holder_name": "joseph Doe",
            "card_cvc": "123"
        }
    },
    "browser_info": {
        "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
        "accept_header": "text\\/html,application\\/xhtml+xml,application\\/xml;q=0.9,image\\/webp,image\\/apng,*\\/*;q=0.8",
        "language": "en-GB",
        "color_depth": 24,
        "screen_height": 1440,
        "screen_width": 2560,
        "time_zone": -330,
        "java_enabled": true,
        "java_script_enabled": true,
        "ip_address": "0.0.0.0"
    },
    "mandate_data": {
        "customer_acceptance": {
            "acceptance_type": "offline",
            "accepted_at": "1963-05-03T04:07:52.723Z",
            "online": {
                "ip_address": "125.0.0.1", 
                "user_agent": "amet irure esse"
            }
        },
        "mandate_type": {
            "single_use": {
                "amount": 68607706,
                "currency": "USD"
            }
        }
    }
}'`

- Payments - Create using Mandates
`curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: API_KEY_HERE' \
--data-raw '{
    "amount": 200,
    "currency": "USD",
    "confirm": true,
    "customer_id": "{customer_id}",
    "email": "johndoe@gmail.com",
    "name": "John Doe",
    "phone": "999999999",
  "capture_method": "automatic",
    "phone_country_code": "+1",
    "description": "Its my first payment request",
    "return_url": "https://google.com",
    "mandate_id": "{mandate_id}",
    "off_session":true,
    "browser_info": {
        "ip_address":"172.0.0.1"
    },
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "joseph",
            "last_name": "Doe"
        }     
    }
}'`

## 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
- [ ] I added a [CHANGELOG](/CHANGELOG.md) entry if applicable
