Bug: [REFACTOR]: [MOLLIE] Add amount conversion framework to Mollie



### :memo: Feature Description

Currently, amounts are represented as `i64` values throughout the application. We want to introduce a `Unit` struct that explicitly states the denomination. A new type, `MinorUnit`, has been added to standardize the flow of amounts across the application. This type will now be used by all the connector flows.

Rather than handling conversions in each connector, we will centralize the conversion logic in one place within the core of the application.

### :hammer: Possible Implementation

- For each connector, we need to create an amount conversion function. Connectors will specify the format they require, and the core framework will handle the conversion accordingly.
- Connectors should invoke the `convert` function to receive the amount in their required format.
- Refer to the [connector documentation](https://docs.mollie.com/reference/create-payment) to determine the required amount format for each connector.
- You can refer [this PR](https://github.com/juspay/hyperswitch/pull/4825) for more context.


🔖 Note: All the changes needed should be contained within `hyperswitch/crates/router/src/connector/` , `crates/router/src/types/api.rs` , `crates/router/tests/connectors/`


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

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

### :package: Have you read the Contributing Guidelines?

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

### :package: Submission Process:
- Ask the maintainers for assignment of the issue, you can request for assignment by commenting on the issue itself.
- Once assigned, submit a pull request (PR).
- Maintainers will review and provide feedback, if any. 
- Maintainers can unassign issues due to inactivity, [read more here](https://github.com/juspay/hyperswitch/wiki/Hacktoberfest-Contribution-Rules).

Refer [here](https://github.com/juspay/hyperswitch/blob/main/docs/TERMS_OF_CONTEST.md) for Terms and conditions for the contest.

###  :sparkles: Are you willing to submit a PR?

diff --git a/crates/hyperswitch_connectors/src/connectors/mollie.rs b/crates/hyperswitch_connectors/src/connectors/mollie.rs
index 5066fb422fa..010ae90c56f 100644
--- a/crates/hyperswitch_connectors/src/connectors/mollie.rs
+++ b/crates/hyperswitch_connectors/src/connectors/mollie.rs
@@ -1,12 +1,11 @@
 pub mod transformers;
 
-use std::fmt::Debug;
-
 use common_enums::enums;
 use common_utils::{
     errors::CustomResult,
     ext_traits::BytesExt,
     request::{Method, Request, RequestBuilder, RequestContent},
+    types::{AmountConvertor, StringMajorUnit, StringMajorUnitForConnector},
 };
 use error_stack::{report, ResultExt};
 use hyperswitch_domain_models::{
@@ -43,10 +42,20 @@ use masking::{Mask, PeekInterface};
 use transformers as mollie;
 
 // use self::mollie::{webhook_headers, VoltWebhookBodyEventType};
-use crate::{constants::headers, types::ResponseRouterData};
+use crate::{constants::headers, types::ResponseRouterData, utils::convert_amount};
+
+#[derive(Clone)]
+pub struct Mollie {
+    amount_converter: &'static (dyn AmountConvertor<Output = StringMajorUnit> + Sync),
+}
 
-#[derive(Debug, Clone)]
-pub struct Mollie;
+impl Mollie {
+    pub fn new() -> &'static Self {
+        &Self {
+            amount_converter: &StringMajorUnitForConnector,
+        }
+    }
+}
 
 impl api::Payment for Mollie {}
 impl api::PaymentSession for Mollie {}
@@ -254,12 +263,13 @@ impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData
         req: &PaymentsAuthorizeRouterData,
         _connectors: &Connectors,
     ) -> CustomResult<RequestContent, errors::ConnectorError> {
-        let router_obj = mollie::MollieRouterData::try_from((
-            &self.get_currency_unit(),
+        let amount = convert_amount(
+            self.amount_converter,
+            req.request.minor_amount,
             req.request.currency,
-            req.request.amount,
-            req,
-        ))?;
+        )?;
+
+        let router_obj = mollie::MollieRouterData::from((amount, req));
         let connector_req = mollie::MolliePaymentsRequest::try_from(&router_obj)?;
         Ok(RequestContent::Json(Box::new(connector_req)))
     }
@@ -448,12 +458,13 @@ impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Mollie
         req: &RefundsRouterData<Execute>,
         _connectors: &Connectors,
     ) -> CustomResult<RequestContent, errors::ConnectorError> {
-        let router_obj = mollie::MollieRouterData::try_from((
-            &self.get_currency_unit(),
+        let amount = convert_amount(
+            self.amount_converter,
+            req.request.minor_refund_amount,
             req.request.currency,
-            req.request.refund_amount,
-            req,
-        ))?;
+        )?;
+
+        let router_obj = mollie::MollieRouterData::from((amount, req));
         let connector_req = mollie::MollieRefundRequest::try_from(&router_obj)?;
         Ok(RequestContent::Json(Box::new(connector_req)))
     }
diff --git a/crates/hyperswitch_connectors/src/connectors/mollie/transformers.rs b/crates/hyperswitch_connectors/src/connectors/mollie/transformers.rs
index a12434a460a..dc5f64bee18 100644
--- a/crates/hyperswitch_connectors/src/connectors/mollie/transformers.rs
+++ b/crates/hyperswitch_connectors/src/connectors/mollie/transformers.rs
@@ -1,6 +1,6 @@
 use cards::CardNumber;
 use common_enums::enums;
-use common_utils::{pii::Email, request::Method};
+use common_utils::{pii::Email, request::Method, types::StringMajorUnit};
 use hyperswitch_domain_models::{
     payment_method_data::{BankDebitData, BankRedirectData, PaymentMethodData, WalletData},
     router_data::{ConnectorAuthType, PaymentMethodToken, RouterData},
@@ -8,7 +8,7 @@ use hyperswitch_domain_models::{
     router_response_types::{PaymentsResponseData, RedirectForm, RefundsResponseData},
     types,
 };
-use hyperswitch_interfaces::{api, errors};
+use hyperswitch_interfaces::errors;
 use masking::{ExposeInterface, Secret};
 use serde::{Deserialize, Serialize};
 use url::Url;
@@ -17,7 +17,7 @@ use crate::{
     types::{RefundsResponseRouterData, ResponseRouterData},
     unimplemented_payment_method,
     utils::{
-        self, AddressDetailsData, BrowserInformationData, CardData as CardDataUtil,
+        AddressDetailsData, BrowserInformationData, CardData as CardDataUtil,
         PaymentMethodTokenizationRequestData, PaymentsAuthorizeRequestData, RouterData as _,
     },
 };
@@ -26,26 +26,16 @@ type Error = error_stack::Report<errors::ConnectorError>;
 
 #[derive(Debug, Serialize)]
 pub struct MollieRouterData<T> {
-    pub amount: String,
+    pub amount: StringMajorUnit,
     pub router_data: T,
 }
 
-impl<T> TryFrom<(&api::CurrencyUnit, enums::Currency, i64, T)> for MollieRouterData<T> {
-    type Error = error_stack::Report<errors::ConnectorError>;
-
-    fn try_from(
-        (currency_unit, currency, amount, router_data): (
-            &api::CurrencyUnit,
-            enums::Currency,
-            i64,
-            T,
-        ),
-    ) -> Result<Self, Self::Error> {
-        let amount = utils::get_amount_as_string(currency_unit, amount, currency)?;
-        Ok(Self {
+impl<T> From<(StringMajorUnit, T)> for MollieRouterData<T> {
+    fn from((amount, router_data): (StringMajorUnit, T)) -> Self {
+        Self {
             amount,
             router_data,
-        })
+        }
     }
 }
 
@@ -68,7 +58,7 @@ pub struct MolliePaymentsRequest {
 #[derive(Default, Debug, Serialize, Deserialize)]
 pub struct Amount {
     currency: enums::Currency,
-    value: String,
+    value: StringMajorUnit,
 }
 
 #[derive(Debug, Serialize)]
diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs
index e115558995d..ba2d6999f2b 100644
--- a/crates/router/src/types/api.rs
+++ b/crates/router/src/types/api.rs
@@ -434,7 +434,9 @@ impl ConnectorData {
                     Ok(ConnectorEnum::Old(Box::new(connector::Itaubank::new())))
                 }
                 enums::Connector::Klarna => Ok(ConnectorEnum::Old(Box::new(&connector::Klarna))),
-                enums::Connector::Mollie => Ok(ConnectorEnum::Old(Box::new(&connector::Mollie))),
+                enums::Connector::Mollie => {
+                    Ok(ConnectorEnum::Old(Box::new(connector::Mollie::new())))
+                }
                 enums::Connector::Nexixpay => {
                     Ok(ConnectorEnum::Old(Box::new(connector::Nexixpay::new())))
                 }
diff --git a/crates/router/tests/connectors/mollie.rs b/crates/router/tests/connectors/mollie.rs
index 7017363cad0..d59bc78226d 100644
--- a/crates/router/tests/connectors/mollie.rs
+++ b/crates/router/tests/connectors/mollie.rs
@@ -13,7 +13,7 @@ impl utils::Connector for MollieTest {
     fn get_data(&self) -> types::api::ConnectorData {
         use router::connector::Mollie;
         utils::construct_connector_data_old(
-            Box::new(&Mollie),
+            Box::new(Mollie::new()),
             types::Connector::Mollie,
             types::api::GetToken::Connector,
             None,

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


## Description
<!-- Describe your changes in detail -->
This PR do amount conversion changes for Mollie Connector and it accepts the amount in StringMajorUnit

### 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).
-->
 Fixes https://github.com/juspay/hyperswitch/issues/6092
 
 ## Test Cases
 1. Create Merchant Account
 ```
 curl --location 'http://localhost:8080/accounts' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: test_admin' \
--data-raw '{
    "merchant_id": "merchant_1729161609",
    "locker_id": "m0010",
    "merchant_name": "NewAge Retailer",
    "primary_business_details": [
        {
            "country": "US",
            "business": "default"
        },
        {
            "country": "GB",
            "business": "payouts"
        }
    ],
    "merchant_details": {
        "primary_contact_person": "John Test",
        "primary_email": "JohnTest@test.com",
        "primary_phone": "sunt laborum",
        "secondary_contact_person": "John Test2",
        "secondary_email": "JohnTest2@test.com",
        "secondary_phone": "cillum do dolor id",
        "website": "www.example.com",
        "about_business": "Online Retail with a wide selection of organic products for North America",
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US"
        }
    },
    "return_url": "https://duck.com",
    "webhook_details": {
        "webhook_version": "1.0.1",
        "webhook_username": "ekart_retail",
        "webhook_password": "password_ekart@123",
        "payment_created_enabled": true,
        "payment_succeeded_enabled": true,
        "payment_failed_enabled": true
    },
    "sub_merchants_enabled": false,
    "metadata": {
        "city": "NY",
        "unit": "245"
    }
}'
```
2. Create API key 
```
curl --location 'http://localhost:8080/api_keys/merchant_1729160602' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key:__' \
--data '{
  "name": "API Key 1",
  "description": null,
  "expiration": "2045-09-23T01:02:03.000Z"
}'
```
3. Create MCA for Mollie connector
```
curl --location 'http://localhost:8080/account/merchant_1729160602/connectors' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: test_admin' \
--data '{
  "connector_type": "payment_processor",
  "connector_name": "mollie",
  "connector_account_details":{
    
    "auth_type":"HeaderKey",
    "api_key":"_____________"
    
},
  "test_mode": false,
  "disabled": false,

  "payment_methods_enabled": [
    {
      "payment_method": "card",
      "payment_method_types": [
        {
          "payment_method_type": "credit",
          "card_networks": [
            "Visa",
            "Mastercard"
          ],
          "minimum_amount": 1,
          "maximum_amount": 68607706,
          "recurring_enabled": true,
          "installment_payment_enabled": true
        },
        {
          "payment_method_type": "debit",
          "card_networks": [
            "Visa",
            "Mastercard"
          ],
          "minimum_amount": 1,
          "maximum_amount": 68607706,
          "recurring_enabled": true,
          "installment_payment_enabled": true
        }
      ]
    },
    {
      "payment_method": "pay_later",
      "payment_method_types": [
        {
          "payment_method_type": "klarna",
          "payment_experience": "redirect_to_url",
          "minimum_amount": 1,
          "maximum_amount": 68607706,
          "recurring_enabled": true,
          "installment_payment_enabled": true
        },
        {
          "payment_method_type": "affirm",
          "payment_experience": "redirect_to_url",
          "minimum_amount": 1,
          "maximum_amount": 68607706,
          "recurring_enabled": true,
          "installment_payment_enabled": true
        },
        {
          "payment_method_type": "afterpay_clearpay",
          "payment_experience": "redirect_to_url",
          "minimum_amount": 1,
          "maximum_amount": 68607706,
          "recurring_enabled": true,
          "installment_payment_enabled": true
        }
      ]
    },

    {
        "payment_method" : "bank_transfer",
        "payment_method_types":[
            {
            "payment_method_type":"sepa",
            "payment_experience": "redirect_to_url",
          "minimum_amount": 1,
          "maximum_amount": 68607706,
          "recurring_enabled": true,
          "installment_payment_enabled": true
            }
        ]
    },
    {
        "payment_method": "bank_redirect",
        "payment_method_types": [
            {
                "payment_method_type": "przelewy24",
                "payment_experience": "redirect_to_url",
                "minimum_amount": 1,
                "maximum_amount": 68607706,
                "recurring_enabled": true,
                "installment_payment_enabled": true

            },
            {
                "payment_method_type": "bancontact_card",
                "payment_experience": "redirect_to_url",
                "minimum_amount": 1,
                "maximum_amount": 68607706,
                "recurring_enabled": true,
                "installment_payment_enabled": true

            },
            {
                "payment_method_type": "eps",
                "payment_experience": "redirect_to_url",
                "minimum_amount": 1,
                "maximum_amount": 68607706,
                "recurring_enabled": true,
                "installment_payment_enabled": true

            }
        ]
    }
  ],
  "metadata": {
    "city": "NY",
    "unit": "245"
  },
  "business_country":  "US",
  "business_label": "default"
}'
```

4. Create a Payment of Przelewy24 via Mollie
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: ____' \
--data-raw '{
  "amount": 6540,
  "currency": "EUR",
  "confirm": true,
  "capture_method": "automatic",
  "capture_on": "2022-09-10T10:11:12Z",
  "amount_to_capture": 6540,
  "customer_id": "StripeCustomer",
  "email": "guest@example.com",
  "name": "John Doe",
  "phone": "999999999",
  "phone_country_code": "+1",
  "description": "Its my first payment request",
  "authentication_type": "no_three_ds",
  "return_url": "https://google.com",
  "payment_method": "bank_redirect",
   "payment_method_type": "przelewy24",
  "payment_method_data": {
    "bank_redirect": {
      "przelewy24": {
      }
    }
  },
  "billing": {
    "address": {
      "line1": "1467",
      "line2": "Harrison Street",
      "line3": "Harrison Street",
      "city": "San Fransico",
      "state": "California",
      "zip": "94122",
      "country": "BE",
      "first_name": "joseph",
      "last_name": "Doe"
    },
    "phone": {
      "number": "8056594427",
      "country_code": "+91"
    }
  },
  "shipping": {
    "address": {
      "line1": "1467",
      "line2": "Harrison Street",
      "line3": "Harrison Street",
      "city": "San Fransico",
      "state": "California",
      "zip": "94122",
      "country": "BE",
      "first_name": "joseph",
      "last_name": "Doe"
    },
    "phone": {
      "number": "8056594427",
      "country_code": "+91"
    }
  },
  "statement_descriptor_name": "joseph",
  "statement_descriptor_suffix": "JS",
  "metadata": {
    "udf1": "value1",
    "new_customer": "true",
    "login_date": "2019-09-10T10:11:12Z"
  },
   "profile_id": "pro_xA9ALBzKrljCM1SCCV26"
}'
```
Response
```
{
    "payment_id": "pay_bEvdBi9AeDtAMvrSZi2J",
    "merchant_id": "merchant_1729160602",
    "status": "requires_customer_action",
    "amount": 6540,
    "net_amount": 6540,
    "amount_capturable": 6540,
    "amount_received": null,
    "connector": "mollie",
    "client_secret": "pay_bEvdBi9AeDtAMvrSZi2J_secret_iv9QnUtPYFZbjeV0P7iW",
    "created": "2024-10-17T10:25:07.604Z",
    "currency": "EUR",
    "customer_id": "StripeCustomer",
    "customer": {
        "id": "StripeCustomer",
        "name": "John Doe",
        "email": "guest@example.com",
        "phone": "999999999",
        "phone_country_code": "+1"
    },
    "description": "Its my first payment request",
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": null,
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "bank_redirect",
    "payment_method_data": {
        "bank_redirect": {
            "type": "BankRedirectResponse",
            "bank_name": null
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": {
        "address": {
            "city": "San Fransico",
            "country": "BE",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": null
    },
    "billing": {
        "address": {
            "city": "San Fransico",
            "country": "BE",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": null
    },
    "order_details": null,
    "email": "guest@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "return_url": "https://google.com/",
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "next_action": {
        "type": "redirect_to_url",
        "redirect_to_url": "http://localhost:8080/payments/redirect/pay_bEvdBi9AeDtAMvrSZi2J/merchant_1729160602/pay_bEvdBi9AeDtAMvrSZi2J_1"
    },
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": "przelewy24",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "StripeCustomer",
        "created_at": 1729160707,
        "expires": 1729164307,
        "secret": "epk_7d82e37938e54484ab6baf8d22109af3"
    },
    "manual_retry_allowed": null,
    "connector_transaction_id": "tr_fZzrHzunjU",
    "frm_message": null,
    "metadata": {
        "udf1": "value1",
        "login_date": "2019-09-10T10:11:12Z",
        "new_customer": "true"
    },
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": "tr_fZzrHzunjU",
    "payment_link": null,
    "profile_id": "pro_xA9ALBzKrljCM1SCCV26",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_WVDHef0DfuinnrZPKggd",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-10-17T10:40:07.604Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2024-10-17T10:25:09.587Z",
    "charges": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": null
}
```

## 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`
- [ ] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible