service = $service; $this->payments = $payments; $this->invoices = $invoices; $this->presenter = $presenter; } /** * Registers the standard routes and the refund route. * * @since 0.1.0 * * @return void */ public function register_routes() { parent::register_routes(); foreach ( array( 'refund', 'verify', 'reject' ) as $action ) { register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P\d+)/' . $action, array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, $action ), 'permission_callback' => Permissions::require_capability( $this->capability() ), ) ); } } /** * Capability that protects every route. * * @since 0.1.0 * * @return string */ protected function capability(): string { return Capabilities::MANAGE_PAYMENTS; } /** * Arguments of the list route. * * @since 0.1.0 * * @return array> */ protected function collection_args(): array { return array_merge( $this->list_params( array_keys( PaymentRepository::ORDERBY ), 'id' ), array( 'type' => array( 'type' => 'string', 'default' => '', 'enum' => array( '', 'payment', 'refund' ), 'validate_callback' => 'rest_validate_request_arg', ), 'status' => array( 'type' => 'string', 'default' => '', 'enum' => array( '', 'pending', 'completed', 'rejected' ), 'validate_callback' => 'rest_validate_request_arg', ), 'gateway' => array( 'type' => 'string', 'default' => '', 'sanitize_callback' => 'sanitize_text_field', ), 'customer_id' => array( 'type' => 'integer', 'default' => 0, 'sanitize_callback' => 'absint', ), 'invoice_id' => array( 'type' => 'integer', 'default' => 0, 'sanitize_callback' => 'absint', ), ) ); } /** * Lists payments. * * @since 0.1.0 * * @param WP_REST_Request $request Request. * @return array{items: array>, total: int} */ protected function query_items( WP_REST_Request $request ): array { return $this->payments->query( array( 'search' => $request['search'], 'type' => $request['type'], 'status' => $request['status'], 'gateway' => $request['gateway'], 'customer_id' => $request['customer_id'], 'invoice_id' => $request['invoice_id'], 'orderby' => $request['orderby'], 'order' => $request['order'], 'page' => $request['page'], 'per_page' => $request['per_page'], ) ); } /** * Finds one payment. * * @since 0.1.0 * * @param int $id Item id. * @return array|null */ protected function find_item( int $id ): ?array { return $this->payments->find( $id ); } /** * Records a payment and returns the updated invoice. * * @since 0.1.0 * * @param WP_REST_Request $request Request: `invoice_id` plus the payment fields. * @return WP_REST_Response|WP_Error */ public function create_item( $request ) { $body = $this->request_body( $request ); $result = $this->create_resource( $body ); if ( is_wp_error( $result ) ) { return $result; } $response = rest_ensure_response( $this->presenter->detail( $result ) ); $response->set_status( 201 ); return $response; } /** * Refunds a payment and returns the updated invoice. * * @since 0.1.0 * * @param WP_REST_Request $request Request: optional `amount`, `to_credit`, `note`. * @return WP_REST_Response|WP_Error */ public function refund( $request ) { $result = $this->service->refund( (int) $request['id'], $this->request_body( $request ) ); return is_wp_error( $result ) ? $result : rest_ensure_response( $this->presenter->detail( $result ) ); } /** * Confirms a payment a customer reported. * * @since 0.1.0 * * @param WP_REST_Request $request Request. * @return WP_REST_Response|WP_Error */ public function verify( $request ) { $result = $this->service->verify( (int) $request['id'] ); return is_wp_error( $result ) ? $result : rest_ensure_response( $this->presenter->detail( $result ) ); } /** * Rejects a payment a customer reported. * * @since 0.1.0 * * @param WP_REST_Request $request Request: optional `note`. * @return WP_REST_Response|WP_Error */ public function reject( $request ) { $body = $this->request_body( $request ); $result = $this->service->reject( (int) $request['id'], isset( $body['note'] ) && is_string( $body['note'] ) ? $body['note'] : '' ); return is_wp_error( $result ) ? $result : rest_ensure_response( $this->presenter->detail( $result ) ); } /** * Records a payment. * * @since 0.1.0 * * @param array $body Request body. * @return array|WP_Error */ protected function create_resource( array $body ) { $invoice_id = Sanitizer::absint( $body['invoice_id'] ?? 0 ); if ( $invoice_id < 1 ) { return new WP_Error( 'hostkhata_invalid_input', __( 'Choose an invoice.', 'hostkhata' ), array( 'status' => 400, 'errors' => array( 'invoice_id' => __( 'Choose an invoice.', 'hostkhata' ) ), ) ); } return $this->service->record( $invoice_id, $body ); } /** * Payments cannot be edited. * * @since 0.1.0 * * @param int $id Item id. * @param array $body Request body. * @return WP_Error */ protected function update_resource( int $id, array $body ) { return new WP_Error( 'hostkhata_not_editable', __( 'Payments cannot be edited. Refund it and record a new one.', 'hostkhata' ), array( 'status' => 405 ) ); } /** * Payments cannot be deleted. * * @since 0.1.0 * * @param int $id Item id. * @return WP_Error */ protected function delete_resource( int $id ) { return new WP_Error( 'hostkhata_not_deletable', __( 'Payments cannot be deleted. Refund it instead.', 'hostkhata' ), array( 'status' => 405 ) ); } /** * Shapes a payment. * * @since 0.1.0 * * @param array $item Item from the repository. * @return array */ protected function present( array $item ): array { return $this->presenter->payment( $item ); } /** * Message for a payment that does not exist. * * @since 0.1.0 * * @return string */ protected function not_found_message(): string { return __( 'Payment not found.', 'hostkhata' ); } }