diff --git a/includes/admin/settings/class-wc-settings-checkout.php b/includes/admin/settings/class-wc-settings-checkout.php index 258a4b38444..b6ff2d1206b 100644 --- a/includes/admin/settings/class-wc-settings-checkout.php +++ b/includes/admin/settings/class-wc-settings-checkout.php @@ -45,7 +45,6 @@ class WC_Settings_Payment_Gateways extends WC_Settings_Page { ); if ( ! defined( 'WC_INSTALLING' ) ) { - // Load shipping methods so we can show any global options they may have. $payment_gateways = WC()->payment_gateways->payment_gateways(); foreach ( $payment_gateways as $gateway ) { diff --git a/includes/api/class-wc-rest-payment-gateways-controller.php b/includes/api/class-wc-rest-payment-gateways-controller.php new file mode 100644 index 00000000000..3387debdc9c --- /dev/null +++ b/includes/api/class-wc-rest-payment-gateways-controller.php @@ -0,0 +1,385 @@ + + */ + public function register_routes() { + register_rest_route( $this->namespace, '/' . $this->rest_base, array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_items' ), + 'permission_callback' => array( $this, 'get_items_permissions_check' ), + 'args' => $this->get_collection_params(), + ), + 'schema' => array( $this, 'get_public_item_schema' ), + ) ); + register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\w-]+)', array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_item' ), + 'permission_callback' => array( $this, 'get_item_permissions_check' ), + 'args' => array( + 'context' => $this->get_context_param( array( 'default' => 'view' ) ), + ), + ), + array( + 'methods' => WP_REST_Server::EDITABLE, + 'callback' => array( $this, 'update_item' ), + 'permission_callback' => array( $this, 'update_items_permissions_check' ), + 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), + ), + 'schema' => array( $this, 'get_public_item_schema' ), + ) ); + } + + /** + * Check whether a given request has permission to view payment gateways. + * + * @param WP_REST_Request $request Full details about the request. + * @return WP_Error|boolean + */ + public function get_items_permissions_check( $request ) { + if ( ! wc_rest_check_manager_permissions( 'payment_gateways', 'read' ) ) { + return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); + } + return true; + } + + /** + * Check if a given request has access to read a payment gateway. + * + * @param WP_REST_Request $request Full details about the request. + * @return WP_Error|boolean + */ + public function get_item_permissions_check( $request ) { + if ( ! wc_rest_check_manager_permissions( 'payment_gateways', 'read' ) ) { + return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); + } + return true; + } + + /** + * Check whether a given request has permission to edit payment gateways. + * + * @param WP_REST_Request $request Full details about the request. + * @return WP_Error|boolean + */ + public function update_items_permissions_check( $request ) { + if ( ! wc_rest_check_manager_permissions( 'payment_gateways', 'edit' ) ) { + return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you are not allowed to edit this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); + } + return true; + } + + /** + * Get payment gateways. + * + * @param WP_REST_Request $request Full details about the request. + * @return WP_Error|WP_REST_Response + */ + public function get_items( $request ) { + $this->maybe_define_wp_admin(); + $payment_gateways = WC()->payment_gateways->payment_gateways(); + $response = array(); + foreach ( $payment_gateways as $payment_gateway_id => $payment_gateway ) { + $payment_gateway->id = $payment_gateway_id; + $gateway = $this->prepare_item_for_response( $payment_gateway, $request ); + $gateway = $this->prepare_response_for_collection( $gateway ); + $response[] = $gateway; + } + return rest_ensure_response( $response ); + } + + /** + * Get a single payment gateway. + * + * @param WP_REST_Request $request + * @return WP_REST_Response|WP_Error + */ + public function get_item( $request ) { + $this->maybe_define_wp_admin(); + $gateway = $this->get_gateway( $request ); + + if ( is_null( $gateway ) ) { + return new WP_Error( 'woocommerce_rest_payment_gateway_invalid', __( "Resource doesn't exist.", 'woocommerce' ), array( 'status' => 404 ) ); + } + + $gateway = $this->prepare_item_for_response( $gateway, $request ); + return rest_ensure_response( $gateway ); + } + + /** + * Update A Single Shipping Zone Method. + * + * @param WP_REST_Request $request + * @return WP_REST_Response|WP_Error + */ + public function update_item( $request ) { + $this->maybe_define_wp_admin(); + $gateway = $this->get_gateway( $request ); + + if ( is_null( $gateway ) ) { + return new WP_Error( 'woocommerce_rest_payment_gateway_invalid', __( "Resource doesn't exist.", 'woocommerce' ), array( 'status' => 404 ) ); + } + + // Update settings if present + if ( isset( $request['settings'] ) ) { + $gateway->init_form_fields(); + $settings = $gateway->settings; + foreach ( $gateway->form_fields as $key => $field ) { + if ( isset( $request['settings'][ $key ] ) ) { + $settings[ $key ] = $request['settings'][ $key ]; + } + } + $gateway->settings = $settings; + update_option( $gateway->get_option_key(), apply_filters( 'woocommerce_gateway_' . $gateway->id . '_settings_values', $settings, $gateway ) ); + } + + // Update order + if ( isset( $request['order'] ) ) { + $order = (array) get_option( 'woocommerce_gateway_order' ); + $order[ $gateway->id ] = $request['order']; + update_option( 'woocommerce_gateway_order', $order ); + $gateway->order = absint( $request['order'] ); + } + + // Update if this method is enabled or not. + if ( isset( $request['enabled'] ) ) { + $settings = $gateway->settings; + $gateway->enabled = $settings['enabled'] = (bool) $request['enabled']; + update_option( $gateway->get_option_key(), apply_filters( 'woocommerce_gateway_' . $gateway->id . '_settings_values', $settings, $gateway ) ); + $gateway->settings = $settings; + } + + $gateway = $this->prepare_item_for_response( $gateway, $request ); + return rest_ensure_response( $gateway ); + } + + /** + * Get a gateway based on the current request object. + * + * @param WC_Payment_Gateway $gateway Payment gateway object. + * @return WP_REST_Response|null + */ + public function get_gateway( $request ) { + $gateway = null; + $payment_gateways = WC()->payment_gateways->payment_gateways(); + foreach ( $payment_gateways as $payment_gateway_id => $payment_gateway ) { + if ( $request['id'] !== $payment_gateway_id ) { + continue; + } + $payment_gateway->id = $payment_gateway_id; + $gateway = $payment_gateway; + } + return $gateway; + } + + /** + * Prepare a payment gateway for response. + * + * @param WC_Payment_Gateway $gateway Payment gateway object. + * @param WP_REST_Request $request Request object. + * @return WP_REST_Response $response Response data. + */ + public function prepare_item_for_response( $gateway, $request ) { + $order = (array) get_option( 'woocommerce_gateway_order' ); + $item = array( + 'id' => $gateway->id, + 'title' => $gateway->title, + 'description' => $gateway->description, + 'order' => isset( $order[ $gateway->id ] ) ? $order[ $gateway->id ] : '', + 'enabled' => ( 'yes' === $gateway->enabled ), + 'method_title' => empty( $gateway->method_title ) ? ucfirst( $gateway->id ) : $gateway->method_title, + 'method_description' => $gateway->method_description, + 'settings' => $this->get_settings( $gateway ), + ); + + $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; + $data = $this->add_additional_fields_to_object( $item, $request ); + $data = $this->filter_response_by_context( $item, $context ); + + $response = rest_ensure_response( $item ); + $response->add_links( $this->prepare_links( $gateway, $request ) ); + + /** + * Filter payment gateway objects returned from the REST API. + * + * @param WP_REST_Response $response The response object. + * @param WC_Payment_Gateway $gateway Payment gateway object. + * @param WP_REST_Request $request Request object. + */ + return apply_filters( 'woocommerce_rest_prepare_payment_gateway', $response, $gateway, $request ); + } + + /** + * Return settings associated with this payment gateway. + */ + public function get_settings( $gateway ) { + $settings = array(); + $gateway->init_form_fields(); + foreach ( $gateway->form_fields as $id => $field ) { + // Make sure we at least have a title and type + if ( empty( $field['title'] ) || empty( $field['type'] ) ) { + continue; + } + // Ignore 'title' settings/fields -- they are UI only + if ( 'title' === $field['type'] ) { + continue; + } + $data = array( + 'id' => $id, + 'label' => empty( $field['label'] ) ? $field['title'] : $field['label'], + 'description' => empty( $field['description'] ) ? '' : $field['description'], + 'type' => $field['type'], + 'value' => $gateway->settings[ $id ], + 'default' => empty( $field['default'] ) ? '' : $field['default'], + 'tip' => empty( $field['description'] ) ? '' : $field['description'], + 'placeholder' => empty( $field['placeholder'] ) ? '' : $field['placeholder'], + ); + if ( ! empty( $field['options'] ) ) { + $data['options'] = $field['options']; + } + $settings[ $id ] = $data; + } + return $settings; + } + + /** + * Some form fields (like COD) have a setting to limit to specific shipping + * methods. Some of the code for loading these into settings is behind an + * is_admin check. To work correctly with methods that do this, we can + * define the constant here and act as wp-admin (since these settings are + * shown to managers and admins only anyway). + */ + protected function maybe_define_wp_admin() { + if ( ! defined( 'WP_ADMIN' ) ) { + define( 'WP_ADMIN', true ); + } + } + + /** + * Prepare links for the request. + * + * @param WC_Payment_Gateway $gateway Payment gateway object. + * @param WP_REST_Request $request Request object. + * @return array + */ + protected function prepare_links( $gateway, $request ) { + $links = array( + 'self' => array( + 'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $gateway->id ) ), + ), + 'collection' => array( + 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ), + ), + ); + + return $links; + } + + /** + * Get the payment gateway schema, conforming to JSON Schema. + * + * @return array + */ + public function get_item_schema() { + $schema = array( + '$schema' => 'http://json-schema.org/draft-04/schema#', + 'title' => 'payment_gateway', + 'type' => 'object', + 'properties' => array( + 'id' => array( + 'description' => __( 'Payment gateway ID.', 'woocommerce' ), + 'type' => 'string', + 'context' => array( 'view' ), + ), + 'title' => array( + 'description' => __( 'Payment gateway title on checkout.', 'woocommerce' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'description' => array( + 'description' => __( 'Payment gateway description on checkout.', 'woocommerce' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'order' => array( + 'description' => __( 'Payment gateway sort order.', 'woocommerce' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit' ), + 'arg_options' => array( + 'sanitize_callback' => 'absint', + ), + ), + 'enabled' => array( + 'description' => __( 'Payment gateway enabled status.', 'woocommerce' ), + 'type' => 'boolean', + 'context' => array( 'view', 'edit' ), + ), + 'method_title' => array( + 'description' => __( 'Payment gateway method title.', 'woocommerce' ), + 'type' => 'string', + 'context' => array( 'view' ), + ), + 'method_description' => array( + 'description' => __( 'Payment gateway method description.', 'woocommerce' ), + 'type' => 'string', + 'context' => array( 'view' ), + ), + 'settings' => array( + 'description' => __( 'Payment gateway settings.', 'woocommerce' ), + 'type' => 'array', + 'context' => array( 'view', 'edit' ), + ), + ), + ); + + return $this->add_additional_fields_schema( $schema ); + } + + /** + * Get any query params needed. + * + * @return array + */ + public function get_collection_params() { + return array( + 'context' => $this->get_context_param( array( 'default' => 'view' ) ), + ); + } + +} diff --git a/includes/api/class-wc-rest-settings-options-controller.php b/includes/api/class-wc-rest-settings-options-controller.php index 125c3b8818e..15317fbb592 100644 --- a/includes/api/class-wc-rest-settings-options-controller.php +++ b/includes/api/class-wc-rest-settings-options-controller.php @@ -387,6 +387,8 @@ class WC_REST_Settings_Options_Controller extends WC_REST_Controller { 'arg_options' => array( 'sanitize_callback' => 'sanitize_title', ), + 'context' => array( 'view', 'edit' ), + 'readonly' => true, ), 'label' => array( 'description' => __( 'A human readable translation wrapped label. Meant to be used in interfaces.', 'woocommerce' ), @@ -394,6 +396,8 @@ class WC_REST_Settings_Options_Controller extends WC_REST_Controller { 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), + 'context' => array( 'view', 'edit' ), + 'readonly' => true, ), 'description' => array( 'description' => __( 'A human readable translation wrapped description. Meant to be used in interfaces.', 'woocommerce' ), @@ -401,14 +405,19 @@ class WC_REST_Settings_Options_Controller extends WC_REST_Controller { 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), + 'context' => array( 'view', 'edit' ), + 'readonly' => true, ), 'value' => array( 'description' => __( 'Setting value.', 'woocommerce' ), 'type' => 'mixed', + 'context' => array( 'view', 'edit' ), ), 'default' => array( 'description' => __( 'Default value for the setting.', 'woocommerce' ), 'type' => 'mixed', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, ), 'tip' => array( 'description' => __( 'Extra help text explaining the setting.', 'woocommerce' ), @@ -416,6 +425,8 @@ class WC_REST_Settings_Options_Controller extends WC_REST_Controller { 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), + 'context' => array( 'view', 'edit' ), + 'readonly' => true, ), 'placeholder' => array( 'description' => __( 'Placeholder text to be displayed in text inputs.', 'woocommerce' ), @@ -423,6 +434,8 @@ class WC_REST_Settings_Options_Controller extends WC_REST_Controller { 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), + 'context' => array( 'view', 'edit' ), + 'readonly' => true, ), 'type' => array( 'description' => __( 'Type of setting. Allowed values: text, email, number, color, password, textarea, select, multiselect, radio, image_width, checkbox.', 'woocommerce' ), @@ -430,10 +443,14 @@ class WC_REST_Settings_Options_Controller extends WC_REST_Controller { 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), + 'context' => array( 'view', 'edit' ), + 'readonly' => true, ), 'options' => array( 'description' => __( 'Array of options (key value pairs) for inputs such as select, multiselect, and radio buttons.', 'woocommerce' ), 'type' => 'array', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, ), ), ); diff --git a/includes/api/class-wc-rest-shipping-methods-controller.php b/includes/api/class-wc-rest-shipping-methods-controller.php index 0c290bcab7a..d0f686ef400 100644 --- a/includes/api/class-wc-rest-shipping-methods-controller.php +++ b/includes/api/class-wc-rest-shipping-methods-controller.php @@ -61,7 +61,7 @@ class WC_REST_Shipping_Methods_Controller extends WC_REST_Controller { } /** - * Check whether a given request has permission to view system status. + * Check whether a given request has permission to view shipping methods. * * @param WP_REST_Request $request Full details about the request. * @return WP_Error|boolean @@ -125,9 +125,9 @@ class WC_REST_Shipping_Methods_Controller extends WC_REST_Controller { /** * Prepare a shipping method for response. * - * @param WP_Comment $method Shipping method object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. + * @param WC_Shipping_Method $method Shipping method object. + * @param WP_REST_Request $request Request object. + * @return WP_REST_Response $response Response data. */ public function prepare_item_for_response( $method, $request ) { $data = array( @@ -146,11 +146,11 @@ class WC_REST_Shipping_Methods_Controller extends WC_REST_Controller { $response->add_links( $this->prepare_links( $method, $request ) ); /** - * Filter product reviews object returned from the REST API. + * Filter shipping methods object returned from the REST API. * - * @param WP_REST_Response $response The response object. - * @param Object $method Product review object used to create response. - * @param WP_REST_Request $request Request object. + * @param WP_REST_Response $response The response object. + * @param WC_Shipping_Method $method Shipping method object used to create response. + * @param WP_REST_Request $request Request object. */ return apply_filters( 'woocommerce_rest_prepare_shipping_method', $response, $method, $request ); } @@ -158,9 +158,9 @@ class WC_REST_Shipping_Methods_Controller extends WC_REST_Controller { /** * Prepare links for the request. * - * @param Object $method Shipping method object. - * @param WP_REST_Request $request Request object. - * @return array Links for the given product review. + * @param WC_Shipping_Method $method Shipping method object. + * @param WP_REST_Request $request Request object. + * @return array */ protected function prepare_links( $method, $request ) { $links = array( diff --git a/includes/api/class-wc-rest-shipping-zone-methods-controller.php b/includes/api/class-wc-rest-shipping-zone-methods-controller.php index 6751e14255a..e6a45011379 100644 --- a/includes/api/class-wc-rest-shipping-zone-methods-controller.php +++ b/includes/api/class-wc-rest-shipping-zone-methods-controller.php @@ -385,12 +385,14 @@ class WC_REST_Shipping_Zone_Methods_Controller extends WC_REST_Shipping_Zones_Co 'instance_id' => array( 'description' => __( 'Shipping method instance ID.', 'woocommerce' ), 'type' => 'integer', - 'context' => array( 'view' ), + 'context' => array( 'view', 'edit' ), + 'readonly' => true, ), 'title' => array( 'description' => __( 'Shipping method customer facing title.', 'woocommerce' ), 'type' => 'string', - 'context' => array( 'view' ), + 'context' => array( 'view', 'edit' ), + 'readonly' => true, ), 'order' => array( 'description' => __( 'Shipping method sort order.', 'woocommerce' ), @@ -410,17 +412,19 @@ class WC_REST_Shipping_Zone_Methods_Controller extends WC_REST_Shipping_Zones_Co 'method_id' => array( 'description' => __( 'Shipping method ID. Write on create only.', 'woocommerce' ), 'type' => 'string', - 'context' => array( 'view', 'edit.' ), + 'context' => array( 'view', 'edit' ), ), 'method_title' => array( 'description' => __( 'Shipping method title.', 'woocommerce' ), 'type' => 'string', - 'context' => array( 'view' ), + 'context' => array( 'view', 'edit' ), + 'readonly' => true, ), 'method_description' => array( 'description' => __( 'Shipping method description.', 'woocommerce' ), 'type' => 'string', - 'context' => array( 'view' ), + 'context' => array( 'view', 'edit' ), + 'readonly' => true, ), 'settings' => array( 'description' => __( 'Shipping method settings.', 'woocommerce' ), diff --git a/includes/class-wc-api.php b/includes/class-wc-api.php index 1357a99c037..5823478a503 100644 --- a/includes/class-wc-api.php +++ b/includes/class-wc-api.php @@ -174,6 +174,7 @@ class WC_API extends WC_Legacy_API { include_once( dirname( __FILE__ ) . '/api/class-wc-rest-system-status-controller.php' ); include_once( dirname( __FILE__ ) . '/api/class-wc-rest-system-status-tools-controller.php' ); include_once( dirname( __FILE__ ) . '/api/class-wc-rest-shipping-methods-controller.php' ); + include_once( dirname( __FILE__ ) . '/api/class-wc-rest-payment-gateways-controller.php' ); } /** @@ -213,6 +214,7 @@ class WC_API extends WC_Legacy_API { 'WC_REST_System_Status_Controller', 'WC_REST_System_Status_Tools_Controller', 'WC_REST_Shipping_Methods_Controller', + 'WC_REST_Payment_Gateways_Controller', ); foreach ( $controllers as $controller ) { diff --git a/includes/wc-rest-functions.php b/includes/wc-rest-functions.php index 6acfc381e9a..5867ff09ede 100644 --- a/includes/wc-rest-functions.php +++ b/includes/wc-rest-functions.php @@ -311,6 +311,7 @@ function wc_rest_check_manager_permissions( $object, $context = 'read' ) { 'system_status' => 'manage_woocommerce', 'attributes' => 'manage_product_terms', 'shipping_methods' => 'manage_woocommerce', + 'payment_gateways' => 'manage_woocommerce', ); $permission = current_user_can( $objects[ $object ] ); diff --git a/tests/unit-tests/api/payment-gateways.php b/tests/unit-tests/api/payment-gateways.php new file mode 100644 index 00000000000..9486d2feb6c --- /dev/null +++ b/tests/unit-tests/api/payment-gateways.php @@ -0,0 +1,286 @@ +endpoint = new WC_REST_Payment_Gateways_Controller(); + $this->user = $this->factory->user->create( array( + 'role' => 'administrator', + ) ); + } + + /** + * Test route registration. + * + * @since 2.7.0 + */ + public function test_register_routes() { + $routes = $this->server->get_routes(); + $this->assertArrayHasKey( '/wc/v1/payment_gateways', $routes ); + $this->assertArrayHasKey( '/wc/v1/payment_gateways/(?P[\w-]+)', $routes ); + } + + /** + * Test getting all payment gateways. + * + * @since 2.7.0 + */ + public function test_get_payment_gateways() { + wp_set_current_user( $this->user ); + + $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/payment_gateways' ) ); + $gateways = $response->get_data(); + + $this->assertEquals( 200, $response->get_status() ); + $this->assertContains( array( + 'id' => 'cheque', + 'title' => 'Check Payments', + 'description' => 'Please send a check to Store Name, Store Street, Store Town, Store State / County, Store Postcode.', + 'order' => '', + 'enabled' => true, + 'method_title' => 'Check Payments', + 'method_description' => "Allows check payments. Why would you take checks in this day and age? Well you probably wouldn't but it does allow you to make test purchases for testing order emails and the 'success' pages etc.", + 'settings' => $this->get_settings( 'WC_Gateway_Cheque' ), + '_links' => array( + 'self' => array( + array( + 'href' => rest_url( '/wc/v1/payment_gateways/cheque' ), + ), + ), + 'collection' => array( + array( + 'href' => rest_url( '/wc/v1/payment_gateways' ), + ), + ), + ), + ), $gateways ); + } + + /** + * Tests to make sure payment gateways cannot viewed without valid permissions. + * + * @since 2.7.0 + */ + public function test_get_payment_gateways_without_permission() { + wp_set_current_user( 0 ); + $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/payment_gateways' ) ); + $this->assertEquals( 401, $response->get_status() ); + } + + /** + * Test getting a single payment gateway. + * + * @since 2.7.0 + */ + public function test_get_payment_gateway() { + wp_set_current_user( $this->user ); + + $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/payment_gateways/paypal' ) ); + $paypal = $response->get_data(); + + $this->assertEquals( 200, $response->get_status() ); + $this->assertEquals( array( + 'id' => 'paypal', + 'title' => 'PayPal', + 'description' => "Pay via PayPal; you can pay with your credit card if you don't have a PayPal account.", + 'order' => '', + 'enabled' => true, + 'method_title' => 'PayPal', + 'method_description' => 'PayPal standard sends customers to PayPal to enter their payment information. PayPal IPN requires fsockopen/cURL support to update order statuses after payment. Check the system status page for more details.', + 'settings' => $this->get_settings( 'WC_Gateway_Paypal' ), + ), $paypal ); + } + + /** + * Test getting a payment gateway without valid permissions. + * + * @since 2.7.0 + */ + public function test_get_payment_gateway_without_permission() { + wp_set_current_user( 0 ); + $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/payment_gateways/paypal' ) ); + $this->assertEquals( 401, $response->get_status() ); + } + + /** + * Test getting a payment gateway with an invalid id. + * + * @since 2.7.0 + */ + public function test_get_payment_gateway_invalid_id() { + wp_set_current_user( $this->user ); + $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/payment_gateways/totally_fake_method' ) ); + $this->assertEquals( 404, $response->get_status() ); + } + + /** + * Test updating a single payment gateway. + * + * @since 2.7.0 + */ + public function test_update_payment_gateway() { + wp_set_current_user( $this->user ); + + // Test defaults + $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/payment_gateways/paypal' ) ); + $paypal = $response->get_data(); + + $this->assertEquals( 'PayPal', $paypal['settings']['title']['value'] ); + $this->assertEquals( 'admin@example.org', $paypal['settings']['email']['value'] ); + $this->assertEquals( 'no', $paypal['settings']['testmode']['value'] ); + + // test updating single setting + $request = new WP_REST_Request( 'POST', '/wc/v1/payment_gateways/paypal' ); + $request->set_body_params( array( + 'settings' => array( + 'email' => 'woo@woo.local', + ), + ) ); + $response = $this->server->dispatch( $request ); + $paypal = $response->get_data(); + + $this->assertEquals( 200, $response->get_status() ); + $this->assertEquals( 'PayPal', $paypal['settings']['title']['value'] ); + $this->assertEquals( 'woo@woo.local', $paypal['settings']['email']['value'] ); + $this->assertEquals( 'no', $paypal['settings']['testmode']['value'] ); + + // test updating multiple settings + $request = new WP_REST_Request( 'POST', '/wc/v1/payment_gateways/paypal' ); + $request->set_body_params( array( + 'settings' => array( + 'testmode' => 'yes', + 'title' => 'PayPal - New Title', + ), + ) ); + $response = $this->server->dispatch( $request ); + $paypal = $response->get_data(); + + $this->assertEquals( 200, $response->get_status() ); + $this->assertEquals( 'PayPal - New Title', $paypal['settings']['title']['value'] ); + $this->assertEquals( 'woo@woo.local', $paypal['settings']['email']['value'] ); + $this->assertEquals( 'yes', $paypal['settings']['testmode']['value'] ); + + // Test other parameters, and recheck settings + $request = new WP_REST_Request( 'POST', '/wc/v1/payment_gateways/paypal' ); + $request->set_body_params( array( + 'enabled' => false, + 'order' => 2, + ) ); + $response = $this->server->dispatch( $request ); + $paypal = $response->get_data(); + + $this->assertFalse( $paypal['enabled'] ); + $this->assertEquals( 2, $paypal['order'] ); + $this->assertEquals( 'PayPal - New Title', $paypal['settings']['title']['value'] ); + $this->assertEquals( 'woo@woo.local', $paypal['settings']['email']['value'] ); + $this->assertEquals( 'yes', $paypal['settings']['testmode']['value'] ); + } + + /** + * Test updating a payment gateway without valid permissions. + * + * @since 2.7.0 + */ + public function test_update_payment_gateway_without_permission() { + wp_set_current_user( 0 ); + $request = new WP_REST_Request( 'POST', '/wc/v1/payment_gateways/paypal' ); + $request->set_body_params( array( + 'settings' => array( + 'testmode' => 'yes', + 'title' => 'PayPal - New Title', + ), + ) ); + $response = $this->server->dispatch( $request ); + $this->assertEquals( 401, $response->get_status() ); + } + + /** + * Test updating a payment gateway with an invalid id. + * + * @since 2.7.0 + */ + public function test_update_payment_gateway_invalid_id() { + wp_set_current_user( $this->user ); + $request = new WP_REST_Request( 'POST', '/wc/v1/payment_gateways/totally_fake_method' ); + $request->set_body_params( array( + 'enabled' => true, + ) ); + $response = $this->server->dispatch( $request ); + $this->assertEquals( 404, $response->get_status() ); + } + + /** + * Test the payment gateway schema. + * + * @since 2.7.0 + */ + public function test_payment_gateway_schema() { + wp_set_current_user( $this->user ); + + $request = new WP_REST_Request( 'OPTIONS', '/wc/v1/payment_gateways' ); + $response = $this->server->dispatch( $request ); + $data = $response->get_data(); + $properties = $data['schema']['properties']; + + $this->assertEquals( 8, count( $properties ) ); + $this->assertArrayHasKey( 'id', $properties ); + $this->assertArrayHasKey( 'title', $properties ); + $this->assertArrayHasKey( 'description', $properties ); + $this->assertArrayHasKey( 'order', $properties ); + $this->assertArrayHasKey( 'enabled', $properties ); + $this->assertArrayHasKey( 'method_title', $properties ); + $this->assertArrayHasKey( 'method_description', $properties ); + $this->assertArrayHasKey( 'settings', $properties ); + } + + /** + * Loads a particualr gateway's settings so we can correctly test API output. + * + * @since 2.7.0 + * @param string $gateway_class Name of WC_Payment_Gateway class. + */ + private function get_settings( $gateway_class ) { + if ( ! defined( 'WP_ADMIN' ) ) { + define( 'WP_ADMIN', true ); + } + $gateway = new $gateway_class; + $settings = array(); + $gateway->init_form_fields(); + foreach ( $gateway->form_fields as $id => $field ) { + // Make sure we at least have a title and type + if ( empty( $field['title'] ) || empty( $field['type'] ) ) { + continue; + } + // Ignore 'title' settings/fields -- they are UI only + if ( 'title' === $field['type'] ) { + continue; + } + $data = array( + 'id' => $id, + 'label' => empty( $field['label'] ) ? $field['title'] : $field['label'], + 'description' => empty( $field['description'] ) ? '' : $field['description'], + 'type' => $field['type'], + 'value' => $gateway->settings[ $id ], + 'default' => empty( $field['default'] ) ? '' : $field['default'], + 'tip' => empty( $field['description'] ) ? '' : $field['description'], + 'placeholder' => empty( $field['placeholder'] ) ? '' : $field['placeholder'], + ); + if ( ! empty( $field['options'] ) ) { + $data['options'] = $field['options']; + } + $settings[ $id ] = $data; + } + return $settings; + } + +} diff --git a/tests/unit-tests/api/shipping-methods.php b/tests/unit-tests/api/shipping-methods.php index 4c700cdfee8..da841fcd021 100644 --- a/tests/unit-tests/api/shipping-methods.php +++ b/tests/unit-tests/api/shipping-methods.php @@ -115,7 +115,7 @@ class Shipping_Methods extends WC_REST_Unit_Test_Case { } /** - * Test the product review schema. + * Test the shipping method schema. * * @since 2.7.0 */