        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsAuthorizeRouterData, errors::ConnectorError> {
        let response: PaypalAuthResponse =
            res.response
                .parse_struct("paypal PaypalAuthResponse")
                .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        match response {
            PaypalAuthResponse::PaypalOrdersResponse(response) => {
                event_builder.map(|i| i.set_response_body(&response));
                router_env::logger::info!(connector_response=?response);

                RouterData::try_from(ResponseRouterData {
                    response,
                    data: data.clone(),
                    http_code: res.status_code,
                })
            }
            PaypalAuthResponse::PaypalRedirectResponse(response) => {
                event_builder.map(|i| i.set_response_body(&response));
                router_env::logger::info!(connector_response=?response);
                RouterData::try_from(ResponseRouterData {
                    response,
                    data: data.clone(),
                    http_code: res.status_code,
                })
            }
            PaypalAuthResponse::PaypalThreeDsResponse(response) => {
                event_builder.map(|i| i.set_response_body(&response));
                router_env::logger::info!(connector_response=?response);
                RouterData::try_from(ResponseRouterData {
                    response,
                    data: data.clone(),
                    http_code: res.status_code,
                })
            }
        }
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.get_order_error_response(res, event_builder)
    }
}

impl PaymentIncrementalAuthorization for Paypal {}

impl
    ConnectorIntegration<
        IncrementalAuthorization,
        PaymentsIncrementalAuthorizationData,
        PaymentsResponseData,
    > for Paypal
{
    fn get_headers(
        &self,
        req: &PaymentsIncrementalAuthorizationRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_http_method(&self) -> Method {
        Method::Post
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        req: &PaymentsIncrementalAuthorizationRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let paypal_meta: PaypalMeta = to_connector_meta(req.request.connector_meta.clone())?;
        let incremental_authorization_id = paypal_meta.incremental_authorization_id.ok_or(
            errors::ConnectorError::RequestEncodingFailedWithReason(
                "Missing incremental authorization id".to_string(),
            ),
        )?;
        Ok(format!(
            "{}v2/payments/authorizations/{}/reauthorize",
            self.base_url(connectors),
            incremental_authorization_id
        ))
    }

    fn get_request_body(
        &self,
        req: &PaymentsIncrementalAuthorizationRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = connector_utils::convert_amount(
            self.amount_converter,
            MinorUnit::new(req.request.total_amount),
            req.request.currency,
        )?;
        let connector_router_data =
            paypal::PaypalRouterData::try_from((amount, None, None, None, req))?;
        let connector_req = paypal::PaypalIncrementalAuthRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &PaymentsIncrementalAuthorizationRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&IncrementalAuthorizationType::get_url(
                    self, req, connectors,
                )?)
                .attach_default_headers()
                .headers(IncrementalAuthorizationType::get_headers(
                    self, req, connectors,
                )?)
                .set_body(IncrementalAuthorizationType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsIncrementalAuthorizationRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<
        RouterData<
            IncrementalAuthorization,
            PaymentsIncrementalAuthorizationData,
            PaymentsResponseData,
        >,
        errors::ConnectorError,
    > {
        let response: PaypalIncrementalAuthResponse = res
            .response
            .parse_struct("Paypal IncrementalAuthResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
        .change_context(errors::ConnectorError::ResponseHandlingFailed)
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl api::PaymentsPreProcessing for Paypal {}

impl ConnectorIntegration<PreProcessing, PaymentsPreProcessingData, PaymentsResponseData>
    for Paypal
{
    fn get_headers(
        &self,
        req: &PaymentsPreProcessingRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_url(
        &self,
        req: &PaymentsPreProcessingRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let order_id = req
            .request
            .connector_transaction_id
            .to_owned()
            .ok_or(errors::ConnectorError::MissingConnectorTransactionID)?;
        Ok(format!(
            "{}v2/checkout/orders/{}?fields=payment_source",
            self.base_url(connectors),
            order_id,
        ))
    }

    fn build_request(
        &self,
        req: &PaymentsPreProcessingRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Get)
                .url(&PaymentsPreProcessingType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(PaymentsPreProcessingType::get_headers(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsPreProcessingRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsPreProcessingRouterData, errors::ConnectorError> {
        let response: paypal::PaypalPreProcessingResponse = res
            .response
            .parse_struct("paypal PaypalPreProcessingResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);

        match response {
            // if card supports 3DS check for liability
            paypal::PaypalPreProcessingResponse::PaypalLiabilityResponse(liability_response) => {
                // permutation for status to continue payment
                match (
                    liability_response
                        .payment_source
                        .card
                        .authentication_result
                        .three_d_secure
                        .enrollment_status
                        .as_ref(),
                    liability_response
                        .payment_source
                        .card
                        .authentication_result
                        .three_d_secure
                        .authentication_status
                        .as_ref(),
                    liability_response
                        .payment_source
                        .card
                        .authentication_result
                        .liability_shift
                        .clone(),
                ) {
                    (
                        Some(paypal::EnrollmentStatus::Ready),
                        Some(paypal::AuthenticationStatus::Success),
                        paypal::LiabilityShift::Possible,
                    )
                    | (
                        Some(paypal::EnrollmentStatus::Ready),
                        Some(paypal::AuthenticationStatus::Attempted),
                        paypal::LiabilityShift::Possible,
                    )
                    | (Some(paypal::EnrollmentStatus::NotReady), None, paypal::LiabilityShift::No)
                    | (Some(paypal::EnrollmentStatus::Unavailable), None, paypal::LiabilityShift::No)
                    | (Some(paypal::EnrollmentStatus::Bypassed), None, paypal::LiabilityShift::No) => {
                        Ok(PaymentsPreProcessingRouterData {
                            status: enums::AttemptStatus::AuthenticationSuccessful,
                            response: Ok(PaymentsResponseData::TransactionResponse {
                                resource_id: ResponseId::NoResponseId,
                                redirection_data: Box::new(None),
                                mandate_reference: Box::new(None),
                                connector_metadata: None,
                                network_txn_id: None,
                                connector_response_reference_id: None,
                                incremental_authorization_allowed: None,
                                charges: None,
                            }),
                            ..data.clone()
                        })
                    }
                    _ => Ok(PaymentsPreProcessingRouterData {
                        response: Err(ErrorResponse {
                            attempt_status: Some(enums::AttemptStatus::Failure),
                            code: NO_ERROR_CODE.to_string(),
                            message: NO_ERROR_MESSAGE.to_string(),
                            connector_transaction_id: None,
                            reason: Some(format!("{} Connector Responsded with LiabilityShift: {:?}, EnrollmentStatus: {:?}, and AuthenticationStatus: {:?}",
                            constants::CANNOT_CONTINUE_AUTH,
                            liability_response
                                .payment_source
                                .card
                                .authentication_result
                                .liability_shift,
                            liability_response
                                .payment_source
                                .card
                                .authentication_result
                                .three_d_secure
                                .enrollment_status
                                .unwrap_or(paypal::EnrollmentStatus::Null),
                            liability_response
                                .payment_source
                                .card
                                .authentication_result
                                .three_d_secure
                                .authentication_status
                                .unwrap_or(paypal::AuthenticationStatus::Null),
                            )),
                            status_code: res.status_code,
                            network_advice_code: None,
                            network_decline_code: None,
                            network_error_message: None,
                            connector_metadata: None,
                        }),
                        ..data.clone()
                    }),
                }
            }
            // if card does not supports 3DS check for liability
            paypal::PaypalPreProcessingResponse::PaypalNonLiabilityResponse(_) => {
                Ok(PaymentsPreProcessingRouterData {
                    status: enums::AttemptStatus::AuthenticationSuccessful,
                    response: Ok(PaymentsResponseData::TransactionResponse {
                        resource_id: ResponseId::NoResponseId,
                        redirection_data: Box::new(None),
                        mandate_reference: Box::new(None),
                        connector_metadata: None,
                        network_txn_id: None,
                        connector_response_reference_id: None,
                        incremental_authorization_allowed: None,
                        charges: None,
                    }),
                    ..data.clone()
                })
            }
        }
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<CompleteAuthorize, CompleteAuthorizeData, PaymentsResponseData>
    for Paypal
{
    fn get_headers(
        &self,
        req: &PaymentsCompleteAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        req: &PaymentsCompleteAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let complete_authorize_url = if req.request.is_auto_capture()? {
            "capture".to_string()
        } else {
            "authorize".to_string()
        };
        Ok(format!(
            "{}v2/checkout/orders/{}/{complete_authorize_url}",
            self.base_url(connectors),
            req.request
                .connector_transaction_id
                .clone()
                .ok_or(errors::ConnectorError::MissingConnectorTransactionID)?
        ))
    }

    fn build_request(
        &self,
        req: &PaymentsCompleteAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&PaymentsCompleteAuthorizeType::get_url(
                    self, req, connectors,
                )?)
                .headers(PaymentsCompleteAuthorizeType::get_headers(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsCompleteAuthorizeRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCompleteAuthorizeRouterData, errors::ConnectorError> {
        let response: paypal::PaypalOrdersResponse = res
            .response
            .parse_struct("paypal PaypalOrdersResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Paypal {
    fn get_headers(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let paypal_meta: PaypalMeta = to_connector_meta(req.request.connector_meta.clone())?;
        match req.payment_method {
            enums::PaymentMethod::Wallet | enums::PaymentMethod::BankRedirect => Ok(format!(
                "{}v2/checkout/orders/{}",
                self.base_url(connectors),
                req.request
                    .connector_transaction_id
                    .get_connector_transaction_id()
                    .change_context(errors::ConnectorError::MissingConnectorTransactionID)?
            )),
            _ => {
                let psync_url = match paypal_meta.psync_flow {
                    transformers::PaypalPaymentIntent::Authorize => {
                        let authorize_id = paypal_meta.authorize_id.ok_or(
                            errors::ConnectorError::RequestEncodingFailedWithReason(
                                "Missing Authorize id".to_string(),
                            ),
                        )?;
                        format!("v2/payments/authorizations/{authorize_id}")
                    }
                    transformers::PaypalPaymentIntent::Capture => {
                        let capture_id = paypal_meta.capture_id.ok_or(
                            errors::ConnectorError::RequestEncodingFailedWithReason(
                                "Missing Capture id".to_string(),
                            ),
                        )?;
                        format!("v2/payments/captures/{capture_id}")
                    }
                    // only set when payment is done through card 3DS
                    //because no authorize or capture id is generated during payment authorize call for card 3DS
                    transformers::PaypalPaymentIntent::Authenticate => {
                        format!(
                            "v2/checkout/orders/{}",
                            req.request
                                .connector_transaction_id
                                .get_connector_transaction_id()
                                .change_context(
                                    errors::ConnectorError::MissingConnectorTransactionID
                                )?
                        )
                    }
                };
                Ok(format!("{}{psync_url}", self.base_url(connectors)))
            }
        }
    }

    fn build_request(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Get)
                .url(&PaymentsSyncType::get_url(self, req, connectors)?)
                .headers(PaymentsSyncType::get_headers(self, req, connectors)?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsSyncRouterData, errors::ConnectorError> {
        let response: paypal::PaypalSyncResponse = res
            .response
            .parse_struct("paypal SyncResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::foreign_try_from((
            ResponseRouterData {
                response,
                data: data.clone(),
                http_code: res.status_code,
            },
            data.request.payment_experience,
        ))
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<Capture, PaymentsCaptureData, PaymentsResponseData> for Paypal {
    fn get_headers(
        &self,
        req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let paypal_meta: PaypalMeta = to_connector_meta(req.request.connector_meta.clone())?;
        let authorize_id = paypal_meta.authorize_id.ok_or(
            errors::ConnectorError::RequestEncodingFailedWithReason(
                "Missing Authorize id".to_string(),
            ),
        )?;
        Ok(format!(
            "{}v2/payments/authorizations/{}/capture",
            self.base_url(connectors),
            authorize_id
        ))
    }

    fn get_request_body(
        &self,
        req: &PaymentsCaptureRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount_to_capture = connector_utils::convert_amount(
            self.amount_converter,
            req.request.minor_amount_to_capture,
            req.request.currency,
        )?;
        let connector_router_data =
            paypal::PaypalRouterData::try_from((amount_to_capture, None, None, None, req))?;
        let connector_req = paypal::PaypalPaymentsCaptureRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&PaymentsCaptureType::get_url(self, req, connectors)?)
                .headers(PaymentsCaptureType::get_headers(self, req, connectors)?)
                .set_body(PaymentsCaptureType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsCaptureRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCaptureRouterData, errors::ConnectorError> {
        let response: paypal::PaypalCaptureResponse = res
            .response
            .parse_struct("Paypal PaymentsCaptureResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<Void, PaymentsCancelData, PaymentsResponseData> for Paypal {
    fn get_headers(
        &self,
        req: &PaymentsCancelRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        req: &PaymentsCancelRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let paypal_meta: PaypalMeta = to_connector_meta(req.request.connector_meta.clone())?;
        let authorize_id = paypal_meta.authorize_id.ok_or(
            errors::ConnectorError::RequestEncodingFailedWithReason(
                "Missing Authorize id".to_string(),
            ),
        )?;
        Ok(format!(
            "{}v2/payments/authorizations/{}/void",
            self.base_url(connectors),
            authorize_id,
        ))
    }

    fn build_request(
        &self,
        req: &PaymentsCancelRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let request = RequestBuilder::new()
            .method(Method::Post)
            .url(&PaymentsVoidType::get_url(self, req, connectors)?)
            .headers(PaymentsVoidType::get_headers(self, req, connectors)?)
            .build();

        Ok(Some(request))
    }

    fn handle_response(
        &self,
        data: &PaymentsCancelRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCancelRouterData, errors::ConnectorError> {
        let response: paypal::PaypalPaymentsCancelResponse = res
            .response
            .parse_struct("PaymentCancelResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }
    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Paypal {
    fn get_headers(
        &self,
        req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let paypal_meta: PaypalMeta = to_connector_meta(req.request.connector_metadata.clone())?;
        let capture_id = paypal_meta.capture_id.ok_or(
            errors::ConnectorError::RequestEncodingFailedWithReason(
                "Missing Capture id".to_string(),
            ),
        )?;
        Ok(format!(
            "{}v2/payments/captures/{}/refund",
            self.base_url(connectors),
            capture_id,
        ))
    }

    fn get_request_body(
        &self,
        req: &RefundsRouterData<Execute>,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = connector_utils::convert_amount(
            self.amount_converter,
            req.request.minor_refund_amount,
            req.request.currency,
        )?;
        let connector_router_data =
            paypal::PaypalRouterData::try_from((amount, None, None, None, req))?;
        let connector_req = paypal::PaypalRefundRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let request = RequestBuilder::new()
            .method(Method::Post)
            .url(&RefundExecuteType::get_url(self, req, connectors)?)
            .headers(RefundExecuteType::get_headers(self, req, connectors)?)
            .set_body(RefundExecuteType::get_request_body(self, req, connectors)?)
            .build();

        Ok(Some(request))
    }

    fn handle_response(
        &self,
        data: &RefundsRouterData<Execute>,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefundsRouterData<Execute>, errors::ConnectorError> {
        let response: paypal::RefundResponse =
            res.response
                .parse_struct("paypal RefundResponse")
                .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Paypal {
    fn get_headers(
        &self,
        req: &RefundSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        req: &RefundSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!(
            "{}v2/payments/refunds/{}",
            self.base_url(connectors),
            req.request.get_connector_refund_id()?
        ))
    }

    fn build_request(
        &self,
        req: &RefundSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Get)
                .url(&RefundSyncType::get_url(self, req, connectors)?)
                .headers(RefundSyncType::get_headers(self, req, connectors)?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &RefundSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefundSyncRouterData, errors::ConnectorError> {
        let response: paypal::RefundSyncResponse = res
            .response
            .parse_struct("paypal RefundSyncResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl
    ConnectorIntegration<
        VerifyWebhookSource,
        VerifyWebhookSourceRequestData,
        VerifyWebhookSourceResponseData,
    > for Paypal
{
    fn get_headers(
        &self,
        req: &RouterData<
            VerifyWebhookSource,
            VerifyWebhookSourceRequestData,
            VerifyWebhookSourceResponseData,
        >,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        let auth = paypal::PaypalAuthType::try_from(&req.connector_auth_type)?;
        let credentials = auth.get_credentials()?;
        let auth_val = credentials.generate_authorization_value();

        Ok(vec![
            (
                headers::CONTENT_TYPE.to_string(),
                VerifyWebhookSourceType::get_content_type(self)
                    .to_string()
                    .into(),
            ),
            (headers::AUTHORIZATION.to_string(), auth_val.into_masked()),
        ])
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &RouterData<
            VerifyWebhookSource,
            VerifyWebhookSourceRequestData,
            VerifyWebhookSourceResponseData,
        >,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!(
            "{}v1/notifications/verify-webhook-signature",
            self.base_url(connectors)
        ))
    }

    fn build_request(
        &self,
        req: &VerifyWebhookSourceRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let request = RequestBuilder::new()
            .method(Method::Post)
            .url(&VerifyWebhookSourceType::get_url(self, req, connectors)?)
            .headers(VerifyWebhookSourceType::get_headers(self, req, connectors)?)
            .set_body(VerifyWebhookSourceType::get_request_body(
                self, req, connectors,
            )?)
            .build();
        Ok(Some(request))
    }

    fn get_request_body(
        &self,
        req: &RouterData<
            VerifyWebhookSource,
            VerifyWebhookSourceRequestData,
            VerifyWebhookSourceResponseData,
        >,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = paypal::PaypalSourceVerificationRequest::try_from(&req.request)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn handle_response(
        &self,
        data: &VerifyWebhookSourceRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<VerifyWebhookSourceRouterData, errors::ConnectorError> {
        let response: paypal::PaypalSourceVerificationResponse = res
            .response
            .parse_struct("paypal PaypalSourceVerificationResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }
    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

#[async_trait::async_trait]
impl IncomingWebhook for Paypal {
    fn get_webhook_object_reference_id(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
        let payload: paypal::PaypalWebhooksBody =
            request
                .body
                .parse_struct("PaypalWebhooksBody")
                .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
        match payload.resource {
            paypal::PaypalResource::PaypalCardWebhooks(resource) => {
                Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
                    api_models::payments::PaymentIdType::ConnectorTransactionId(
                        resource.supplementary_data.related_ids.order_id,
                    ),
                ))
            }
            paypal::PaypalResource::PaypalRedirectsWebhooks(resource) => {
                Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
                    api_models::payments::PaymentIdType::PaymentAttemptId(
                        resource
                            .purchase_units
                            .first()
                            .and_then(|unit| unit.invoice_id.clone().or(unit.reference_id.clone()))
                            .ok_or(errors::ConnectorError::WebhookReferenceIdNotFound)?,
                    ),
                ))
            }
            paypal::PaypalResource::PaypalRefundWebhooks(resource) => {
                Ok(api_models::webhooks::ObjectReferenceId::RefundId(
                    api_models::webhooks::RefundIdType::ConnectorRefundId(resource.id),
                ))
            }
            paypal::PaypalResource::PaypalDisputeWebhooks(resource) => {
                Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
                    api_models::payments::PaymentIdType::ConnectorTransactionId(
                        resource
                            .disputed_transactions
                            .first()
                            .map(|transaction| transaction.seller_transaction_id.clone())
                            .ok_or(errors::ConnectorError::WebhookReferenceIdNotFound)?,
                    ),
                ))
            }
            #[cfg(feature = "payouts")]
            paypal::PaypalResource::PaypalBatchPayoutWebhooks(resource) => {
                Ok(api_models::webhooks::ObjectReferenceId::PayoutId(
                    api_models::webhooks::PayoutIdType::ConnectorPayoutId(
                        resource.batch_header.payout_batch_id,
                    ),
                ))
            }
            #[cfg(feature = "payouts")]
            paypal::PaypalResource::PaypalItemPayoutWebhooks(resource) => {
                Ok(api_models::webhooks::ObjectReferenceId::PayoutId(
                    api_models::webhooks::PayoutIdType::PayoutAttemptId(resource.sender_batch_id),
                ))
            }
        }
    }

    fn get_webhook_event_type(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::IncomingWebhookEvent, errors::ConnectorError> {
        let payload: paypal::PaypalWebooksEventType = request
            .body
            .parse_struct("PaypalWebooksEventType")
            .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
        let outcome = match payload.event_type {
            PaypalWebhookEventType::CustomerDisputeResolved => Some(
                request
                    .body
                    .parse_struct::<paypal::DisputeOutcome>("PaypalWebooksEventType")
                    .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?
                    .outcome_code,
            ),
            PaypalWebhookEventType::CustomerDisputeCreated
            | PaypalWebhookEventType::RiskDisputeCreated
            | PaypalWebhookEventType::CustomerDisputedUpdated
            | PaypalWebhookEventType::PaymentAuthorizationCreated
            | PaypalWebhookEventType::PaymentAuthorizationVoided
            | PaypalWebhookEventType::PaymentCaptureDeclined
            | PaypalWebhookEventType::PaymentCaptureCompleted
            | PaypalWebhookEventType::PaymentCapturePending
            | PaypalWebhookEventType::PaymentCaptureRefunded
            | PaypalWebhookEventType::CheckoutOrderApproved
            | PaypalWebhookEventType::CheckoutOrderCompleted
            | PaypalWebhookEventType::CheckoutOrderProcessed
            | PaypalWebhookEventType::Unknown => None,
            #[cfg(feature = "payouts")]
            PaypalWebhookEventType::PayoutsBatchDenied
            | PaypalWebhookEventType::PayoutsBatchProcessing
            | PaypalWebhookEventType::PayoutsBatchSuccess
            | PaypalWebhookEventType::PayoutsItemBlocked
            | PaypalWebhookEventType::PayoutsItemCanceled
            | PaypalWebhookEventType::PayoutsItemDenied
            | PaypalWebhookEventType::PayoutsItemFailed
            | PaypalWebhookEventType::PayoutsItemHeld
            | PaypalWebhookEventType::PayoutsItemRefunded
            | PaypalWebhookEventType::PayoutsItemReturned
            | PaypalWebhookEventType::PayoutsItemSuccess
            | PaypalWebhookEventType::PayoutsItemUnclaimed => None,
        };

        Ok(transformers::get_payapl_webhooks_event(
            payload.event_type,
            outcome,
        ))
    }

    fn get_webhook_resource_object(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
        let details: paypal::PaypalWebhooksBody =
            request
                .body
                .parse_struct("PaypalWebhooksBody")
                .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
        Ok(match details.resource {
            paypal::PaypalResource::PaypalCardWebhooks(resource) => Box::new(
                paypal::PaypalPaymentsSyncResponse::try_from((*resource, details.event_type))?,
            ),


File: crates/router/src/db/health_check.rs

use async_bb8_diesel::{AsyncConnection, AsyncRunQueryDsl};
use diesel_models::ConfigNew;
use error_stack::ResultExt;
use router_env::{instrument, logger, tracing};

use super::{MockDb, Store};
use crate::{
    connection,
    core::errors::{self, CustomResult},
    types::storage,
};

#[async_trait::async_trait]
pub trait HealthCheckDbInterface {
    async fn health_check_db(&self) -> CustomResult<(), errors::HealthCheckDBError>;
}

#[async_trait::async_trait]
impl HealthCheckDbInterface for Store {
    #[instrument(skip_all)]
    async fn health_check_db(&self) -> CustomResult<(), errors::HealthCheckDBError> {
        let conn = connection::pg_connection_write(self)
            .await
            .change_context(errors::HealthCheckDBError::DBError)?;

        conn.transaction_async(|conn| async move {
            let query = diesel::select(diesel::dsl::sql::<diesel::sql_types::Integer>("1 + 1"));
            let _x: i32 = query.get_result_async(&conn).await.map_err(|err| {
                logger::error!(read_err=?err,"Error while reading element in the database");
                errors::HealthCheckDBError::DBReadError
            })?;

            logger::debug!("Database read was successful");

            let config = ConfigNew {
                key: "test_key".to_string(),
                config: "test_value".to_string(),
            };

            config.insert(&conn).await.map_err(|err| {
                logger::error!(write_err=?err,"Error while writing to database");
                errors::HealthCheckDBError::DBWriteError
            })?;

            logger::debug!("Database write was successful");

            storage::Config::delete_by_key(&conn, "test_key")
                .await
                .map_err(|err| {
                    logger::error!(delete_err=?err,"Error while deleting element in the database");
                    errors::HealthCheckDBError::DBDeleteError
                })?;

            logger::debug!("Database delete was successful");

            Ok::<_, errors::HealthCheckDBError>(())
        })
        .await?;

        Ok(())
    }
}

#[async_trait::async_trait]
impl HealthCheckDbInterface for MockDb {
    async fn health_check_db(&self) -> CustomResult<(), errors::HealthCheckDBError> {
        Ok(())
    }
}


pub struct BreadpayCartRequest {
    custom_total: StringMinorUnit,
    options: Option<BreadpayCartOptions>,
}


pub struct RoleUpdateInternal {
    groups: Option<Vec<enums::PermissionGroup>>,
    role_name: Option<String>,
    last_modified_by: String,
    last_modified_at: PrimitiveDateTime,
}


File: crates/diesel_models/src/capture.rs
 Public functions: 1
 Public structs: 3

use common_utils::types::{ConnectorTransactionId, MinorUnit};
use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
use serde::{Deserialize, Serialize};
use time::PrimitiveDateTime;

use crate::{enums as storage_enums, schema::captures};

#[derive(
    Clone, Debug, Eq, PartialEq, Identifiable, Queryable, Selectable, Serialize, Deserialize,
)]
#[diesel(table_name = captures, primary_key(capture_id), check_for_backend(diesel::pg::Pg))]
pub struct Capture {
    pub capture_id: String,
    pub payment_id: common_utils::id_type::PaymentId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub status: storage_enums::CaptureStatus,
    pub amount: MinorUnit,
    pub currency: Option<storage_enums::Currency>,
    pub connector: String,
    pub error_message: Option<String>,
    pub error_code: Option<String>,
    pub error_reason: Option<String>,
    pub tax_amount: Option<MinorUnit>,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub created_at: PrimitiveDateTime,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub modified_at: PrimitiveDateTime,
    pub authorized_attempt_id: String,
    pub connector_capture_id: Option<ConnectorTransactionId>,
    pub capture_sequence: i16,
    // reference to the capture at connector side
    pub connector_response_reference_id: Option<String>,
    /// INFO: This field is deprecated and replaced by processor_capture_data
    pub connector_capture_data: Option<String>,
    pub processor_capture_data: Option<String>,
}

#[derive(Clone, Debug, Insertable, router_derive::DebugAsDisplay, Serialize, Deserialize)]
#[diesel(table_name = captures)]
pub struct CaptureNew {
    pub capture_id: String,
    pub payment_id: common_utils::id_type::PaymentId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub status: storage_enums::CaptureStatus,
    pub amount: MinorUnit,
    pub currency: Option<storage_enums::Currency>,
    pub connector: String,
    pub error_message: Option<String>,
    pub error_code: Option<String>,
    pub error_reason: Option<String>,
    pub tax_amount: Option<MinorUnit>,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub created_at: PrimitiveDateTime,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub modified_at: PrimitiveDateTime,
    pub authorized_attempt_id: String,
    pub connector_capture_id: Option<ConnectorTransactionId>,
    pub capture_sequence: i16,
    pub connector_response_reference_id: Option<String>,
    /// INFO: This field is deprecated and replaced by processor_capture_data
    pub connector_capture_data: Option<String>,
    pub processor_capture_data: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum CaptureUpdate {
    ResponseUpdate {
        status: storage_enums::CaptureStatus,
        connector_capture_id: Option<ConnectorTransactionId>,
        connector_response_reference_id: Option<String>,
        processor_capture_data: Option<String>,
    },
    ErrorUpdate {
        status: storage_enums::CaptureStatus,
        error_code: Option<String>,
        error_message: Option<String>,
        error_reason: Option<String>,
    },
}

#[derive(Clone, Debug, Default, AsChangeset, router_derive::DebugAsDisplay)]
#[diesel(table_name = captures)]
pub struct CaptureUpdateInternal {
    pub status: Option<storage_enums::CaptureStatus>,
    pub error_message: Option<String>,
    pub error_code: Option<String>,
    pub error_reason: Option<String>,
    pub modified_at: Option<PrimitiveDateTime>,
    pub connector_capture_id: Option<ConnectorTransactionId>,
    pub connector_response_reference_id: Option<String>,
    pub processor_capture_data: Option<String>,
}

impl CaptureUpdate {
    pub fn apply_changeset(self, source: Capture) -> Capture {
        let CaptureUpdateInternal {
            status,
            error_message,
            error_code,
            error_reason,
            modified_at: _,
            connector_capture_id,
            connector_response_reference_id,
            processor_capture_data,
        } = self.into();
        Capture {
            status: status.unwrap_or(source.status),
            error_message: error_message.or(source.error_message),
            error_code: error_code.or(source.error_code),
            error_reason: error_reason.or(source.error_reason),
            modified_at: common_utils::date_time::now(),
            connector_capture_id: connector_capture_id.or(source.connector_capture_id),
            connector_response_reference_id: connector_response_reference_id
                .or(source.connector_response_reference_id),
            processor_capture_data: processor_capture_data.or(source.processor_capture_data),
            ..source
        }
    }
}

impl From<CaptureUpdate> for CaptureUpdateInternal {
    fn from(payment_attempt_child_update: CaptureUpdate) -> Self {
        let now = Some(common_utils::date_time::now());
        match payment_attempt_child_update {
            CaptureUpdate::ResponseUpdate {
                status,
                connector_capture_id: connector_transaction_id,
                connector_response_reference_id,
                processor_capture_data,
            } => Self {
                status: Some(status),
                connector_capture_id: connector_transaction_id,
                modified_at: now,
                connector_response_reference_id,
                processor_capture_data,
                ..Self::default()
            },
            CaptureUpdate::ErrorUpdate {
                status,
                error_code,
                error_message,
                error_reason,
            } => Self {
                status: Some(status),
                error_code,
                error_message,
                error_reason,
                modified_at: now,
                ..Self::default()
            },
        }
    }
}


File: crates/api_models/src/customers.rs
 Public functions: 12
 Public structs: 11

use common_utils::{crypto, custom_serde, id_type, pii, types::Description};
use masking::Secret;
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;

use crate::payments;

/// The customer details
#[cfg(feature = "v1")]
#[derive(Debug, Default, Clone, Deserialize, Serialize, ToSchema)]
pub struct CustomerRequest {
    /// The identifier for the customer object. If not provided the customer ID will be autogenerated.
    #[schema(value_type = Option<String>, max_length = 64, min_length = 1, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
    pub customer_id: Option<id_type::CustomerId>,
    /// The identifier for the Merchant Account
    #[schema(max_length = 255, example = "y3oqhf46pyzuxjbcn2giaqnb44")]
    #[serde(skip)]
    pub merchant_id: id_type::MerchantId,
    /// The customer's name
    #[schema(max_length = 255, value_type = Option<String>, example = "Jon Test")]
    pub name: Option<Secret<String>>,
    /// The customer's email address
    #[schema(value_type = Option<String>, max_length = 255, example = "JonTest@test.com")]
    pub email: Option<pii::Email>,
    /// The customer's phone number
    #[schema(value_type = Option<String>, max_length = 255, example = "9123456789")]
    pub phone: Option<Secret<String>>,
    /// An arbitrary string that you can attach to a customer object.
    #[schema(max_length = 255, example = "First Customer", value_type = Option<String>)]
    pub description: Option<Description>,
    /// The country code for the customer phone number
    #[schema(max_length = 255, example = "+65")]
    pub phone_country_code: Option<String>,
    /// The address for the customer
    #[schema(value_type = Option<AddressDetails>)]
    pub address: Option<payments::AddressDetails>,
    /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500
    /// characters long. Metadata is useful for storing additional, structured information on an
    /// object.
    #[schema(value_type = Option<Object>,example = json!({ "city": "NY", "unit": "245" }))]
    pub metadata: Option<pii::SecretSerdeValue>,
    /// Customer's tax registration ID
    #[schema(max_length = 255, value_type = Option<String>, example = "123456789")]
    pub tax_registration_id: Option<Secret<String>>,
}

#[derive(Debug, Default, Clone, Deserialize, Serialize, ToSchema)]
pub struct CustomerListRequest {
    /// Offset
    #[schema(example = 32)]
    pub offset: Option<u32>,
    /// Limit
    #[schema(example = 32)]
    pub limit: Option<u16>,
}

#[cfg(feature = "v1")]
impl CustomerRequest {
    pub fn get_merchant_reference_id(&self) -> Option<id_type::CustomerId> {
        Some(
            self.customer_id
                .to_owned()
                .unwrap_or_else(common_utils::generate_customer_id_of_default_length),
        )
    }
    pub fn get_address(&self) -> Option<payments::AddressDetails> {
        self.address.clone()
    }
    pub fn get_optional_email(&self) -> Option<pii::Email> {
        self.email.clone()
    }
}

/// The customer details
#[cfg(feature = "v2")]
#[derive(Debug, Default, Clone, Deserialize, Serialize, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct CustomerRequest {
    /// The merchant identifier for the customer object.
    #[schema(value_type = Option<String>, max_length = 64, min_length = 1, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
    pub merchant_reference_id: Option<id_type::CustomerId>,
    /// The customer's name
    #[schema(max_length = 255, value_type = String, example = "Jon Test")]
    pub name: Secret<String>,
    /// The customer's email address
    #[schema(value_type = String, max_length = 255, example = "JonTest@test.com")]
    pub email: pii::Email,
    /// The customer's phone number
    #[schema(value_type = Option<String>, max_length = 255, example = "9123456789")]
    pub phone: Option<Secret<String>>,
    /// An arbitrary string that you can attach to a customer object.
    #[schema(max_length = 255, example = "First Customer", value_type = Option<String>)]
    pub description: Option<Description>,
    /// The country code for the customer phone number
    #[schema(max_length = 255, example = "+65")]
    pub phone_country_code: Option<String>,
    /// The default billing address for the customer
    #[schema(value_type = Option<AddressDetails>)]
    pub default_billing_address: Option<payments::AddressDetails>,
    /// The default shipping address for the customer
    #[schema(value_type = Option<AddressDetails>)]
    pub default_shipping_address: Option<payments::AddressDetails>,
    /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500
    /// characters long. Metadata is useful for storing additional, structured information on an
    /// object.
    #[schema(value_type = Option<Object>,example = json!({ "city": "NY", "unit": "245" }))]
    pub metadata: Option<pii::SecretSerdeValue>,
    /// The customer's tax registration number.
    #[schema(max_length = 255, value_type = Option<String>, example = "123456789")]
    pub tax_registration_id: Option<Secret<String>>,
}

#[cfg(feature = "v2")]
impl CustomerRequest {
    pub fn get_merchant_reference_id(&self) -> Option<id_type::CustomerId> {
        self.merchant_reference_id.clone()
    }

    pub fn get_default_customer_billing_address(&self) -> Option<payments::AddressDetails> {
        self.default_billing_address.clone()
    }

    pub fn get_default_customer_shipping_address(&self) -> Option<payments::AddressDetails> {
        self.default_shipping_address.clone()
    }

    pub fn get_optional_email(&self) -> Option<pii::Email> {
        Some(self.email.clone())
    }
}

#[cfg(feature = "v1")]
#[derive(Debug, Clone, Serialize, ToSchema)]
pub struct CustomerResponse {
    /// The identifier for the customer object
    #[schema(value_type = String, max_length = 64, min_length = 1, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
    pub customer_id: id_type::CustomerId,
    /// The customer's name
    #[schema(max_length = 255, value_type = Option<String>, example = "Jon Test")]
    pub name: crypto::OptionalEncryptableName,
    /// The customer's email address
    #[schema(value_type = Option<String>,max_length = 255, example = "JonTest@test.com")]
    pub email: crypto::OptionalEncryptableEmail,
    /// The customer's phone number
    #[schema(value_type = Option<String>,max_length = 255, example = "9123456789")]
    pub phone: crypto::OptionalEncryptablePhone,
    /// The country code for the customer phone number
    #[schema(max_length = 255, example = "+65")]
    pub phone_country_code: Option<String>,
    /// An arbitrary string that you can attach to a customer object.
    #[schema(max_length = 255, example = "First Customer", value_type = Option<String>)]
    pub description: Option<Description>,
    /// The address for the customer
    #[schema(value_type = Option<AddressDetails>)]
    pub address: Option<payments::AddressDetails>,
    ///  A timestamp (ISO 8601 code) that determines when the customer was created
    #[schema(value_type = PrimitiveDateTime,example = "2023-01-18T11:04:09.922Z")]
    #[serde(with = "custom_serde::iso8601")]
    pub created_at: time::PrimitiveDateTime,
    /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500
    /// characters long. Metadata is useful for storing additional, structured information on an
    /// object.
    #[schema(value_type = Option<Object>,example = json!({ "city": "NY", "unit": "245" }))]
    pub metadata: Option<pii::SecretSerdeValue>,
    /// The identifier for the default payment method.
    #[schema(max_length = 64, example = "pm_djh2837dwduh890123")]
    pub default_payment_method_id: Option<String>,
    /// The customer's tax registration number.
    #[schema(max_length = 255, value_type = Option<String>, example = "123456789")]
    pub tax_registration_id: crypto::OptionalEncryptableSecretString,
}

#[cfg(feature = "v1")]
impl CustomerResponse {
    pub fn get_merchant_reference_id(&self) -> Option<id_type::CustomerId> {
        Some(self.customer_id.clone())
    }
}

#[cfg(feature = "v2")]
#[derive(Debug, Clone, Serialize, ToSchema)]
pub struct CustomerResponse {
    /// Unique identifier for the customer
    #[schema(
        min_length = 32,
        max_length = 64,
        example = "12345_cus_01926c58bc6e77c09e809964e72af8c8",
        value_type = String
    )]
    pub id: id_type::GlobalCustomerId,
    /// The identifier for the customer object
    #[schema(value_type = String, max_length = 64, min_length = 1, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
    pub merchant_reference_id: Option<id_type::CustomerId>,
    /// Connector specific customer reference ids
    #[schema(value_type = Option<Object>, example = json!({"mca_hwySG2NtpzX0qr7toOy8": "cus_Rnm2pDKGyQi506"}))]
    pub connector_customer_ids: Option<common_types::customers::ConnectorCustomerMap>,
    /// The customer's name
    #[schema(max_length = 255, value_type = Option<String>, example = "Jon Test")]
    pub name: crypto::OptionalEncryptableName,
    /// The customer's email address
    #[schema(value_type = Option<String> ,max_length = 255, example = "JonTest@test.com")]
    pub email: crypto::OptionalEncryptableEmail,
    /// The customer's phone number
    #[schema(value_type = Option<String>,max_length = 255, example = "9123456789")]
    pub phone: crypto::OptionalEncryptablePhone,
    /// The country code for the customer phone number
    #[schema(max_length = 255, example = "+65")]
    pub phone_country_code: Option<String>,
    /// An arbitrary string that you can attach to a customer object.
    #[schema(max_length = 255, example = "First Customer", value_type = Option<String>)]
    pub description: Option<Description>,
    /// The default billing address for the customer
    #[schema(value_type = Option<AddressDetails>)]
    pub default_billing_address: Option<payments::AddressDetails>,
    /// The default shipping address for the customer
    #[schema(value_type = Option<AddressDetails>)]
    pub default_shipping_address: Option<payments::AddressDetails>,
    ///  A timestamp (ISO 8601 code) that determines when the customer was created
    #[schema(value_type = PrimitiveDateTime,example = "2023-01-18T11:04:09.922Z")]
    #[serde(with = "custom_serde::iso8601")]
    pub created_at: time::PrimitiveDateTime,
    /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500
    /// characters long. Metadata is useful for storing additional, structured information on an
    /// object.
    #[schema(value_type = Option<Object>,example = json!({ "city": "NY", "unit": "245" }))]
    pub metadata: Option<pii::SecretSerdeValue>,
    /// The identifier for the default payment method.
    #[schema(value_type = Option<String>, max_length = 64, example = "12345_pm_01926c58bc6e77c09e809964e72af8c8")]
    pub default_payment_method_id: Option<id_type::GlobalPaymentMethodId>,
    /// The customer's tax registration number.
    #[schema(max_length = 255, value_type = Option<String>, example = "123456789")]
    pub tax_registration_id: crypto::OptionalEncryptableSecretString,
}

#[cfg(feature = "v2")]
impl CustomerResponse {
    pub fn get_merchant_reference_id(&self) -> Option<id_type::CustomerId> {
        self.merchant_reference_id.clone()
    }
}

#[cfg(feature = "v1")]
#[derive(Debug, Deserialize, Serialize, ToSchema)]
pub struct CustomerDeleteResponse {
    /// The identifier for the customer object
    #[schema(value_type = String, max_length = 255, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
    pub customer_id: id_type::CustomerId,
    /// Whether customer was deleted or not
    #[schema(example = false)]
    pub customer_deleted: bool,
    /// Whether address was deleted or not
    #[schema(example = false)]
    pub address_deleted: bool,
    /// Whether payment methods deleted or not
    #[schema(example = false)]
    pub payment_methods_deleted: bool,
}

#[cfg(feature = "v2")]
#[derive(Debug, Deserialize, Serialize, ToSchema)]
pub struct CustomerDeleteResponse {
    /// Unique identifier for the customer
    #[schema(
        min_length = 32,
        max_length = 64,
        example = "12345_cus_01926c58bc6e77c09e809964e72af8c8",
        value_type = String
    )]
    pub id: id_type::GlobalCustomerId,
    /// The identifier for the customer object
    #[schema(value_type = String, max_length = 255, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
    pub merchant_reference_id: Option<id_type::CustomerId>,
    /// Whether customer was deleted or not
    #[schema(example = false)]
    pub customer_deleted: bool,
    /// Whether address was deleted or not
    #[schema(example = false)]
    pub address_deleted: bool,
    /// Whether payment methods deleted or not
    #[schema(example = false)]
    pub payment_methods_deleted: bool,
}

/// The identifier for the customer object. If not provided the customer ID will be autogenerated.
#[cfg(feature = "v1")]
#[derive(Debug, Default, Clone, Deserialize, Serialize, ToSchema)]
pub struct CustomerUpdateRequest {
    /// The identifier for the Merchant Account
    #[schema(max_length = 255, example = "y3oqhf46pyzuxjbcn2giaqnb44")]
    #[serde(skip)]
    pub merchant_id: id_type::MerchantId,
    /// The customer's name
    #[schema(max_length = 255, value_type = Option<String>, example = "Jon Test")]
    pub name: Option<Secret<String>>,
    /// The customer's email address
    #[schema(value_type = Option<String>, max_length = 255, example = "JonTest@test.com")]
    pub email: Option<pii::Email>,
    /// The customer's phone number
    #[schema(value_type = Option<String>, max_length = 255, example = "9123456789")]
    pub phone: Option<Secret<String>>,
    /// An arbitrary string that you can attach to a customer object.
    #[schema(max_length = 255, example = "First Customer", value_type = Option<String>)]
    pub description: Option<Description>,
    /// The country code for the customer phone number
    #[schema(max_length = 255, example = "+65")]
    pub phone_country_code: Option<String>,
    /// The address for the customer
    #[schema(value_type = Option<AddressDetails>)]
    pub address: Option<payments::AddressDetails>,
    /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500
    /// characters long. Metadata is useful for storing additional, structured information on an
    /// object.
    #[schema(value_type = Option<Object>,example = json!({ "city": "NY", "unit": "245" }))]
    pub metadata: Option<pii::SecretSerdeValue>,
    /// Customer's tax registration ID
    #[schema(max_length = 255, value_type = Option<String>, example = "123456789")]
    pub tax_registration_id: Option<Secret<String>>,
}

#[cfg(feature = "v1")]
impl CustomerUpdateRequest {
    pub fn get_address(&self) -> Option<payments::AddressDetails> {
        self.address.clone()
    }
}

#[cfg(feature = "v2")]
#[derive(Debug, Default, Clone, Deserialize, Serialize, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct CustomerUpdateRequest {
    /// The customer's name
    #[schema(max_length = 255, value_type = String, example = "Jon Test")]
    pub name: Option<Secret<String>>,
    /// The customer's email address
    #[schema(value_type = String, max_length = 255, example = "JonTest@test.com")]
    pub email: Option<pii::Email>,
    /// The customer's phone number
    #[schema(value_type = Option<String>, max_length = 255, example = "9123456789")]
    pub phone: Option<Secret<String>>,
    /// An arbitrary string that you can attach to a customer object.
    #[schema(max_length = 255, example = "First Customer", value_type = Option<String>)]
    pub description: Option<Description>,
    /// The country code for the customer phone number
    #[schema(max_length = 255, example = "+65")]
    pub phone_country_code: Option<String>,
    /// The default billing address for the customer
    #[schema(value_type = Option<AddressDetails>)]
    pub default_billing_address: Option<payments::AddressDetails>,
    /// The default shipping address for the customer
    #[schema(value_type = Option<AddressDetails>)]
    pub default_shipping_address: Option<payments::AddressDetails>,
    /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500
    /// characters long. Metadata is useful for storing additional, structured information on an
    /// object.
    #[schema(value_type = Option<Object>,example = json!({ "city": "NY", "unit": "245" }))]
    pub metadata: Option<pii::SecretSerdeValue>,
    /// The unique identifier of the payment method
    #[schema(value_type = Option<String>, example = "12345_pm_01926c58bc6e77c09e809964e72af8c8")]
    pub default_payment_method_id: Option<id_type::GlobalPaymentMethodId>,
    /// The customer's tax registration number.
    #[schema(max_length = 255, value_type = Option<String>, example = "123456789")]
    pub tax_registration_id: Option<Secret<String>>,
}

#[cfg(feature = "v2")]
impl CustomerUpdateRequest {
    pub fn get_default_customer_billing_address(&self) -> Option<payments::AddressDetails> {
        self.default_billing_address.clone()
    }

    pub fn get_default_customer_shipping_address(&self) -> Option<payments::AddressDetails> {
        self.default_shipping_address.clone()
    }
}

#[cfg(feature = "v1")]
#[derive(Debug, Serialize)]
pub struct CustomerUpdateRequestInternal {
    pub customer_id: id_type::CustomerId,
    pub request: CustomerUpdateRequest,
}

#[cfg(feature = "v2")]
#[derive(Debug, Serialize)]
pub struct CustomerUpdateRequestInternal {
    pub id: id_type::GlobalCustomerId,
    pub request: CustomerUpdateRequest,
}


impl NewUser {
    pub fn get_user_id(&self) -> String {
        self.user_id.clone()
    }

    pub fn get_email(&self) -> UserEmail {
        self.email.clone()
    }

    pub fn get_name(&self) -> Secret<String> {
        self.name.clone().get_secret()
    }

    pub fn get_new_merchant(&self) -> NewUserMerchant {
        self.new_merchant.clone()
    }

    pub fn get_password(&self) -> Option<UserPassword> {
        self.password
            .as_ref()
            .map(|password| password.deref().clone())
    }

    pub async fn insert_user_in_db(
        &self,
        db: &dyn GlobalStorageInterface,
    ) -> UserResult<UserFromStorage> {
        match db.insert_user(self.clone().try_into()?).await {
            Ok(user) => Ok(user.into()),
            Err(e) => {
                if e.current_context().is_db_unique_violation() {
                    Err(e.change_context(UserErrors::UserExists))
                } else {
                    Err(e.change_context(UserErrors::InternalServerError))
                }
            }
        }
        .attach_printable("Error while inserting user")
    }

    pub async fn check_if_already_exists_in_db(&self, state: SessionState) -> UserResult<()> {
        if state
            .global_store
            .find_user_by_email(&self.get_email())
            .await
            .is_ok()
        {
            return Err(report!(UserErrors::UserExists));
        }
        Ok(())
    }

    pub async fn insert_user_and_merchant_in_db(
        &self,
        state: SessionState,
    ) -> UserResult<UserFromStorage> {
        self.check_if_already_exists_in_db(state.clone()).await?;
        let db = state.global_store.as_ref();
        let merchant_id = self.get_new_merchant().get_merchant_id();
        self.new_merchant
            .create_new_merchant_and_insert_in_db(state.clone())
            .await?;
        let created_user = self.insert_user_in_db(db).await;
        if created_user.is_err() {
            let _ = admin::merchant_account_delete(state, merchant_id).await;
        };
        created_user
    }

    pub fn get_no_level_user_role(
        self,
        role_id: String,
        user_status: UserStatus,
    ) -> NewUserRole<NoLevel> {
        let now = common_utils::date_time::now();
        let user_id = self.get_user_id();

        NewUserRole {
            status: user_status,
            created_by: user_id.clone(),
            last_modified_by: user_id.clone(),
            user_id,
            role_id,
            created_at: now,
            last_modified: now,
            entity: NoLevel,
        }
    }

    pub async fn insert_org_level_user_role_in_db(
        self,
        state: SessionState,
        role_id: String,
        user_status: UserStatus,
    ) -> UserResult<UserRole> {
        let org_id = self
            .get_new_merchant()
            .get_new_organization()
            .get_organization_id();

        let org_user_role = self
            .get_no_level_user_role(role_id, user_status)
            .add_entity(OrganizationLevel {
                tenant_id: state.tenant.tenant_id.clone(),
                org_id,
            });

        org_user_role.insert_in_v2(&state).await
    }
}


File: crates/masking/src/serde.rs
 Public functions: 1

//! Serde-related.

pub use erased_serde::Serialize as ErasedSerialize;
pub use serde::{de, Deserialize, Serialize, Serializer};
use serde_json::{value::Serializer as JsonValueSerializer, Value};

use crate::{Secret, Strategy, StrongSecret, ZeroizableSecret};

/// Marker trait for secret types which can be [`Serialize`]-d by [`serde`].
///
/// When the `serde` feature of this crate is enabled and types are marked with
/// this trait, they receive a [`Serialize` impl] for `Secret<T>`.
/// (NOTE: all types which impl `DeserializeOwned` receive a [`Deserialize`]
/// impl)
///
/// This is done deliberately to prevent accidental exfiltration of secrets
/// via `serde` serialization.
#[cfg_attr(docsrs, cfg(feature = "serde"))]
pub trait SerializableSecret: Serialize {}
// #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
// pub trait NonSerializableSecret: Serialize {}

impl SerializableSecret for Value {}
impl SerializableSecret for u8 {}
impl SerializableSecret for u16 {}
impl SerializableSecret for i8 {}
impl SerializableSecret for i32 {}
impl SerializableSecret for i64 {}
impl SerializableSecret for url::Url {}

#[cfg(feature = "time")]
impl SerializableSecret for time::Date {}

impl<T: SerializableSecret> SerializableSecret for &T {}

impl<'de, T, I> Deserialize<'de> for Secret<T, I>
where
    T: Clone + de::DeserializeOwned + Sized,
    I: Strategy<T>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        T::deserialize(deserializer).map(Self::new)
    }
}

impl<T, I> Serialize for Secret<T, I>
where
    T: SerializableSecret + Serialize + Sized,
    I: Strategy<T>,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        pii_serializer::pii_serialize(self, serializer)
    }
}

impl<'de, T, I> Deserialize<'de> for StrongSecret<T, I>
where
    T: Clone + de::DeserializeOwned + Sized + ZeroizableSecret,
    I: Strategy<T>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        T::deserialize(deserializer).map(Self::new)
    }
}

impl<T, I> Serialize for StrongSecret<T, I>
where
    T: SerializableSecret + Serialize + ZeroizableSecret + Sized,
    I: Strategy<T>,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        pii_serializer::pii_serialize(self, serializer)
    }
}

/// Masked serialization.
///
/// the default behaviour for secrets is to serialize in exposed format since the common use cases
/// for storing the secret to database or sending it over the network requires the secret to be exposed
/// This method allows to serialize the secret in masked format if needed for logs or other insecure exposures
pub fn masked_serialize<T: Serialize>(value: &T) -> Result<Value, serde_json::Error> {
    value.serialize(PIISerializer {
        inner: JsonValueSerializer,
    })
}

/// Masked serialization.
///
/// Trait object for supporting serialization to Value while accounting for masking
/// The usual Serde Serialize trait cannot be used as trait objects
/// like &dyn Serialize or boxed trait objects like Box<dyn Serialize> because of Rust's "object safety" rules.
/// In particular, the trait contains generic methods which cannot be made into a trait object.
/// In this case we remove the generic for assuming the serialization to be of 2 types only raw json or masked json
pub trait ErasedMaskSerialize: ErasedSerialize {
    /// Masked serialization.
    fn masked_serialize(&self) -> Result<Value, serde_json::Error>;
}

impl<T: Serialize + ErasedSerialize> ErasedMaskSerialize for T {
    fn masked_serialize(&self) -> Result<Value, serde_json::Error> {
        masked_serialize(self)
    }
}

impl Serialize for dyn ErasedMaskSerialize + '_ {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        erased_serde::serialize(self, serializer)
    }
}

impl Serialize for dyn ErasedMaskSerialize + '_ + Send {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        erased_serde::serialize(self, serializer)
    }
}

use pii_serializer::PIISerializer;

mod pii_serializer {
    use std::fmt::Display;

    pub(super) fn pii_serialize<
        V: Serialize,
        T: std::fmt::Debug + PeekInterface<V>,
        S: Serializer,
    >(
        value: &T,
        serializer: S,
    ) -> Result<S::Ok, S::Error> {
        // Mask the value if the serializer is of type PIISerializer
        // or send empty map if the serializer is of type FlatMapSerializer over PiiSerializer
        if std::any::type_name::<S>() == std::any::type_name::<PIISerializer>() {
            format!("{value:?}").serialize(serializer)
        } else if std::any::type_name::<S>()
            == std::any::type_name::<
                serde::__private::ser::FlatMapSerializer<'_, SerializeMap<PIISerializer>>,
            >()
        {
            std::collections::HashMap::<String, String>::from([]).serialize(serializer)
        } else {
            value.peek().serialize(serializer)
        }
    }

    use serde::{Serialize, Serializer};
    use serde_json::{value::Serializer as JsonValueSerializer, Map, Value};

    use crate::PeekInterface;

    pub(super) struct PIISerializer {
        pub inner: JsonValueSerializer,
    }

    impl Clone for PIISerializer {
        fn clone(&self) -> Self {
            Self {
                inner: JsonValueSerializer,
            }
        }
    }

    impl Serializer for PIISerializer {
        type Ok = Value;
        type Error = serde_json::Error;

        type SerializeSeq = SerializeVec<Self>;
        type SerializeTuple = SerializeVec<Self>;
        type SerializeTupleStruct = SerializeVec<Self>;
        type SerializeTupleVariant = SerializeTupleVariant<Self>;
        type SerializeMap = SerializeMap<Self>;
        type SerializeStruct = SerializeMap<Self>;
        type SerializeStructVariant = SerializeStructVariant<Self>;

        #[inline]
        fn serialize_bool(self, value: bool) -> Result<Self::Ok, Self::Error> {
            self.inner.serialize_bool(value)
        }

        #[inline]
        fn serialize_i8(self, value: i8) -> Result<Self::Ok, Self::Error> {
            self.serialize_i64(value.into())
        }

        #[inline]
        fn serialize_i16(self, value: i16) -> Result<Self::Ok, Self::Error> {
            self.serialize_i64(value.into())
        }

        #[inline]
        fn serialize_i32(self, value: i32) -> Result<Self::Ok, Self::Error> {
            self.serialize_i64(value.into())
        }

        fn serialize_i64(self, value: i64) -> Result<Self::Ok, Self::Error> {
            self.inner.serialize_i64(value)
        }

        fn serialize_i128(self, value: i128) -> Result<Self::Ok, Self::Error> {
            self.inner.serialize_i128(value)
        }

        #[inline]
        fn serialize_u8(self, value: u8) -> Result<Self::Ok, Self::Error> {
            self.serialize_u64(value.into())
        }

        #[inline]
        fn serialize_u16(self, value: u16) -> Result<Self::Ok, Self::Error> {
            self.serialize_u64(value.into())
        }

        #[inline]
        fn serialize_u32(self, value: u32) -> Result<Self::Ok, Self::Error> {
            self.serialize_u64(value.into())
        }

        #[inline]
        fn serialize_u64(self, value: u64) -> Result<Self::Ok, Self::Error> {
            Ok(Value::Number(value.into()))
        }

        fn serialize_u128(self, value: u128) -> Result<Self::Ok, Self::Error> {
            self.inner.serialize_u128(value)
        }

        #[inline]
        fn serialize_f32(self, float: f32) -> Result<Self::Ok, Self::Error> {
            Ok(Value::from(float))
        }

        #[inline]
        fn serialize_f64(self, float: f64) -> Result<Self::Ok, Self::Error> {
            Ok(Value::from(float))
        }

        #[inline]
        fn serialize_char(self, value: char) -> Result<Self::Ok, Self::Error> {
            let mut s = String::new();
            s.push(value);
            Ok(Value::String(s))
        }

        #[inline]
        fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error> {
            Ok(Value::String(value.to_owned()))
        }

        fn serialize_bytes(self, value: &[u8]) -> Result<Self::Ok, Self::Error> {
            let vec = value.iter().map(|&b| Value::Number(b.into())).collect();
            Ok(Value::Array(vec))
        }

        #[inline]
        fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
            Ok(Value::Null)
        }

        #[inline]
        fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
            self.serialize_unit()
        }

        #[inline]
        fn serialize_unit_variant(
            self,
            _name: &'static str,
            _variant_index: u32,
            variant: &'static str,
        ) -> Result<Self::Ok, Self::Error> {
            self.serialize_str(variant)
        }

        #[inline]
        fn serialize_newtype_struct<T>(
            self,
            _name: &'static str,
            value: &T,
        ) -> Result<Self::Ok, Self::Error>
        where
            T: ?Sized + Serialize,
        {
            value.serialize(self)
        }

        fn serialize_newtype_variant<T>(
            self,
            _name: &'static str,
            _variant_index: u32,
            variant: &'static str,
            value: &T,
        ) -> Result<Self::Ok, Self::Error>
        where
            T: ?Sized + Serialize,
        {
            let mut values = Map::new();
            values.insert(String::from(variant), value.serialize(self)?);
            Ok(Value::Object(values))
        }

        #[inline]
        fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
            self.serialize_unit()
        }

        #[inline]
        fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
        where
            T: ?Sized + Serialize,
        {
            value.serialize(self)
        }

        fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
            Ok(SerializeVec {
                vec: Vec::with_capacity(len.unwrap_or(0)),
                ser: self,
            })
        }

        fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
            self.serialize_seq(Some(len))
        }

        fn serialize_tuple_struct(
            self,
            _name: &'static str,
            len: usize,
        ) -> Result<Self::SerializeTupleStruct, Self::Error> {
            self.serialize_seq(Some(len))
        }

        fn serialize_tuple_variant(
            self,
            _name: &'static str,
            _variant_index: u32,
            variant: &'static str,
            len: usize,
        ) -> Result<Self::SerializeTupleVariant, Self::Error> {
            Ok(SerializeTupleVariant {
                name: String::from(variant),
                vec: Vec::with_capacity(len),
                ser: self,
            })
        }

        fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
            Ok(SerializeMap {
                inner: self.clone().inner.serialize_map(len)?,
                ser: self,
            })
        }

        fn serialize_struct(
            self,
            _name: &'static str,
            len: usize,
        ) -> Result<Self::SerializeStruct, Self::Error> {
            self.serialize_map(Some(len))
        }

        fn serialize_struct_variant(
            self,
            _name: &'static str,
            _variant_index: u32,
            variant: &'static str,
            _len: usize,
        ) -> Result<Self::SerializeStructVariant, Self::Error> {
            Ok(SerializeStructVariant {
                name: String::from(variant),
                map: Map::new(),
                ser: self,
            })
        }

        fn collect_str<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
        where
            T: ?Sized + Display,
        {
            self.inner.collect_str(value)
        }
    }

    pub(super) struct SerializeVec<T: Serializer> {
        vec: Vec<Value>,
        ser: T,
    }

    impl<T: Serializer<Ok = Value> + Clone> serde::ser::SerializeSeq for SerializeVec<T> {
        type Ok = Value;
        type Error = T::Error;

        fn serialize_element<V>(&mut self, value: &V) -> Result<(), Self::Error>
        where
            V: ?Sized + Serialize,
        {
            self.vec.push(value.serialize(self.ser.clone())?);
            Ok(())
        }

        fn end(self) -> Result<Self::Ok, Self::Error> {
            Ok(Value::Array(self.vec))
        }
    }

    impl<T: Serializer<Ok = Value> + Clone> serde::ser::SerializeTuple for SerializeVec<T> {
        type Ok = Value;
        type Error = T::Error;

        fn serialize_element<V>(&mut self, value: &V) -> Result<(), Self::Error>
        where
            V: ?Sized + Serialize,
        {
            serde::ser::SerializeSeq::serialize_element(self, value)
        }

        fn end(self) -> Result<Self::Ok, Self::Error> {
            serde::ser::SerializeSeq::end(self)
        }
    }

    impl<T: Serializer<Ok = Value> + Clone> serde::ser::SerializeTupleStruct for SerializeVec<T> {
        type Ok = Value;
        type Error = T::Error;

        fn serialize_field<V>(&mut self, value: &V) -> Result<(), Self::Error>
        where
            V: ?Sized + Serialize,
        {
            serde::ser::SerializeSeq::serialize_element(self, value)
        }

        fn end(self) -> Result<Self::Ok, Self::Error> {
            serde::ser::SerializeSeq::end(self)
        }
    }

    pub(super) struct SerializeStructVariant<T: Serializer> {
        name: String,
        map: Map<String, Value>,
        ser: T,
    }

    impl<T: Serializer<Ok = Value> + Clone> serde::ser::SerializeStructVariant
        for SerializeStructVariant<T>
    {
        type Ok = Value;
        type Error = T::Error;

        fn serialize_field<V>(&mut self, key: &'static str, value: &V) -> Result<(), Self::Error>
        where
            V: ?Sized + Serialize,
        {
            self.map
                .insert(String::from(key), value.serialize(self.ser.clone())?);
            Ok(())
        }

        fn end(self) -> Result<Self::Ok, Self::Error> {
            let mut object = Map::new();

            object.insert(self.name, Value::Object(self.map));

            Ok(Value::Object(object))
        }
    }

    pub(super) struct SerializeTupleVariant<T: Serializer> {
        name: String,
        vec: Vec<Value>,
        ser: T,
    }

    impl<T: Serializer<Ok = Value> + Clone> serde::ser::SerializeTupleVariant
        for SerializeTupleVariant<T>
    {
        type Ok = Value;
        type Error = T::Error;

        fn serialize_field<V>(&mut self, value: &V) -> Result<(), Self::Error>
        where
            V: ?Sized + Serialize,
        {
            self.vec.push(value.serialize(self.ser.clone())?);
            Ok(())
        }

        fn end(self) -> Result<Value, Self::Error> {
            let mut object = Map::new();

            object.insert(self.name, Value::Array(self.vec));

            Ok(Value::Object(object))
        }
    }

    pub(super) struct SerializeMap<T: Serializer> {
        inner: <serde_json::value::Serializer as Serializer>::SerializeMap,
        ser: T,
    }

    impl<T: Serializer<Ok = Value, Error = serde_json::Error> + Clone> serde::ser::SerializeMap
        for SerializeMap<T>
    {
        type Ok = Value;
        type Error = T::Error;

        fn serialize_key<V>(&mut self, key: &V) -> Result<(), Self::Error>
        where
            V: ?Sized + Serialize,
        {
            self.inner.serialize_key(key)?;
            Ok(())
        }

        fn serialize_value<V>(&mut self, value: &V) -> Result<(), Self::Error>
        where
            V: ?Sized + Serialize,
        {
            let value = value.serialize(self.ser.clone())?;
            self.inner.serialize_value(&value)?;
            Ok(())
        }

        fn end(self) -> Result<Value, Self::Error> {
            self.inner.end()
        }
    }

    impl<T: Serializer<Ok = Value, Error = serde_json::Error> + Clone> serde::ser::SerializeStruct
        for SerializeMap<T>
    {
        type Ok = Value;
        type Error = T::Error;

        fn serialize_field<V>(&mut self, key: &'static str, value: &V) -> Result<(), Self::Error>
        where
            V: ?Sized + Serialize,
        {
            serde::ser::SerializeMap::serialize_entry(self, key, value)
        }

        fn end(self) -> Result<Value, Self::Error> {
            serde::ser::SerializeMap::end(self)
        }
    }
}


pub struct TokenizeCreditCard {
    tokenize_credit_card: TokenizeCreditCardData,
}


File: crates/analytics/src/frm/core.rs
 Public functions: 2

#![allow(dead_code)]
use std::collections::HashMap;

use api_models::analytics::{
    frm::{FrmDimensions, FrmMetrics, FrmMetricsBucketIdentifier, FrmMetricsBucketResponse},
    AnalyticsMetadata, FrmFilterValue, FrmFiltersResponse, GetFrmFilterRequest,
    GetFrmMetricRequest, MetricsResponse,
};
use error_stack::ResultExt;
use router_env::{
    logger,
    tracing::{self, Instrument},
};

use super::{
    filters::{get_frm_filter_for_dimension, FrmFilterRow},
    FrmMetricsAccumulator,
};
use crate::{
    errors::{AnalyticsError, AnalyticsResult},
    frm::FrmMetricAccumulator,
    metrics, AnalyticsProvider,
};

pub async fn get_metrics(
    pool: &AnalyticsProvider,
    merchant_id: &common_utils::id_type::MerchantId,
    req: GetFrmMetricRequest,
) -> AnalyticsResult<MetricsResponse<FrmMetricsBucketResponse>> {
    let mut metrics_accumulator: HashMap<FrmMetricsBucketIdentifier, FrmMetricsAccumulator> =
        HashMap::new();
    let mut set = tokio::task::JoinSet::new();
    for metric_type in req.metrics.iter().cloned() {
        let req = req.clone();
        let pool = pool.clone();
        let task_span =
            tracing::debug_span!("analytics_frm_query", frm_metric = metric_type.as_ref());
        // Currently JoinSet works with only static lifetime references even if the task pool does not outlive the given reference
        // We can optimize away this clone once that is fixed
        let merchant_id_scoped = merchant_id.to_owned();
        set.spawn(
            async move {
                let data = pool
                    .get_frm_metrics(
                        &metric_type,
                        &req.group_by_names.clone(),
                        &merchant_id_scoped,
                        &req.filters,
                        req.time_series.map(|t| t.granularity),
                        &req.time_range,
                    )
                    .await
                    .change_context(AnalyticsError::UnknownError);
                (metric_type, data)
            }
            .instrument(task_span),
        );
    }

    while let Some((metric, data)) = set
        .join_next()
        .await
        .transpose()
        .change_context(AnalyticsError::UnknownError)?
    {
        let data = data?;

        let attributes = router_env::metric_attributes!(
            ("metric_type", metric.to_string()),
            ("source", pool.to_string()),
        );
        let value = u64::try_from(data.len());
        if let Ok(val) = value {
            metrics::BUCKETS_FETCHED.record(val, attributes);
            logger::debug!("Attributes: {:?}, Buckets fetched: {}", attributes, val);
        }

        for (id, value) in data {
            logger::debug!(bucket_id=?id, bucket_value=?value, "Bucket row for metric {metric}");
            let metrics_builder = metrics_accumulator.entry(id).or_default();
            match metric {
                FrmMetrics::FrmBlockedRate => {
                    metrics_builder.frm_blocked_rate.add_metrics_bucket(&value)
                }
                FrmMetrics::FrmTriggeredAttempts => metrics_builder
                    .frm_triggered_attempts
                    .add_metrics_bucket(&value),
            }
        }

        logger::debug!(
            "Analytics Accumulated Results: metric: {}, results: {:#?}",
            metric,
            metrics_accumulator
        );
    }
    let query_data: Vec<FrmMetricsBucketResponse> = metrics_accumulator
        .into_iter()
        .map(|(id, val)| FrmMetricsBucketResponse {
            values: val.collect(),
            dimensions: id,
        })
        .collect();

    Ok(MetricsResponse {
        query_data,
        meta_data: [AnalyticsMetadata {
            current_time_range: req.time_range,
        }],
    })
}

pub async fn get_filters(
    pool: &AnalyticsProvider,
    req: GetFrmFilterRequest,
    merchant_id: &common_utils::id_type::MerchantId,
) -> AnalyticsResult<FrmFiltersResponse> {
    let mut res = FrmFiltersResponse::default();
    for dim in req.group_by_names {
        let values = match pool {
            AnalyticsProvider::Sqlx(pool) => {
    get_frm_filter_for_dimension(dim, merchant_id, &req.time_range, pool)
        .await
}
            AnalyticsProvider::Clickhouse(pool) => {
    get_frm_filter_for_dimension(dim, merchant_id, &req.time_range, pool)
        .await
}
        AnalyticsProvider::CombinedCkh(sqlx_pool, ckh_pool) => {
    let ckh_result = get_frm_filter_for_dimension(
        dim,
        merchant_id,
        &req.time_range,
        ckh_pool,
    )
    .await;
    let sqlx_result = get_frm_filter_for_dimension(
        dim,
        merchant_id,
        &req.time_range,
        sqlx_pool,
    )
    .await;
    match (&sqlx_result, &ckh_result) {
        (Ok(ref sqlx_res), Ok(ref ckh_res)) if sqlx_res != ckh_res => {
            logger::error!(clickhouse_result=?ckh_res, postgres_result=?sqlx_res, "Mismatch between clickhouse & postgres frm analytics filters")
        },
        _ => {}
    };
    ckh_result
}
        AnalyticsProvider::CombinedSqlx(sqlx_pool, ckh_pool) => {
    let ckh_result = get_frm_filter_for_dimension(
        dim,
        merchant_id,
        &req.time_range,
        ckh_pool,
    )
    .await;
    let sqlx_result = get_frm_filter_for_dimension(
        dim,
        merchant_id,
        &req.time_range,
        sqlx_pool,
    )
    .await;
    match (&sqlx_result, &ckh_result) {
        (Ok(ref sqlx_res), Ok(ref ckh_res)) if sqlx_res != ckh_res => {
            logger::error!(clickhouse_result=?ckh_res, postgres_result=?sqlx_res, "Mismatch between clickhouse & postgres frm analytics filters")
        },
        _ => {}
    };
    sqlx_result
}
}
        .change_context(AnalyticsError::UnknownError)?
        .into_iter()
        .filter_map(|fil: FrmFilterRow| match dim {
            FrmDimensions::FrmStatus => fil.frm_status.map(|i| i.as_ref().to_string()),
            FrmDimensions::FrmName => fil.frm_name,
            FrmDimensions::FrmTransactionType => {
                fil.frm_transaction_type.map(|i| i.as_ref().to_string())
            }
        })
        .collect::<Vec<String>>();
        res.query_data.push(FrmFilterValue {
            dimension: dim,
            values,
        })
    }
    Ok(res)
}


Documentation: api-reference/v1/customers/customers--delete.mdx
# Type: Doc File

---
openapi: delete /customers/{customer_id}
---


File: crates/router/src/compatibility/stripe/app.rs
 Public functions: 6
 Public structs: 6

use actix_web::{web, Scope};

#[cfg(feature = "v1")]
use super::{customers::*, payment_intents::*, setup_intents::*};
use super::{refunds::*, webhooks::*};
use crate::routes::{self, mandates, webhooks};

pub struct PaymentIntents;

#[cfg(feature = "v1")]
impl PaymentIntents {
    pub fn server(state: routes::AppState) -> Scope {
        let mut route = web::scope("/payment_intents").app_data(web::Data::new(state));
        #[cfg(feature = "olap")]
        {
            route = route.service(web::resource("/list").route(web::get().to(payment_intent_list)))
        }
        route = route
            .service(web::resource("").route(web::post().to(payment_intents_create)))
            .service(
                web::resource("/sync")
                    .route(web::post().to(payment_intents_retrieve_with_gateway_creds)),
            )
            .service(
                web::resource("/{payment_id}")
                    .route(web::get().to(payment_intents_retrieve))
                    .route(web::post().to(payment_intents_update)),
            )
            .service(
                web::resource("/{payment_id}/confirm")
                    .route(web::post().to(payment_intents_confirm)),
            )
            .service(
                web::resource("/{payment_id}/capture")
                    .route(web::post().to(payment_intents_capture)),
            )
            .service(
                web::resource("/{payment_id}/cancel").route(web::post().to(payment_intents_cancel)),
            );
        route
    }
}

pub struct SetupIntents;

#[cfg(feature = "v1")]
impl SetupIntents {
    pub fn server(state: routes::AppState) -> Scope {
        web::scope("/setup_intents")
            .app_data(web::Data::new(state))
            .service(web::resource("").route(web::post().to(setup_intents_create)))
            .service(
                web::resource("/{setup_id}")
                    .route(web::get().to(setup_intents_retrieve))
                    .route(web::post().to(setup_intents_update)),
            )
            .service(
                web::resource("/{setup_id}/confirm").route(web::post().to(setup_intents_confirm)),
            )
    }
}

pub struct Refunds;

impl Refunds {
    pub fn server(config: routes::AppState) -> Scope {
        web::scope("/refunds")
            .app_data(web::Data::new(config))
            .service(web::resource("").route(web::post().to(refund_create)))
            .service(
                web::resource("/sync").route(web::post().to(refund_retrieve_with_gateway_creds)),
            )
            .service(
                web::resource("/{refund_id}")
                    .route(web::get().to(refund_retrieve))
                    .route(web::post().to(refund_update)),
            )
    }
}

pub struct Customers;

#[cfg(feature = "v1")]
impl Customers {
    pub fn server(config: routes::AppState) -> Scope {
        web::scope("/customers")
            .app_data(web::Data::new(config))
            .service(web::resource("").route(web::post().to(customer_create)))
            .service(
                web::resource("/{customer_id}")
                    .route(web::get().to(customer_retrieve))
                    .route(web::post().to(customer_update))
                    .route(web::delete().to(customer_delete)),
            )
            .service(
                web::resource("/{customer_id}/payment_methods")
                    .route(web::get().to(list_customer_payment_method_api)),
            )
    }
}

pub struct Webhooks;

impl Webhooks {
    pub fn server(config: routes::AppState) -> Scope {
        web::scope("/webhooks")
            .app_data(web::Data::new(config))
            .service(
                web::resource("/{merchant_id}/{connector_name}")
                    .route(
                        web::post().to(webhooks::receive_incoming_webhook::<StripeOutgoingWebhook>),
                    )
                    .route(
                        web::get().to(webhooks::receive_incoming_webhook::<StripeOutgoingWebhook>),
                    ),
            )
    }
}

pub struct Mandates;

impl Mandates {
    pub fn server(config: routes::AppState) -> Scope {
        web::scope("/payment_methods")
            .app_data(web::Data::new(config))
            .service(web::resource("/{id}/detach").route(web::post().to(mandates::revoke_mandate)))
    }
}


pub struct BankAccount {
    account_holder: Option<Secret<String>>,
    bank_name: Option<Secret<String>>,
    bic: Option<Secret<String>>,
    iban: Option<Secret<String>>,
}