Repository: juspay/hyperswitch
File: crates/hyperswitch_connectors/src/connectors/aci/transformers.rs (Rust)

Code before:
) -> Option<Instruction> {
    if item.router_data.request.customer_acceptance.is_some()
        && item.router_data.request.setup_future_usage == Some(enums::FutureUsage::OffSession)
    {
        return Some(Instruction {
            mode: InstructionMode::Initial,
            transaction_type: InstructionType::Unscheduled,
            source: InstructionSource::CardholderInitiatedTransaction,
            initial_transaction_id: None,
            create_registration: Some(true),
        });
    } else if item.router_data.request.mandate_id.is_some() {
        let initial_transaction_id = item
            .router_data
            .recurring_mandate_payment_data
            .as_ref()
            .and_then(|mandate_data| mandate_data.mandate_metadata.as_ref())
            .and_then(|metadata| {
                serde_json::from_value::<AciMandateMetadata>(metadata.clone().expose())
                    .ok()
                    .map(|m| m.initial_transaction_id)
            });

        return Some(Instruction {
            mode: InstructionMode::Repeated,
            transaction_type: InstructionType::Unscheduled,
            source: InstructionSource::MerchantInitiatedTransaction,
            initial_transaction_id,
            create_registration: None,
        });
    }
    None
}

fn get_recurring_type(
    item: &AciRouterData<&PaymentsAuthorizeRouterData>,
) -> Option<AciRecurringType> {
    if item.router_data.request.mandate_id.is_some() {
        Some(AciRecurringType::Repeated)
    } else if item.router_data.request.customer_acceptance.is_some()
        && item.router_data.request.setup_future_usage == Some(enums::FutureUsage::OffSession)
    {
        Some(AciRecurringType::Initial)
    } else {
        None
    }
}

impl TryFrom<&PaymentsCancelRouterData> for AciCancelRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &PaymentsCancelRouterData) -> Result<Self, Self::Error> {

Review comment (bug):
We accept a field called `mit_category` in the `/payments` request. It is an enum with the following values:

```rust
pub enum MitCategory {
    /// A fixed purchase amount split into multiple scheduled payments until the total is paid.
    Installment,
    /// Merchant-initiated transaction using stored credentials, but not tied to a fixed schedule.
    Unscheduled,
    /// Merchant-initiated payments that occur at regular intervals, typically for the same amount.
    Recurring,
    /// A retried MIT following a previously failed or declined transaction.
    Resubmission,
}
```

We can read the `mit_category` value from the request payload and map it to the corresponding `transaction_type`. You may refer to `crates/hyperswitch_connectors/src/connectors/checkout/transformers.rs` for an example of how `mit_category` is mapped in the Authorize request.

Code after:
}

fn get_instruction_details(
    item: &AciRouterData<&PaymentsAuthorizeRouterData>,
) -> Option<Instruction> {
    if item.router_data.request.customer_acceptance.is_some()
        && item.router_data.request.setup_future_usage == Some(enums::FutureUsage::OffSession)
    {
        return Some(Instruction {
            mode: InstructionMode::Initial,
            transaction_type: InstructionType::Unscheduled,
            source: InstructionSource::CardholderInitiatedTransaction,
            initial_transaction_id: None,
            create_registration: Some(true),
        });
    } else if item.router_data.request.mandate_id.is_some() {
        let initial_transaction_id = item
            .router_data
            .request
            .get_connector_mandate_request_reference_id()
            .ok();

        let transaction_type = match item.router_data.request.mit_category.as_ref() {
            Some(MitCategory::Installment) => InstructionType::Installment,
            Some(MitCategory::Recurring) => InstructionType::Recurring,
            Some(MitCategory::Unscheduled) | Some(MitCategory::Resubmission) | None => {
                InstructionType::Unscheduled
            }
        };

        return Some(Instruction {
            mode: InstructionMode::Repeated,
            transaction_type,
            source: InstructionSource::MerchantInitiatedTransaction,
            initial_transaction_id,
            create_registration: None,
        });
    }
    None
}

fn get_recurring_type(
    item: &AciRouterData<&PaymentsAuthorizeRouterData>,
) -> Option<AciRecurringType> {
    if item.router_data.request.mandate_id.is_some() {
        Some(AciRecurringType::Repeated)
    } else if item.router_data.request.customer_acceptance.is_some()
        && item.router_data.request.setup_future_usage == Some(enums::FutureUsage::OffSession)
    {
        Some(AciRecurringType::Initial)
    } else {