/*
 * Binance Crypto Loan REST API
 *
 * OpenAPI Specification for the Binance Crypto Loan REST API
 *
 * The version of the OpenAPI document: 1.0.0
 *
 *
 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
 * https://openapi-generator.tech
 * Do not edit the class manually.
 */

#![allow(unused_imports)]
use async_trait::async_trait;
use derive_builder::Builder;
use reqwest;
use rust_decimal::prelude::*;
use serde::{Deserialize, Serialize};
use serde_json::{Value, json};
use std::collections::BTreeMap;

use crate::common::{
    config::ConfigurationRestApi,
    models::{ParamBuildError, RestApiResponse},
    utils::send_request,
};
use crate::crypto_loan::rest_api::models;

const HAS_TIME_UNIT: bool = false;

#[async_trait]
pub trait FlexibleRateApi: Send + Sync {
    async fn check_collateral_repay_rate(
        &self,
        params: CheckCollateralRepayRateParams,
    ) -> anyhow::Result<RestApiResponse<models::CheckCollateralRepayRateResponse>>;
    async fn flexible_loan_adjust_ltv(
        &self,
        params: FlexibleLoanAdjustLtvParams,
    ) -> anyhow::Result<RestApiResponse<models::FlexibleLoanAdjustLtvResponse>>;
    async fn flexible_loan_borrow(
        &self,
        params: FlexibleLoanBorrowParams,
    ) -> anyhow::Result<RestApiResponse<models::FlexibleLoanBorrowResponse>>;
    async fn flexible_loan_repay(
        &self,
        params: FlexibleLoanRepayParams,
    ) -> anyhow::Result<RestApiResponse<models::FlexibleLoanRepayResponse>>;
    async fn get_flexible_loan_assets_data(
        &self,
        params: GetFlexibleLoanAssetsDataParams,
    ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanAssetsDataResponse>>;
    async fn get_flexible_loan_borrow_history(
        &self,
        params: GetFlexibleLoanBorrowHistoryParams,
    ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanBorrowHistoryResponse>>;
    async fn get_flexible_loan_collateral_assets_data(
        &self,
        params: GetFlexibleLoanCollateralAssetsDataParams,
    ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanCollateralAssetsDataResponse>>;
    async fn get_flexible_loan_interest_rate_history(
        &self,
        params: GetFlexibleLoanInterestRateHistoryParams,
    ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanInterestRateHistoryResponse>>;
    async fn get_flexible_loan_liquidation_history(
        &self,
        params: GetFlexibleLoanLiquidationHistoryParams,
    ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanLiquidationHistoryResponse>>;
    async fn get_flexible_loan_ltv_adjustment_history(
        &self,
        params: GetFlexibleLoanLtvAdjustmentHistoryParams,
    ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanLtvAdjustmentHistoryResponse>>;
    async fn get_flexible_loan_ongoing_orders(
        &self,
        params: GetFlexibleLoanOngoingOrdersParams,
    ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanOngoingOrdersResponse>>;
    async fn get_flexible_loan_repayment_history(
        &self,
        params: GetFlexibleLoanRepaymentHistoryParams,
    ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanRepaymentHistoryResponse>>;
}

#[derive(Debug, Clone)]
pub struct FlexibleRateApiClient {
    configuration: ConfigurationRestApi,
}

impl FlexibleRateApiClient {
    pub fn new(configuration: ConfigurationRestApi) -> Self {
        Self { configuration }
    }
}

/// Request parameters for the [`check_collateral_repay_rate`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`check_collateral_repay_rate`](#method.check_collateral_repay_rate).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct CheckCollateralRepayRateParams {
    ///
    /// The `loan_coin` parameter.
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub loan_coin: String,
    ///
    /// The `collateral_coin` parameter.
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub collateral_coin: String,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl CheckCollateralRepayRateParams {
    /// Create a builder for [`check_collateral_repay_rate`].
    ///
    /// Required parameters:
    ///
    /// * `loan_coin` — String
    /// * `collateral_coin` — String
    ///
    #[must_use]
    pub fn builder(
        loan_coin: String,
        collateral_coin: String,
    ) -> CheckCollateralRepayRateParamsBuilder {
        CheckCollateralRepayRateParamsBuilder::default()
            .loan_coin(loan_coin)
            .collateral_coin(collateral_coin)
    }
}
/// Request parameters for the [`flexible_loan_adjust_ltv`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`flexible_loan_adjust_ltv`](#method.flexible_loan_adjust_ltv).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct FlexibleLoanAdjustLtvParams {
    ///
    /// The `loan_coin` parameter.
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub loan_coin: String,
    ///
    /// The `collateral_coin` parameter.
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub collateral_coin: String,
    ///
    /// The `adjustment_amount` parameter.
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub adjustment_amount: rust_decimal::Decimal,
    /// "ADDITIONAL", "REDUCED"
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub direction: String,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl FlexibleLoanAdjustLtvParams {
    /// Create a builder for [`flexible_loan_adjust_ltv`].
    ///
    /// Required parameters:
    ///
    /// * `loan_coin` — String
    /// * `collateral_coin` — String
    /// * `adjustment_amount` — `rust_decimal::Decimal`
    /// * `direction` — \"ADDITIONAL\", \"REDUCED\"
    ///
    #[must_use]
    pub fn builder(
        loan_coin: String,
        collateral_coin: String,
        adjustment_amount: rust_decimal::Decimal,
        direction: String,
    ) -> FlexibleLoanAdjustLtvParamsBuilder {
        FlexibleLoanAdjustLtvParamsBuilder::default()
            .loan_coin(loan_coin)
            .collateral_coin(collateral_coin)
            .adjustment_amount(adjustment_amount)
            .direction(direction)
    }
}
/// Request parameters for the [`flexible_loan_borrow`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`flexible_loan_borrow`](#method.flexible_loan_borrow).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct FlexibleLoanBorrowParams {
    ///
    /// The `loan_coin` parameter.
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub loan_coin: String,
    ///
    /// The `collateral_coin` parameter.
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub collateral_coin: String,
    /// Mandatory when collateralAmount is empty
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub loan_amount: Option<rust_decimal::Decimal>,
    /// Mandatory when loanAmount is empty
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub collateral_amount: Option<rust_decimal::Decimal>,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl FlexibleLoanBorrowParams {
    /// Create a builder for [`flexible_loan_borrow`].
    ///
    /// Required parameters:
    ///
    /// * `loan_coin` — String
    /// * `collateral_coin` — String
    ///
    #[must_use]
    pub fn builder(loan_coin: String, collateral_coin: String) -> FlexibleLoanBorrowParamsBuilder {
        FlexibleLoanBorrowParamsBuilder::default()
            .loan_coin(loan_coin)
            .collateral_coin(collateral_coin)
    }
}
/// Request parameters for the [`flexible_loan_repay`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`flexible_loan_repay`](#method.flexible_loan_repay).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct FlexibleLoanRepayParams {
    ///
    /// The `loan_coin` parameter.
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub loan_coin: String,
    ///
    /// The `collateral_coin` parameter.
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub collateral_coin: String,
    /// repay amount of loanCoin
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub repay_amount: rust_decimal::Decimal,
    /// Default: TRUE. TRUE: Return extra collateral to spot account; FALSE: Keep extra collateral in the order, and lower LTV.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub collateral_return: Option<bool>,
    /// Default: FALSE. TRUE: Full repayment; FALSE: Partial repayment, based on loanAmount
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub full_repayment: Option<bool>,
    /// Default: 1. 1: Repayment with loan asset; 2: Repayment with collateral
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub repayment_type: Option<i64>,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl FlexibleLoanRepayParams {
    /// Create a builder for [`flexible_loan_repay`].
    ///
    /// Required parameters:
    ///
    /// * `loan_coin` — String
    /// * `collateral_coin` — String
    /// * `repay_amount` — repay amount of loanCoin
    ///
    #[must_use]
    pub fn builder(
        loan_coin: String,
        collateral_coin: String,
        repay_amount: rust_decimal::Decimal,
    ) -> FlexibleLoanRepayParamsBuilder {
        FlexibleLoanRepayParamsBuilder::default()
            .loan_coin(loan_coin)
            .collateral_coin(collateral_coin)
            .repay_amount(repay_amount)
    }
}
/// Request parameters for the [`get_flexible_loan_assets_data`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`get_flexible_loan_assets_data`](#method.get_flexible_loan_assets_data).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct GetFlexibleLoanAssetsDataParams {
    ///
    /// The `loan_coin` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub loan_coin: Option<String>,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl GetFlexibleLoanAssetsDataParams {
    /// Create a builder for [`get_flexible_loan_assets_data`].
    ///
    #[must_use]
    pub fn builder() -> GetFlexibleLoanAssetsDataParamsBuilder {
        GetFlexibleLoanAssetsDataParamsBuilder::default()
    }
}
/// Request parameters for the [`get_flexible_loan_borrow_history`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`get_flexible_loan_borrow_history`](#method.get_flexible_loan_borrow_history).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct GetFlexibleLoanBorrowHistoryParams {
    ///
    /// The `loan_coin` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub loan_coin: Option<String>,
    ///
    /// The `collateral_coin` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub collateral_coin: Option<String>,
    ///
    /// The `start_time` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub start_time: Option<i64>,
    ///
    /// The `end_time` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub end_time: Option<i64>,
    /// Current querying page. Start from 1; default: 1; max: 1000
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub current: Option<i64>,
    /// Default: 10; max: 100
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub limit: Option<i64>,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl GetFlexibleLoanBorrowHistoryParams {
    /// Create a builder for [`get_flexible_loan_borrow_history`].
    ///
    #[must_use]
    pub fn builder() -> GetFlexibleLoanBorrowHistoryParamsBuilder {
        GetFlexibleLoanBorrowHistoryParamsBuilder::default()
    }
}
/// Request parameters for the [`get_flexible_loan_collateral_assets_data`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`get_flexible_loan_collateral_assets_data`](#method.get_flexible_loan_collateral_assets_data).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct GetFlexibleLoanCollateralAssetsDataParams {
    ///
    /// The `collateral_coin` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub collateral_coin: Option<String>,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl GetFlexibleLoanCollateralAssetsDataParams {
    /// Create a builder for [`get_flexible_loan_collateral_assets_data`].
    ///
    #[must_use]
    pub fn builder() -> GetFlexibleLoanCollateralAssetsDataParamsBuilder {
        GetFlexibleLoanCollateralAssetsDataParamsBuilder::default()
    }
}
/// Request parameters for the [`get_flexible_loan_interest_rate_history`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`get_flexible_loan_interest_rate_history`](#method.get_flexible_loan_interest_rate_history).
#[derive(Clone, Debug, Builder)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct GetFlexibleLoanInterestRateHistoryParams {
    ///
    /// The `coin` parameter.
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub coin: String,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **required.
    #[builder(setter(into))]
    pub recv_window: i64,
    ///
    /// The `start_time` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub start_time: Option<i64>,
    ///
    /// The `end_time` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub end_time: Option<i64>,
    /// Current querying page. Start from 1; default: 1; max: 1000
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub current: Option<i64>,
    /// Default: 10; max: 100
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub limit: Option<i64>,
}

impl GetFlexibleLoanInterestRateHistoryParams {
    /// Create a builder for [`get_flexible_loan_interest_rate_history`].
    ///
    /// Required parameters:
    ///
    /// * `coin` — String
    /// * `recv_window` — i64
    ///
    #[must_use]
    pub fn builder(
        coin: String,
        recv_window: i64,
    ) -> GetFlexibleLoanInterestRateHistoryParamsBuilder {
        GetFlexibleLoanInterestRateHistoryParamsBuilder::default()
            .coin(coin)
            .recv_window(recv_window)
    }
}
/// Request parameters for the [`get_flexible_loan_liquidation_history`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`get_flexible_loan_liquidation_history`](#method.get_flexible_loan_liquidation_history).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct GetFlexibleLoanLiquidationHistoryParams {
    ///
    /// The `loan_coin` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub loan_coin: Option<String>,
    ///
    /// The `collateral_coin` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub collateral_coin: Option<String>,
    ///
    /// The `start_time` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub start_time: Option<i64>,
    ///
    /// The `end_time` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub end_time: Option<i64>,
    /// Current querying page. Start from 1; default: 1; max: 1000
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub current: Option<i64>,
    /// Default: 10; max: 100
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub limit: Option<i64>,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl GetFlexibleLoanLiquidationHistoryParams {
    /// Create a builder for [`get_flexible_loan_liquidation_history`].
    ///
    #[must_use]
    pub fn builder() -> GetFlexibleLoanLiquidationHistoryParamsBuilder {
        GetFlexibleLoanLiquidationHistoryParamsBuilder::default()
    }
}
/// Request parameters for the [`get_flexible_loan_ltv_adjustment_history`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`get_flexible_loan_ltv_adjustment_history`](#method.get_flexible_loan_ltv_adjustment_history).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct GetFlexibleLoanLtvAdjustmentHistoryParams {
    ///
    /// The `loan_coin` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub loan_coin: Option<String>,
    ///
    /// The `collateral_coin` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub collateral_coin: Option<String>,
    ///
    /// The `start_time` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub start_time: Option<i64>,
    ///
    /// The `end_time` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub end_time: Option<i64>,
    /// Current querying page. Start from 1; default: 1; max: 1000
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub current: Option<i64>,
    /// Default: 10; max: 100
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub limit: Option<i64>,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl GetFlexibleLoanLtvAdjustmentHistoryParams {
    /// Create a builder for [`get_flexible_loan_ltv_adjustment_history`].
    ///
    #[must_use]
    pub fn builder() -> GetFlexibleLoanLtvAdjustmentHistoryParamsBuilder {
        GetFlexibleLoanLtvAdjustmentHistoryParamsBuilder::default()
    }
}
/// Request parameters for the [`get_flexible_loan_ongoing_orders`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`get_flexible_loan_ongoing_orders`](#method.get_flexible_loan_ongoing_orders).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct GetFlexibleLoanOngoingOrdersParams {
    ///
    /// The `loan_coin` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub loan_coin: Option<String>,
    ///
    /// The `collateral_coin` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub collateral_coin: Option<String>,
    /// Current querying page. Start from 1; default: 1; max: 1000
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub current: Option<i64>,
    /// Default: 10; max: 100
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub limit: Option<i64>,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl GetFlexibleLoanOngoingOrdersParams {
    /// Create a builder for [`get_flexible_loan_ongoing_orders`].
    ///
    #[must_use]
    pub fn builder() -> GetFlexibleLoanOngoingOrdersParamsBuilder {
        GetFlexibleLoanOngoingOrdersParamsBuilder::default()
    }
}
/// Request parameters for the [`get_flexible_loan_repayment_history`] operation.
///
/// This struct holds all of the inputs you can pass when calling
/// [`get_flexible_loan_repayment_history`](#method.get_flexible_loan_repayment_history).
#[derive(Clone, Debug, Builder, Default)]
#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
pub struct GetFlexibleLoanRepaymentHistoryParams {
    ///
    /// The `loan_coin` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub loan_coin: Option<String>,
    ///
    /// The `collateral_coin` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub collateral_coin: Option<String>,
    ///
    /// The `start_time` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub start_time: Option<i64>,
    ///
    /// The `end_time` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub end_time: Option<i64>,
    /// Current querying page. Start from 1; default: 1; max: 1000
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub current: Option<i64>,
    /// Default: 10; max: 100
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub limit: Option<i64>,
    ///
    /// The `recv_window` parameter.
    ///
    /// This field is **optional.
    #[builder(setter(into), default)]
    pub recv_window: Option<i64>,
}

impl GetFlexibleLoanRepaymentHistoryParams {
    /// Create a builder for [`get_flexible_loan_repayment_history`].
    ///
    #[must_use]
    pub fn builder() -> GetFlexibleLoanRepaymentHistoryParamsBuilder {
        GetFlexibleLoanRepaymentHistoryParamsBuilder::default()
    }
}

#[async_trait]
impl FlexibleRateApi for FlexibleRateApiClient {
    async fn check_collateral_repay_rate(
        &self,
        params: CheckCollateralRepayRateParams,
    ) -> anyhow::Result<RestApiResponse<models::CheckCollateralRepayRateResponse>> {
        let CheckCollateralRepayRateParams {
            loan_coin,
            collateral_coin,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        query_params.insert("loanCoin".to_string(), json!(loan_coin));

        query_params.insert("collateralCoin".to_string(), json!(collateral_coin));

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<models::CheckCollateralRepayRateResponse>(
            &self.configuration,
            "/sapi/v2/loan/flexible/repay/rate",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn flexible_loan_adjust_ltv(
        &self,
        params: FlexibleLoanAdjustLtvParams,
    ) -> anyhow::Result<RestApiResponse<models::FlexibleLoanAdjustLtvResponse>> {
        let FlexibleLoanAdjustLtvParams {
            loan_coin,
            collateral_coin,
            adjustment_amount,
            direction,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        query_params.insert("loanCoin".to_string(), json!(loan_coin));

        query_params.insert("collateralCoin".to_string(), json!(collateral_coin));

        query_params.insert("adjustmentAmount".to_string(), json!(adjustment_amount));

        query_params.insert("direction".to_string(), json!(direction));

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<models::FlexibleLoanAdjustLtvResponse>(
            &self.configuration,
            "/sapi/v2/loan/flexible/adjust/ltv",
            reqwest::Method::POST,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn flexible_loan_borrow(
        &self,
        params: FlexibleLoanBorrowParams,
    ) -> anyhow::Result<RestApiResponse<models::FlexibleLoanBorrowResponse>> {
        let FlexibleLoanBorrowParams {
            loan_coin,
            collateral_coin,
            loan_amount,
            collateral_amount,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        query_params.insert("loanCoin".to_string(), json!(loan_coin));

        if let Some(rw) = loan_amount {
            query_params.insert("loanAmount".to_string(), json!(rw));
        }

        query_params.insert("collateralCoin".to_string(), json!(collateral_coin));

        if let Some(rw) = collateral_amount {
            query_params.insert("collateralAmount".to_string(), json!(rw));
        }

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<models::FlexibleLoanBorrowResponse>(
            &self.configuration,
            "/sapi/v2/loan/flexible/borrow",
            reqwest::Method::POST,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn flexible_loan_repay(
        &self,
        params: FlexibleLoanRepayParams,
    ) -> anyhow::Result<RestApiResponse<models::FlexibleLoanRepayResponse>> {
        let FlexibleLoanRepayParams {
            loan_coin,
            collateral_coin,
            repay_amount,
            collateral_return,
            full_repayment,
            repayment_type,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        query_params.insert("loanCoin".to_string(), json!(loan_coin));

        query_params.insert("collateralCoin".to_string(), json!(collateral_coin));

        query_params.insert("repayAmount".to_string(), json!(repay_amount));

        if let Some(rw) = collateral_return {
            query_params.insert("collateralReturn".to_string(), json!(rw));
        }

        if let Some(rw) = full_repayment {
            query_params.insert("fullRepayment".to_string(), json!(rw));
        }

        if let Some(rw) = repayment_type {
            query_params.insert("repaymentType".to_string(), json!(rw));
        }

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<models::FlexibleLoanRepayResponse>(
            &self.configuration,
            "/sapi/v2/loan/flexible/repay",
            reqwest::Method::POST,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn get_flexible_loan_assets_data(
        &self,
        params: GetFlexibleLoanAssetsDataParams,
    ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanAssetsDataResponse>> {
        let GetFlexibleLoanAssetsDataParams {
            loan_coin,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        if let Some(rw) = loan_coin {
            query_params.insert("loanCoin".to_string(), json!(rw));
        }

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<models::GetFlexibleLoanAssetsDataResponse>(
            &self.configuration,
            "/sapi/v2/loan/flexible/loanable/data",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn get_flexible_loan_borrow_history(
        &self,
        params: GetFlexibleLoanBorrowHistoryParams,
    ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanBorrowHistoryResponse>> {
        let GetFlexibleLoanBorrowHistoryParams {
            loan_coin,
            collateral_coin,
            start_time,
            end_time,
            current,
            limit,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        if let Some(rw) = loan_coin {
            query_params.insert("loanCoin".to_string(), json!(rw));
        }

        if let Some(rw) = collateral_coin {
            query_params.insert("collateralCoin".to_string(), json!(rw));
        }

        if let Some(rw) = start_time {
            query_params.insert("startTime".to_string(), json!(rw));
        }

        if let Some(rw) = end_time {
            query_params.insert("endTime".to_string(), json!(rw));
        }

        if let Some(rw) = current {
            query_params.insert("current".to_string(), json!(rw));
        }

        if let Some(rw) = limit {
            query_params.insert("limit".to_string(), json!(rw));
        }

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<models::GetFlexibleLoanBorrowHistoryResponse>(
            &self.configuration,
            "/sapi/v2/loan/flexible/borrow/history",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn get_flexible_loan_collateral_assets_data(
        &self,
        params: GetFlexibleLoanCollateralAssetsDataParams,
    ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanCollateralAssetsDataResponse>> {
        let GetFlexibleLoanCollateralAssetsDataParams {
            collateral_coin,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        if let Some(rw) = collateral_coin {
            query_params.insert("collateralCoin".to_string(), json!(rw));
        }

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<models::GetFlexibleLoanCollateralAssetsDataResponse>(
            &self.configuration,
            "/sapi/v2/loan/flexible/collateral/data",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn get_flexible_loan_interest_rate_history(
        &self,
        params: GetFlexibleLoanInterestRateHistoryParams,
    ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanInterestRateHistoryResponse>> {
        let GetFlexibleLoanInterestRateHistoryParams {
            coin,
            recv_window,
            start_time,
            end_time,
            current,
            limit,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        query_params.insert("coin".to_string(), json!(coin));

        if let Some(rw) = start_time {
            query_params.insert("startTime".to_string(), json!(rw));
        }

        if let Some(rw) = end_time {
            query_params.insert("endTime".to_string(), json!(rw));
        }

        if let Some(rw) = current {
            query_params.insert("current".to_string(), json!(rw));
        }

        if let Some(rw) = limit {
            query_params.insert("limit".to_string(), json!(rw));
        }

        query_params.insert("recvWindow".to_string(), json!(recv_window));

        send_request::<models::GetFlexibleLoanInterestRateHistoryResponse>(
            &self.configuration,
            "/sapi/v2/loan/interestRateHistory",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn get_flexible_loan_liquidation_history(
        &self,
        params: GetFlexibleLoanLiquidationHistoryParams,
    ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanLiquidationHistoryResponse>> {
        let GetFlexibleLoanLiquidationHistoryParams {
            loan_coin,
            collateral_coin,
            start_time,
            end_time,
            current,
            limit,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        if let Some(rw) = loan_coin {
            query_params.insert("loanCoin".to_string(), json!(rw));
        }

        if let Some(rw) = collateral_coin {
            query_params.insert("collateralCoin".to_string(), json!(rw));
        }

        if let Some(rw) = start_time {
            query_params.insert("startTime".to_string(), json!(rw));
        }

        if let Some(rw) = end_time {
            query_params.insert("endTime".to_string(), json!(rw));
        }

        if let Some(rw) = current {
            query_params.insert("current".to_string(), json!(rw));
        }

        if let Some(rw) = limit {
            query_params.insert("limit".to_string(), json!(rw));
        }

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<models::GetFlexibleLoanLiquidationHistoryResponse>(
            &self.configuration,
            "/sapi/v2/loan/flexible/liquidation/history",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn get_flexible_loan_ltv_adjustment_history(
        &self,
        params: GetFlexibleLoanLtvAdjustmentHistoryParams,
    ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanLtvAdjustmentHistoryResponse>> {
        let GetFlexibleLoanLtvAdjustmentHistoryParams {
            loan_coin,
            collateral_coin,
            start_time,
            end_time,
            current,
            limit,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        if let Some(rw) = loan_coin {
            query_params.insert("loanCoin".to_string(), json!(rw));
        }

        if let Some(rw) = collateral_coin {
            query_params.insert("collateralCoin".to_string(), json!(rw));
        }

        if let Some(rw) = start_time {
            query_params.insert("startTime".to_string(), json!(rw));
        }

        if let Some(rw) = end_time {
            query_params.insert("endTime".to_string(), json!(rw));
        }

        if let Some(rw) = current {
            query_params.insert("current".to_string(), json!(rw));
        }

        if let Some(rw) = limit {
            query_params.insert("limit".to_string(), json!(rw));
        }

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<models::GetFlexibleLoanLtvAdjustmentHistoryResponse>(
            &self.configuration,
            "/sapi/v2/loan/flexible/ltv/adjustment/history",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn get_flexible_loan_ongoing_orders(
        &self,
        params: GetFlexibleLoanOngoingOrdersParams,
    ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanOngoingOrdersResponse>> {
        let GetFlexibleLoanOngoingOrdersParams {
            loan_coin,
            collateral_coin,
            current,
            limit,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        if let Some(rw) = loan_coin {
            query_params.insert("loanCoin".to_string(), json!(rw));
        }

        if let Some(rw) = collateral_coin {
            query_params.insert("collateralCoin".to_string(), json!(rw));
        }

        if let Some(rw) = current {
            query_params.insert("current".to_string(), json!(rw));
        }

        if let Some(rw) = limit {
            query_params.insert("limit".to_string(), json!(rw));
        }

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<models::GetFlexibleLoanOngoingOrdersResponse>(
            &self.configuration,
            "/sapi/v2/loan/flexible/ongoing/orders",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }

    async fn get_flexible_loan_repayment_history(
        &self,
        params: GetFlexibleLoanRepaymentHistoryParams,
    ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanRepaymentHistoryResponse>> {
        let GetFlexibleLoanRepaymentHistoryParams {
            loan_coin,
            collateral_coin,
            start_time,
            end_time,
            current,
            limit,
            recv_window,
        } = params;

        let mut query_params = BTreeMap::new();
        let body_params = BTreeMap::new();

        if let Some(rw) = loan_coin {
            query_params.insert("loanCoin".to_string(), json!(rw));
        }

        if let Some(rw) = collateral_coin {
            query_params.insert("collateralCoin".to_string(), json!(rw));
        }

        if let Some(rw) = start_time {
            query_params.insert("startTime".to_string(), json!(rw));
        }

        if let Some(rw) = end_time {
            query_params.insert("endTime".to_string(), json!(rw));
        }

        if let Some(rw) = current {
            query_params.insert("current".to_string(), json!(rw));
        }

        if let Some(rw) = limit {
            query_params.insert("limit".to_string(), json!(rw));
        }

        if let Some(rw) = recv_window {
            query_params.insert("recvWindow".to_string(), json!(rw));
        }

        send_request::<models::GetFlexibleLoanRepaymentHistoryResponse>(
            &self.configuration,
            "/sapi/v2/loan/flexible/repay/history",
            reqwest::Method::GET,
            query_params,
            body_params,
            if HAS_TIME_UNIT {
                self.configuration.time_unit
            } else {
                None
            },
            true,
        )
        .await
    }
}

#[cfg(all(test, feature = "crypto_loan"))]
mod tests {
    use super::*;
    use crate::TOKIO_SHARED_RT;
    use crate::{errors::ConnectorError, models::DataFuture, models::RestApiRateLimit};
    use async_trait::async_trait;
    use std::collections::HashMap;

    struct DummyRestApiResponse<T> {
        inner: Box<dyn FnOnce() -> DataFuture<Result<T, ConnectorError>> + Send + Sync>,
        status: u16,
        headers: HashMap<String, String>,
        rate_limits: Option<Vec<RestApiRateLimit>>,
    }

    impl<T> From<DummyRestApiResponse<T>> for RestApiResponse<T> {
        fn from(dummy: DummyRestApiResponse<T>) -> Self {
            Self {
                data_fn: dummy.inner,
                status: dummy.status,
                headers: dummy.headers,
                rate_limits: dummy.rate_limits,
            }
        }
    }

    struct MockFlexibleRateApiClient {
        force_error: bool,
    }

    #[async_trait]
    impl FlexibleRateApi for MockFlexibleRateApiClient {
        async fn check_collateral_repay_rate(
            &self,
            _params: CheckCollateralRepayRateParams,
        ) -> anyhow::Result<RestApiResponse<models::CheckCollateralRepayRateResponse>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(
                r#"{"loanCoin":"BUSD","collateralCoin":"BNB","rate":"300.36781234"}"#,
            )
            .unwrap();
            let dummy_response: models::CheckCollateralRepayRateResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::CheckCollateralRepayRateResponse");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn flexible_loan_adjust_ltv(
            &self,
            _params: FlexibleLoanAdjustLtvParams,
        ) -> anyhow::Result<RestApiResponse<models::FlexibleLoanAdjustLtvResponse>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"loanCoin":"BUSD","collateralCoin":"BNB","direction":"ADDITIONAL","adjustmentAmount":"5.235","currentLTV":"0.52","status":"Succeeds"}"#).unwrap();
            let dummy_response: models::FlexibleLoanAdjustLtvResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::FlexibleLoanAdjustLtvResponse");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn flexible_loan_borrow(
            &self,
            _params: FlexibleLoanBorrowParams,
        ) -> anyhow::Result<RestApiResponse<models::FlexibleLoanBorrowResponse>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"loanCoin":"BUSD","loanAmount":"100.5","collateralCoin":"BNB","collateralAmount":"50.5","status":"Succeeds"}"#).unwrap();
            let dummy_response: models::FlexibleLoanBorrowResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::FlexibleLoanBorrowResponse");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn flexible_loan_repay(
            &self,
            _params: FlexibleLoanRepayParams,
        ) -> anyhow::Result<RestApiResponse<models::FlexibleLoanRepayResponse>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"loanCoin":"BUSD","collateralCoin":"BNB","remainingDebt":"100.5","remainingCollateral":"5.253","fullRepayment":false,"currentLTV":"0.25","repayStatus":"REPAID"}"#).unwrap();
            let dummy_response: models::FlexibleLoanRepayResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::FlexibleLoanRepayResponse");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn get_flexible_loan_assets_data(
            &self,
            _params: GetFlexibleLoanAssetsDataParams,
        ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanAssetsDataResponse>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","flexibleInterestRate":"0.00000491","flexibleMinLimit":"100","flexibleMaxLimit":"1000000"}],"total":1}"#).unwrap();
            let dummy_response: models::GetFlexibleLoanAssetsDataResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::GetFlexibleLoanAssetsDataResponse");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn get_flexible_loan_borrow_history(
            &self,
            _params: GetFlexibleLoanBorrowHistoryParams,
        ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanBorrowHistoryResponse>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","initialLoanAmount":"10000","collateralCoin":"BNB","initialCollateralAmount":"49.27565492","borrowTime":1575018510000,"status":"SUCCESS"}],"total":1}"#).unwrap();
            let dummy_response: models::GetFlexibleLoanBorrowHistoryResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::GetFlexibleLoanBorrowHistoryResponse");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn get_flexible_loan_collateral_assets_data(
            &self,
            _params: GetFlexibleLoanCollateralAssetsDataParams,
        ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanCollateralAssetsDataResponse>>
        {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"collateralCoin":"BNB","initialLTV":"0.65","marginCallLTV":"0.75","liquidationLTV":"0.83","maxLimit":"1000000"}],"total":1}"#).unwrap();
            let dummy_response: models::GetFlexibleLoanCollateralAssetsDataResponse =
                serde_json::from_value(resp_json.clone()).expect(
                    "should parse into models::GetFlexibleLoanCollateralAssetsDataResponse",
                );

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn get_flexible_loan_interest_rate_history(
            &self,
            _params: GetFlexibleLoanInterestRateHistoryParams,
        ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanInterestRateHistoryResponse>>
        {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"coin":"USDT","annualizedInterestRate":"0.0647","time":1575018510000},{"coin":"USDT","annualizedInterestRate":"0.0647","time":1575018510000}],"total":2}"#).unwrap();
            let dummy_response: models::GetFlexibleLoanInterestRateHistoryResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::GetFlexibleLoanInterestRateHistoryResponse");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn get_flexible_loan_liquidation_history(
            &self,
            _params: GetFlexibleLoanLiquidationHistoryParams,
        ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanLiquidationHistoryResponse>>
        {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","liquidationDebt":"10000","collateralCoin":"BNB","liquidationCollateralAmount":"123","returnCollateralAmount":"0.2","liquidationFee":"1.2","liquidationStartingPrice":"49.27565492","liquidationStartingTime":1575018510000,"status":"Liquidated"}],"total":1}"#).unwrap();
            let dummy_response: models::GetFlexibleLoanLiquidationHistoryResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::GetFlexibleLoanLiquidationHistoryResponse");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn get_flexible_loan_ltv_adjustment_history(
            &self,
            _params: GetFlexibleLoanLtvAdjustmentHistoryParams,
        ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanLtvAdjustmentHistoryResponse>>
        {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","collateralCoin":"BNB","direction":"ADDITIONAL","collateralAmount":"5.235","preLTV":"0.78","afterLTV":"0.56","adjustTime":1575018510000}],"total":1}"#).unwrap();
            let dummy_response: models::GetFlexibleLoanLtvAdjustmentHistoryResponse =
                serde_json::from_value(resp_json.clone()).expect(
                    "should parse into models::GetFlexibleLoanLtvAdjustmentHistoryResponse",
                );

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn get_flexible_loan_ongoing_orders(
            &self,
            _params: GetFlexibleLoanOngoingOrdersParams,
        ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanOngoingOrdersResponse>> {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","totalDebt":"10000","collateralCoin":"BNB","collateralAmount":"49.27565492","currentLTV":"0.57"}],"total":1}"#).unwrap();
            let dummy_response: models::GetFlexibleLoanOngoingOrdersResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::GetFlexibleLoanOngoingOrdersResponse");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }

        async fn get_flexible_loan_repayment_history(
            &self,
            _params: GetFlexibleLoanRepaymentHistoryParams,
        ) -> anyhow::Result<RestApiResponse<models::GetFlexibleLoanRepaymentHistoryResponse>>
        {
            if self.force_error {
                return Err(ConnectorError::ConnectorClientError {
                    msg: "ResponseError".to_string(),
                    code: None,
                }
                .into());
            }

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","repayAmount":"10000","collateralCoin":"BNB","collateralReturn":"49.27565492","repayStatus":"REPAID","repayTime":1575018510000}],"total":1}"#).unwrap();
            let dummy_response: models::GetFlexibleLoanRepaymentHistoryResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::GetFlexibleLoanRepaymentHistoryResponse");

            let dummy = DummyRestApiResponse {
                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
                status: 200,
                headers: HashMap::new(),
                rate_limits: None,
            };

            Ok(dummy.into())
        }
    }

    #[test]
    fn check_collateral_repay_rate_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = CheckCollateralRepayRateParams::builder(
                "loan_coin_example".to_string(),
                "collateral_coin_example".to_string(),
            )
            .build()
            .unwrap();

            let resp_json: Value = serde_json::from_str(
                r#"{"loanCoin":"BUSD","collateralCoin":"BNB","rate":"300.36781234"}"#,
            )
            .unwrap();
            let expected_response: models::CheckCollateralRepayRateResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::CheckCollateralRepayRateResponse");

            let resp = client
                .check_collateral_repay_rate(params)
                .await
                .expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn check_collateral_repay_rate_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = CheckCollateralRepayRateParams::builder(
                "loan_coin_example".to_string(),
                "collateral_coin_example".to_string(),
            )
            .recv_window(5000)
            .build()
            .unwrap();

            let resp_json: Value = serde_json::from_str(
                r#"{"loanCoin":"BUSD","collateralCoin":"BNB","rate":"300.36781234"}"#,
            )
            .unwrap();
            let expected_response: models::CheckCollateralRepayRateResponse =
                serde_json::from_value(resp_json.clone())
                    .expect("should parse into models::CheckCollateralRepayRateResponse");

            let resp = client
                .check_collateral_repay_rate(params)
                .await
                .expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn check_collateral_repay_rate_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: true };

            let params = CheckCollateralRepayRateParams::builder(
                "loan_coin_example".to_string(),
                "collateral_coin_example".to_string(),
            )
            .build()
            .unwrap();

            match client.check_collateral_repay_rate(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn flexible_loan_adjust_ltv_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = FlexibleLoanAdjustLtvParams::builder("loan_coin_example".to_string(),"collateral_coin_example".to_string(),dec!(1.0),"direction_example".to_string(),).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"loanCoin":"BUSD","collateralCoin":"BNB","direction":"ADDITIONAL","adjustmentAmount":"5.235","currentLTV":"0.52","status":"Succeeds"}"#).unwrap();
            let expected_response : models::FlexibleLoanAdjustLtvResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::FlexibleLoanAdjustLtvResponse");

            let resp = client.flexible_loan_adjust_ltv(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn flexible_loan_adjust_ltv_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = FlexibleLoanAdjustLtvParams::builder("loan_coin_example".to_string(),"collateral_coin_example".to_string(),dec!(1.0),"direction_example".to_string(),).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"loanCoin":"BUSD","collateralCoin":"BNB","direction":"ADDITIONAL","adjustmentAmount":"5.235","currentLTV":"0.52","status":"Succeeds"}"#).unwrap();
            let expected_response : models::FlexibleLoanAdjustLtvResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::FlexibleLoanAdjustLtvResponse");

            let resp = client.flexible_loan_adjust_ltv(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn flexible_loan_adjust_ltv_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: true };

            let params = FlexibleLoanAdjustLtvParams::builder(
                "loan_coin_example".to_string(),
                "collateral_coin_example".to_string(),
                dec!(1.0),
                "direction_example".to_string(),
            )
            .build()
            .unwrap();

            match client.flexible_loan_adjust_ltv(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn flexible_loan_borrow_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = FlexibleLoanBorrowParams::builder("loan_coin_example".to_string(),"collateral_coin_example".to_string(),).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"loanCoin":"BUSD","loanAmount":"100.5","collateralCoin":"BNB","collateralAmount":"50.5","status":"Succeeds"}"#).unwrap();
            let expected_response : models::FlexibleLoanBorrowResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::FlexibleLoanBorrowResponse");

            let resp = client.flexible_loan_borrow(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn flexible_loan_borrow_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = FlexibleLoanBorrowParams::builder("loan_coin_example".to_string(),"collateral_coin_example".to_string(),).loan_amount(dec!(1.0)).collateral_amount(dec!(1.0)).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"loanCoin":"BUSD","loanAmount":"100.5","collateralCoin":"BNB","collateralAmount":"50.5","status":"Succeeds"}"#).unwrap();
            let expected_response : models::FlexibleLoanBorrowResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::FlexibleLoanBorrowResponse");

            let resp = client.flexible_loan_borrow(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn flexible_loan_borrow_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: true };

            let params = FlexibleLoanBorrowParams::builder(
                "loan_coin_example".to_string(),
                "collateral_coin_example".to_string(),
            )
            .build()
            .unwrap();

            match client.flexible_loan_borrow(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn flexible_loan_repay_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = FlexibleLoanRepayParams::builder("loan_coin_example".to_string(),"collateral_coin_example".to_string(),dec!(1.0),).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"loanCoin":"BUSD","collateralCoin":"BNB","remainingDebt":"100.5","remainingCollateral":"5.253","fullRepayment":false,"currentLTV":"0.25","repayStatus":"REPAID"}"#).unwrap();
            let expected_response : models::FlexibleLoanRepayResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::FlexibleLoanRepayResponse");

            let resp = client.flexible_loan_repay(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn flexible_loan_repay_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = FlexibleLoanRepayParams::builder("loan_coin_example".to_string(),"collateral_coin_example".to_string(),dec!(1.0),).collateral_return(true).full_repayment(false).repayment_type(1).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"loanCoin":"BUSD","collateralCoin":"BNB","remainingDebt":"100.5","remainingCollateral":"5.253","fullRepayment":false,"currentLTV":"0.25","repayStatus":"REPAID"}"#).unwrap();
            let expected_response : models::FlexibleLoanRepayResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::FlexibleLoanRepayResponse");

            let resp = client.flexible_loan_repay(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn flexible_loan_repay_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: true };

            let params = FlexibleLoanRepayParams::builder(
                "loan_coin_example".to_string(),
                "collateral_coin_example".to_string(),
                dec!(1.0),
            )
            .build()
            .unwrap();

            match client.flexible_loan_repay(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn get_flexible_loan_assets_data_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = GetFlexibleLoanAssetsDataParams::builder().build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","flexibleInterestRate":"0.00000491","flexibleMinLimit":"100","flexibleMaxLimit":"1000000"}],"total":1}"#).unwrap();
            let expected_response : models::GetFlexibleLoanAssetsDataResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFlexibleLoanAssetsDataResponse");

            let resp = client.get_flexible_loan_assets_data(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_flexible_loan_assets_data_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = GetFlexibleLoanAssetsDataParams::builder().loan_coin("loan_coin_example".to_string()).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","flexibleInterestRate":"0.00000491","flexibleMinLimit":"100","flexibleMaxLimit":"1000000"}],"total":1}"#).unwrap();
            let expected_response : models::GetFlexibleLoanAssetsDataResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFlexibleLoanAssetsDataResponse");

            let resp = client.get_flexible_loan_assets_data(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_flexible_loan_assets_data_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: true };

            let params = GetFlexibleLoanAssetsDataParams::builder().build().unwrap();

            match client.get_flexible_loan_assets_data(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn get_flexible_loan_borrow_history_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = GetFlexibleLoanBorrowHistoryParams::builder().build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","initialLoanAmount":"10000","collateralCoin":"BNB","initialCollateralAmount":"49.27565492","borrowTime":1575018510000,"status":"SUCCESS"}],"total":1}"#).unwrap();
            let expected_response : models::GetFlexibleLoanBorrowHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFlexibleLoanBorrowHistoryResponse");

            let resp = client.get_flexible_loan_borrow_history(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_flexible_loan_borrow_history_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = GetFlexibleLoanBorrowHistoryParams::builder().loan_coin("loan_coin_example".to_string()).collateral_coin("collateral_coin_example".to_string()).start_time(1623319461670).end_time(1641782889000).current(1).limit(10).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","initialLoanAmount":"10000","collateralCoin":"BNB","initialCollateralAmount":"49.27565492","borrowTime":1575018510000,"status":"SUCCESS"}],"total":1}"#).unwrap();
            let expected_response : models::GetFlexibleLoanBorrowHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFlexibleLoanBorrowHistoryResponse");

            let resp = client.get_flexible_loan_borrow_history(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_flexible_loan_borrow_history_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: true };

            let params = GetFlexibleLoanBorrowHistoryParams::builder()
                .build()
                .unwrap();

            match client.get_flexible_loan_borrow_history(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn get_flexible_loan_collateral_assets_data_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = GetFlexibleLoanCollateralAssetsDataParams::builder().build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"collateralCoin":"BNB","initialLTV":"0.65","marginCallLTV":"0.75","liquidationLTV":"0.83","maxLimit":"1000000"}],"total":1}"#).unwrap();
            let expected_response : models::GetFlexibleLoanCollateralAssetsDataResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFlexibleLoanCollateralAssetsDataResponse");

            let resp = client.get_flexible_loan_collateral_assets_data(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_flexible_loan_collateral_assets_data_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = GetFlexibleLoanCollateralAssetsDataParams::builder().collateral_coin("collateral_coin_example".to_string()).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"collateralCoin":"BNB","initialLTV":"0.65","marginCallLTV":"0.75","liquidationLTV":"0.83","maxLimit":"1000000"}],"total":1}"#).unwrap();
            let expected_response : models::GetFlexibleLoanCollateralAssetsDataResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFlexibleLoanCollateralAssetsDataResponse");

            let resp = client.get_flexible_loan_collateral_assets_data(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_flexible_loan_collateral_assets_data_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: true };

            let params = GetFlexibleLoanCollateralAssetsDataParams::builder()
                .build()
                .unwrap();

            match client
                .get_flexible_loan_collateral_assets_data(params)
                .await
            {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn get_flexible_loan_interest_rate_history_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = GetFlexibleLoanInterestRateHistoryParams::builder("coin_example".to_string(),5000,).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"coin":"USDT","annualizedInterestRate":"0.0647","time":1575018510000},{"coin":"USDT","annualizedInterestRate":"0.0647","time":1575018510000}],"total":2}"#).unwrap();
            let expected_response : models::GetFlexibleLoanInterestRateHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFlexibleLoanInterestRateHistoryResponse");

            let resp = client.get_flexible_loan_interest_rate_history(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_flexible_loan_interest_rate_history_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = GetFlexibleLoanInterestRateHistoryParams::builder("coin_example".to_string(),5000,).start_time(1623319461670).end_time(1641782889000).current(1).limit(10).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"coin":"USDT","annualizedInterestRate":"0.0647","time":1575018510000},{"coin":"USDT","annualizedInterestRate":"0.0647","time":1575018510000}],"total":2}"#).unwrap();
            let expected_response : models::GetFlexibleLoanInterestRateHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFlexibleLoanInterestRateHistoryResponse");

            let resp = client.get_flexible_loan_interest_rate_history(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_flexible_loan_interest_rate_history_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: true };

            let params =
                GetFlexibleLoanInterestRateHistoryParams::builder("coin_example".to_string(), 5000)
                    .build()
                    .unwrap();

            match client.get_flexible_loan_interest_rate_history(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn get_flexible_loan_liquidation_history_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = GetFlexibleLoanLiquidationHistoryParams::builder().build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","liquidationDebt":"10000","collateralCoin":"BNB","liquidationCollateralAmount":"123","returnCollateralAmount":"0.2","liquidationFee":"1.2","liquidationStartingPrice":"49.27565492","liquidationStartingTime":1575018510000,"status":"Liquidated"}],"total":1}"#).unwrap();
            let expected_response : models::GetFlexibleLoanLiquidationHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFlexibleLoanLiquidationHistoryResponse");

            let resp = client.get_flexible_loan_liquidation_history(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_flexible_loan_liquidation_history_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = GetFlexibleLoanLiquidationHistoryParams::builder().loan_coin("loan_coin_example".to_string()).collateral_coin("collateral_coin_example".to_string()).start_time(1623319461670).end_time(1641782889000).current(1).limit(10).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","liquidationDebt":"10000","collateralCoin":"BNB","liquidationCollateralAmount":"123","returnCollateralAmount":"0.2","liquidationFee":"1.2","liquidationStartingPrice":"49.27565492","liquidationStartingTime":1575018510000,"status":"Liquidated"}],"total":1}"#).unwrap();
            let expected_response : models::GetFlexibleLoanLiquidationHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFlexibleLoanLiquidationHistoryResponse");

            let resp = client.get_flexible_loan_liquidation_history(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_flexible_loan_liquidation_history_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: true };

            let params = GetFlexibleLoanLiquidationHistoryParams::builder()
                .build()
                .unwrap();

            match client.get_flexible_loan_liquidation_history(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn get_flexible_loan_ltv_adjustment_history_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = GetFlexibleLoanLtvAdjustmentHistoryParams::builder().build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","collateralCoin":"BNB","direction":"ADDITIONAL","collateralAmount":"5.235","preLTV":"0.78","afterLTV":"0.56","adjustTime":1575018510000}],"total":1}"#).unwrap();
            let expected_response : models::GetFlexibleLoanLtvAdjustmentHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFlexibleLoanLtvAdjustmentHistoryResponse");

            let resp = client.get_flexible_loan_ltv_adjustment_history(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_flexible_loan_ltv_adjustment_history_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = GetFlexibleLoanLtvAdjustmentHistoryParams::builder().loan_coin("loan_coin_example".to_string()).collateral_coin("collateral_coin_example".to_string()).start_time(1623319461670).end_time(1641782889000).current(1).limit(10).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","collateralCoin":"BNB","direction":"ADDITIONAL","collateralAmount":"5.235","preLTV":"0.78","afterLTV":"0.56","adjustTime":1575018510000}],"total":1}"#).unwrap();
            let expected_response : models::GetFlexibleLoanLtvAdjustmentHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFlexibleLoanLtvAdjustmentHistoryResponse");

            let resp = client.get_flexible_loan_ltv_adjustment_history(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_flexible_loan_ltv_adjustment_history_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: true };

            let params = GetFlexibleLoanLtvAdjustmentHistoryParams::builder()
                .build()
                .unwrap();

            match client
                .get_flexible_loan_ltv_adjustment_history(params)
                .await
            {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn get_flexible_loan_ongoing_orders_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = GetFlexibleLoanOngoingOrdersParams::builder().build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","totalDebt":"10000","collateralCoin":"BNB","collateralAmount":"49.27565492","currentLTV":"0.57"}],"total":1}"#).unwrap();
            let expected_response : models::GetFlexibleLoanOngoingOrdersResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFlexibleLoanOngoingOrdersResponse");

            let resp = client.get_flexible_loan_ongoing_orders(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_flexible_loan_ongoing_orders_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = GetFlexibleLoanOngoingOrdersParams::builder().loan_coin("loan_coin_example".to_string()).collateral_coin("collateral_coin_example".to_string()).current(1).limit(10).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","totalDebt":"10000","collateralCoin":"BNB","collateralAmount":"49.27565492","currentLTV":"0.57"}],"total":1}"#).unwrap();
            let expected_response : models::GetFlexibleLoanOngoingOrdersResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFlexibleLoanOngoingOrdersResponse");

            let resp = client.get_flexible_loan_ongoing_orders(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_flexible_loan_ongoing_orders_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: true };

            let params = GetFlexibleLoanOngoingOrdersParams::builder()
                .build()
                .unwrap();

            match client.get_flexible_loan_ongoing_orders(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }

    #[test]
    fn get_flexible_loan_repayment_history_required_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = GetFlexibleLoanRepaymentHistoryParams::builder().build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","repayAmount":"10000","collateralCoin":"BNB","collateralReturn":"49.27565492","repayStatus":"REPAID","repayTime":1575018510000}],"total":1}"#).unwrap();
            let expected_response : models::GetFlexibleLoanRepaymentHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFlexibleLoanRepaymentHistoryResponse");

            let resp = client.get_flexible_loan_repayment_history(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_flexible_loan_repayment_history_optional_params_success() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: false };

            let params = GetFlexibleLoanRepaymentHistoryParams::builder().loan_coin("loan_coin_example".to_string()).collateral_coin("collateral_coin_example".to_string()).start_time(1623319461670).end_time(1641782889000).current(1).limit(10).recv_window(5000).build().unwrap();

            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","repayAmount":"10000","collateralCoin":"BNB","collateralReturn":"49.27565492","repayStatus":"REPAID","repayTime":1575018510000}],"total":1}"#).unwrap();
            let expected_response : models::GetFlexibleLoanRepaymentHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFlexibleLoanRepaymentHistoryResponse");

            let resp = client.get_flexible_loan_repayment_history(params).await.expect("Expected a response");
            let data_future = resp.data();
            let actual_response = data_future.await.unwrap();
            assert_eq!(actual_response, expected_response);
        });
    }

    #[test]
    fn get_flexible_loan_repayment_history_response_error() {
        TOKIO_SHARED_RT.block_on(async {
            let client = MockFlexibleRateApiClient { force_error: true };

            let params = GetFlexibleLoanRepaymentHistoryParams::builder()
                .build()
                .unwrap();

            match client.get_flexible_loan_repayment_history(params).await {
                Ok(_) => panic!("Expected an error"),
                Err(err) => {
                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
                }
            }
        });
    }
}
