order_service = $order_service; } /** * Initializes this class's WP hooks. * * @return void */ public function init_hooks() { add_action( 'add_meta_boxes', [ $this, 'maybe_add_meta_box' ] ); } /** * Maybe add the meta box. */ public function maybe_add_meta_box() { // If we cannot get the screen ID, exit. if ( ! function_exists( '\wc_get_page_screen_id' ) ) { return; } // Get the order edit screen to be able to add the meta box to. $wc_screen_id = \wc_get_page_screen_id( 'shop-order' ); add_meta_box( 'wcpay-order-fraud-and-risk-meta-box', __( 'Fraud & Risk', 'woocommerce-payments' ), [ $this, 'display_order_fraud_and_risk_meta_box_message' ], $wc_screen_id, 'side', 'default' ); } /** * Displays the contents of the Fraud & Risk meta box. * * @param \WC_Order $order The order we are working with. * * @return void */ public function display_order_fraud_and_risk_meta_box_message( $order ) { $order = wc_get_order( $order ); if ( ! $order ) { return; } $intent_id = $this->order_service->get_intent_id_for_order( $order ); $charge_id = $this->order_service->get_charge_id_for_order( $order ); $meta_box_type = $this->order_service->get_fraud_meta_box_type_for_order( $order ); $risk_level = $this->order_service->get_charge_risk_level_for_order( $order ); $payment_method = $order->get_payment_method(); if ( strstr( $payment_method, 'woocommerce_payments_' ) ) { $meta_box_type = Fraud_Meta_Box_Type::NOT_CARD; } elseif ( 'woocommerce_payments' !== $payment_method ) { $meta_box_type = Fraud_Meta_Box_Type::NOT_WCPAY; } $icons = [ 'green_check_mark' => [ 'url' => plugins_url( 'assets/images/icons/check-green.svg', WCPAY_PLUGIN_FILE ), 'alt' => __( 'Green check mark', 'woocommerce-payments' ), ], 'orange_shield' => [ 'url' => plugins_url( 'assets/images/icons/shield-stroke-orange.svg', WCPAY_PLUGIN_FILE ), 'alt' => __( 'Orange shield outline', 'woocommerce-payments' ), ], 'red_shield' => [ 'url' => plugins_url( 'assets/images/icons/shield-stroke-red.svg', WCPAY_PLUGIN_FILE ), 'alt' => __( 'Red shield outline', 'woocommerce-payments' ), ], ]; $statuses = [ 'blocked' => __( 'Blocked', 'woocommerce-payments' ), 'approved' => __( 'Approved', 'woocommerce-payments' ), 'held_for_review' => __( 'Held for review', 'woocommerce-payments' ), 'no_action_taken' => __( 'No action taken', 'woocommerce-payments' ), ]; $risk_filters_callout = __( 'Adjust risk filters', 'woocommerce-payments' ); $risk_filters_url = WC_Payments_Admin_Settings::get_settings_url( [ 'anchor' => '%23fp-settings' ] ); $show_adjust_risk_filters_link = true; $this->maybe_print_risk_level_block( $risk_level ); echo '
'; switch ( $meta_box_type ) { case Fraud_Meta_Box_Type::ALLOW: $description = __( 'The payment for this order passed your risk filtering.', 'woocommerce-payments' ); echo '

' . esc_html( $icons['green_check_mark']['alt'] ) . ' ' . esc_html( $statuses['no_action_taken'] ) . '

' . esc_html( $description ) . '

'; break; case Fraud_Meta_Box_Type::BLOCK: $description = __( 'The payment for this order was blocked by your risk filtering. There is no pending authorization, and the order can be cancelled to reduce any held stock.', 'woocommerce-payments' ); $callout = __( 'View more details', 'woocommerce-payments' ); $transaction_url = $this->compose_transaction_url_with_tracking( $order->get_id(), '', Rule::FRAUD_OUTCOME_BLOCK ); echo '

' . esc_html( $icons['red_shield']['alt'] ) . ' ' . esc_html( $statuses['blocked'] ) . '

' . esc_html( $description ) . '

' . esc_html( $callout ) . '

'; break; case Fraud_Meta_Box_Type::NOT_CARD: case Fraud_Meta_Box_Type::NOT_WCPAY: $payment_method_title = $order->get_payment_method_title(); $show_adjust_risk_filters_link = false; if ( ! empty( $payment_method_title ) && 'Popular payment methods' !== $payment_method_title ) { $description = sprintf( /* translators: %1: WooPayments, %2: Payment method title */ __( 'Risk filtering is only available for orders processed using credit cards with %1$s. This order was processed with %2$s.', 'woocommerce-payments' ), 'WooPayments', $payment_method_title ); } else { $description = sprintf( /* translators: %s: WooPayments */ __( 'Risk filtering is only available for orders processed using credit cards with %s.', 'woocommerce-payments' ), 'WooPayments' ); } $callout = __( 'Learn more', 'woocommerce-payments' ); $callout_url = 'https://woocommerce.com/document/woopayments/fraud-and-disputes/fraud-protection/'; $callout_url = add_query_arg( 'status_is', 'fraud-meta-box-not-wcpay-learn-more', $callout_url ); echo '

' . esc_html( $description ) . '

' . esc_html( $callout ) . '

'; break; case Fraud_Meta_Box_Type::PAYMENT_STARTED: $description = __( 'The payment for this order has not yet been passed to the fraud and risk filters to determine its outcome status.', 'woocommerce-payments' ); echo '

' . esc_html( $icons['orange_shield']['alt'] ) . ' ' . esc_html( $statuses['no_action_taken'] ) . '

' . esc_html( $description ) . '

'; break; case Fraud_Meta_Box_Type::REVIEW: $description = __( 'The payment for this order was held for review by your risk filtering. You can review the details and determine whether to approve or block the payment.', 'woocommerce-payments' ); $callout = __( 'Review payment', 'woocommerce-payments' ); $transaction_url = $this->compose_transaction_url_with_tracking( $intent_id, $charge_id, Rule::FRAUD_OUTCOME_REVIEW ); echo '

' . esc_html( $icons['orange_shield']['alt'] ) . ' ' . esc_html( $statuses['held_for_review'] ) . '

' . esc_html( $description ) . '

' . esc_html( $callout ) . '

'; break; case Fraud_Meta_Box_Type::REVIEW_ALLOWED: $description = __( 'The payment for this order was held for review by your risk filtering and manually approved.', 'woocommerce-payments' ); echo '

' . esc_html( $icons['green_check_mark']['alt'] ) . ' ' . esc_html( $statuses['approved'] ) . '

' . esc_html( $description ) . '

'; break; case Fraud_Meta_Box_Type::REVIEW_BLOCKED: $description = __( 'This transaction was held for review by your risk filters, and the charge was manually blocked after review.', 'woocommerce-payments' ); $callout = __( 'Review payment', 'woocommerce-payments' ); $transaction_url = WC_Payments_Utils::compose_transaction_url( $intent_id, $charge_id ); echo '

' . esc_html( $icons['orange_shield']['alt'] ) . ' ' . esc_html( $statuses['held_for_review'] ) . '

' . esc_html( $description ) . '

' . esc_html( $callout ) . '

'; break; case Fraud_Meta_Box_Type::REVIEW_EXPIRED: $description = __( 'The payment for this order was held for review by your risk filtering. The authorization for the charge appears to have expired.', 'woocommerce-payments' ); $callout = __( 'Review payment', 'woocommerce-payments' ); $transaction_url = WC_Payments_Utils::compose_transaction_url( $intent_id, $charge_id ); echo '

' . esc_html( $icons['orange_shield']['alt'] ) . ' ' . esc_html( $statuses['held_for_review'] ) . '

' . esc_html( $description ) . '

' . esc_html( $callout ) . '

'; break; case Fraud_Meta_Box_Type::REVIEW_FAILED: $description = __( 'The payment for this order was held for review by your risk filtering. The authorization for the charge appears to have failed.', 'woocommerce-payments' ); $callout = __( 'Review payment', 'woocommerce-payments' ); $transaction_url = WC_Payments_Utils::compose_transaction_url( $intent_id, $charge_id ); echo '

' . esc_html( $icons['orange_shield']['alt'] ) . ' ' . esc_html( $statuses['held_for_review'] ) . '

' . esc_html( $description ) . '

' . esc_html( $callout ) . '

'; break; case Fraud_Meta_Box_Type::TERMINAL_PAYMENT: $description = __( 'The payment for this order was done in person and has bypassed your risk filtering.', 'woocommerce-payments' ); echo '

' . esc_html( $icons['green_check_mark']['alt'] ) . ' ' . esc_html( $statuses['no_action_taken'] ) . '

' . esc_html( $description ) . '

'; break; default: $description = sprintf( /* translators: %s: WooPayments */ __( 'Risk filtering through %s was not found on this order, it may have been created while filtering was not enabled.', 'woocommerce-payments' ), 'WooPayments' ); echo '

' . esc_html( $description ) . '

'; break; } if ( $show_adjust_risk_filters_link ) { echo '

' . esc_html( $risk_filters_callout ) . '

'; } echo '
'; } /** * Prints the risk level block. * * @param string $risk_level The risk level to display. * * @return void */ private function maybe_print_risk_level_block( $risk_level ) { $valid_risk_levels = [ 'normal', 'elevated', 'highest' ]; if ( ! in_array( $risk_level, $valid_risk_levels, true ) ) { return; } $titles = [ 'normal' => __( 'Normal', 'woocommerce-payments' ), 'elevated' => __( 'Elevated', 'woocommerce-payments' ), 'highest' => __( 'High', 'woocommerce-payments' ), ]; $descriptions = [ 'normal' => __( 'This payment shows a lower than normal risk of fraudulent activity.', 'woocommerce-payments' ), 'elevated' => __( 'This order has a moderate risk of being fraudulent. We suggest contacting the customer to confirm their details before fulfilling it.', 'woocommerce-payments' ), 'highest' => __( 'This order has a high risk of being fraudulent. We suggest contacting the customer to confirm their details before fulfilling it.', 'woocommerce-payments' ), ]; echo '
'; echo '

' . esc_html( $titles[ $risk_level ] ) . '

'; echo '
'; echo '

' . esc_html( $descriptions[ $risk_level ] ) . '

'; echo '
'; } /** * Composes url for transaction details page. * * @param string $primary_id Usually the Payment Intent ID, but can be an order ID. * @param string $fallback_id Usually the Charge ID. * @param string $status The status we're wanting to add to the meta box tracking. * * @return string Transaction details page url with tracking. */ private function compose_transaction_url_with_tracking( $primary_id, $fallback_id, $status ) { return WC_Payments_Utils::compose_transaction_url( $primary_id, $fallback_id, [ 'status_is' => $status, 'type_is' => 'meta_box', ] ); } }