ll( 0, count( $ids ), '%d' ) ); $order_meta_table = self::get_meta_table_name(); // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- $order_table_query is autogenerated and should already be prepared. $table_data = $wpdb->get_results( $wpdb->prepare( "$order_table_query WHERE $order_table_alias.id in ( $id_placeholder )", $ids ) ); // phpcs:enable $meta_data_query = $this->get_order_meta_select_statement(); $order_data = array(); $meta_data = $wpdb->get_results( $wpdb->prepare( // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- $meta_data_query and $order_meta_table is autogenerated and should already be prepared. $id_placeholder is already prepared. "$meta_data_query WHERE $order_meta_table.order_id in ( $id_placeholder )", $ids ) ); foreach ( $table_data as $table_datum ) { $id = $table_datum->{"{$order_table_alias}_id"}; $order_data[ $id ] = new \stdClass(); foreach ( $this->get_all_order_column_mappings() as $table_name => $column_mappings ) { $table_alias = $table_aliases[ $table_name ]; // This remapping is required to keep the query length small enough to be supported by implementations such as HyperDB (i.e. fetching some tables in join via alias.*, while others via full name). We can revert this commit if HyperDB starts supporting SRTM for query length more than 3076 characters. foreach ( $column_mappings as $field => $map ) { $field_name = $map['name'] ?? "{$table_name}_$field"; if ( property_exists( $table_datum, $field_name ) ) { $field_value = $table_datum->{ $field_name }; // Unique column, field name is different prop name. } elseif ( property_exists( $table_datum, "{$table_alias}_$field" ) ) { $field_value = $table_datum->{"{$table_alias}_$field"}; // Non-unique column (billing, shipping etc). } else { $field_value = $table_datum->{ $field }; // Unique column, field name is same as prop name. } $order_data[ $id ]->{$field_name} = $field_value; } } $order_data[ $id ]->id = $id; $order_data[ $id ]->meta_data = array(); } foreach ( $meta_data as $meta_datum ) { // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_key, WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- Not a meta query. $order_data[ $meta_datum->order_id ]->meta_data[] = (object) array( 'meta_id' => $meta_datum->id, 'meta_key' => $meta_datum->meta_key, 'meta_value' => $meta_datum->meta_value, ); // phpcs:enable } return $order_data; } /** * Helper method to generate combined select statement. * * @return string Select SQL statement to fetch order. */ private function get_order_table_select_statement() { $order_table = $this::get_orders_table_name(); $order_table_alias = $this->get_order_table_alias(); $billing_address_table_alias = $this->get_address_table_alias( 'billing' ); $shipping_address_table_alias = $this->get_address_table_alias( 'shipping' ); $op_data_table_alias = $this->get_op_table_alias(); $billing_address_clauses = $this->join_billing_address_table_to_order_query( $order_table_alias, $billing_address_table_alias ); $shipping_address_clauses = $this->join_shipping_address_table_to_order_query( $order_table_alias, $shipping_address_table_alias ); $operational_data_clauses = $this->join_operational_data_table_to_order_query( $order_table_alias, $op_data_table_alias ); /** * We fully spell out address table columns because they have duplicate columns for billing and shipping and would be overwritten if we don't spell them out. There is not such duplication in the operational data table and orders table, so select with `alias`.* is fine. * We do spell ID columns manually, as they are duplicate. */ return " SELECT $order_table_alias.id as o_id, $op_data_table_alias.id as p_id, $order_table_alias.*, {$billing_address_clauses['select']}, {$shipping_address_clauses['select']}, $op_data_table_alias.* FROM $order_table $order_table_alias LEFT JOIN {$billing_address_clauses['join']} LEFT JOIN {$shipping_address_clauses['join']} LEFT JOIN {$operational_data_clauses['join']} "; } /** * Helper function to generate select statement for fetching metadata in bulk. * * @return string Select SQL statement to fetch order metadata. */ private function get_order_meta_select_statement() { $order_meta_table = self::get_meta_table_name(); return " SELECT $order_meta_table.id, $order_meta_table.order_id, $order_meta_table.meta_key, $order_meta_table.meta_value FROM $order_meta_table "; } /** * Helper method to generate join query for billing addresses in wc_address table. * * @param string $order_table_alias Alias for order table to use in join. * @param string $address_table_alias Alias for address table to use in join. * * @return array Select and join statements for billing address table. */ private function join_billing_address_table_to_order_query( $order_table_alias, $address_table_alias ) { return $this->join_address_table_order_query( 'billing', $order_table_alias, $address_table_alias ); } /** * Helper method to generate join query for shipping addresses in wc_address table. * * @param string $order_table_alias Alias for order table to use in join. * @param string $address_table_alias Alias for address table to use in join. * * @return array Select and join statements for shipping address table. */ private function join_shipping_address_table_to_order_query( $order_table_alias, $address_table_alias ) { return $this->join_address_table_order_query( 'shipping', $order_table_alias, $address_table_alias ); } /** * Helper method to generate join and select query for address table. * * @param string $address_type Type of address; 'billing' or 'shipping'. * @param string $order_table_alias Alias of order table to use. * @param string $address_table_alias Alias for address table to use. * * @return array Select and join statements for address table. */ private function join_address_table_order_query( $address_type, $order_table_alias, $address_table_alias ) { global $wpdb; $address_table = $this::get_addresses_table_name(); $column_props_map = 'billing' === $address_type ? $this->billing_address_column_mapping : $this->shipping_address_column_mapping; $clauses = $this->generate_select_and_join_clauses( $order_table_alias, $address_table, $address_table_alias, $column_props_map ); // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $clauses['join'] and $address_table_alias are hardcoded. $clauses['join'] = $wpdb->prepare( "{$clauses['join']} AND $address_table_alias.address_type = %s", $address_type ); // phpcs:enable return array( 'select' => $clauses['select'], 'join' => $clauses['join'], ); } /** * Helper method to join order operational data table. * * @param string $order_table_alias Alias to use for order table. * @param string $operational_table_alias Alias to use for operational data table. * * @return array Select and join queries for operational data table. */ private function join_operational_data_table_to_order_query( $order_table_alias, $operational_table_alias ) { $operational_data_table = $this::get_operational_data_table_name(); return $this->generate_select_and_join_clauses( $order_table_alias, $operational_data_table, $operational_table_alias, $this->operational_data_column_mapping ); } /** * Helper method to generate join and select clauses. * * @param string $order_table_alias Alias for order table. * @param string $table Table to join. * @param string $table_alias Alias for table to join. * @param array[] $column_props_map Column to prop map for table to join. * * @return array Select and join queries. */ private function generate_select_and_join_clauses( $order_table_alias, $table, $table_alias, $column_props_map ) { // Add aliases to column names so they will be unique when fetching. $select_clause = $this->generate_select_clause_for_props( $table_alias, $column_props_map ); $join_clause = "$table $table_alias ON $table_alias.order_id = $order_table_alias.id"; return array( 'select' => $select_clause, 'join' => $join_clause, ); } /** * Helper method to generate select clause for props. * * @param string $table_alias Alias for table. * @param array[] $props Props to column mapping for table. * * @return string Select clause. */ private function generate_select_clause_for_props( $table_alias, $props ) { $select_clauses = array(); foreach ( $props as $column_name => $prop_details ) { $select_clauses[] = isset( $prop_details['name'] ) ? "$table_alias.$column_name as {$prop_details['name']}" : "$table_alias.$column_name as {$table_alias}_$column_name"; } return implode( ', ', $select_clauses ); } /** * Persists order changes to the database. * * @param \WC_Abstract_Order $order The order. * @param bool $force_all_fields Force saving all fields to DB and just changed. * * @throws \Exception If order data is not valid. * * @since 6.8.0 */ protected function persist_order_to_db( &$order, bool $force_all_fields = false ) { $context = ( 0 === absint( $order->get_id() ) ) ? 'create' : 'update'; if ( 'create' === $context ) { $post_id = $this->maybe_create_backup_post( $order, 'create' ); if ( ! $post_id ) { throw new \Exception( esc_html__( 'Could not create order in posts table.', 'woocommerce' ) ); } $order->set_id( $post_id ); } $only_changes = ! $force_all_fields && 'update' === $context; // Figure out what needs to be updated in the database. $db_updates = $this->get_db_rows_for_order( $order, $context, $only_changes ); // Persist changes. foreach ( $db_updates as $update ) { // Make sure 'data' and 'format' entries match before passing to $wpdb. ksort( $update['data'] ); ksort( $update['format'] ); $result = $this->database_util->insert_on_duplicate_key_update( $update['table'], $update['data'], array_values( $update['format'] ) ); if ( false === $result ) { // translators: %s is a table name. throw new \Exception( esc_html( sprintf( __( 'Could not persist order to database table "%s".', 'woocommerce' ), $update['table'] ) ) ); } } $changes = $order->get_changes(); $this->update_address_index_meta( $order, $changes ); $default_taxonomies = $this->init_default_taxonomies( $order, array() ); $this->set_custom_taxonomies( $order, $default_taxonomies ); } /** * Takes care of creating the backup post in the posts table (placeholder or actual order post, depending on sync settings). * * @since 8.8.0 * * @param \WC_Abstract_Order $order The order. * @param string $context The context: either 'create' or 'backfill'. * @return int The new post ID. */ protected function maybe_create_backup_post( &$order, string $context ): int { $data_sync = wc_get_container()->get( DataSynchronizer::class ); $data = array( 'post_type' => $data_sync->data_sync_is_enabled() ? $order->get_type() : $data_sync::PLACEHOLDER_ORDER_POST_TYPE, 'post_status' => 'draft', 'post_parent' => $order->get_changes()['parent_id'] ?? $order->get_data()['parent_id'] ?? 0, 'post_date' => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getOffsetTimestamp() ), 'post_date_gmt' => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ), ); if ( 'backfill' === $context ) { if ( ! $order->get_id() ) { return 0; } $data['import_id'] = $order->get_id(); } return wp_insert_post( $data ); } /** * Set default taxonomies for the order. * * Note: This is re-implementation of part of WP core's `wp_insert_post` function. Since the code block that set default taxonomies is not filterable, we have to re-implement it. * * @param \WC_Abstract_Order $order Order object. * @param array $sanitized_tax_input Sanitized taxonomy input. * * @return array Sanitized tax input with default taxonomies. */ public function init_default_taxonomies( \WC_Abstract_Order $order, array $sanitized_tax_input ) { if ( 'auto-draft' === $order->get_status() ) { return $sanitized_tax_input; } foreach ( get_object_taxonomies( $order->get_type(), 'object' ) as $taxonomy => $tax_object ) { if ( empty( $tax_object->default_term ) ) { return $sanitized_tax_input; } // Filter out empty terms. if ( isset( $sanitized_tax_input[ $taxonomy ] ) && is_array( $sanitized_tax_input[ $taxonomy ] ) ) { $sanitized_tax_input[ $taxonomy ] = array_filter( $sanitized_tax_input[ $taxonomy ] ); } // Passed custom taxonomy list overwrites the existing list if not empty. $terms = wp_get_object_terms( $order->get_id(), $taxonomy, array( 'fields' => 'ids' ) ); if ( ! empty( $terms ) && empty( $sanitized_tax_input[ $taxonomy ] ) ) { $sanitized_tax_input[ $taxonomy ] = $terms; } if ( empty( $sanitized_tax_input[ $taxonomy ] ) ) { $default_term_id = get_option( 'default_term_' . $taxonomy ); if ( ! empty( $default_term_id ) ) { $sanitized_tax_input[ $taxonomy ] = array( (int) $default_term_id ); } } } return $sanitized_tax_input; } /** * Set custom taxonomies for the order. * * Note: This is re-implementation of part of WP core's `wp_insert_post` function. Since the code block that set custom taxonomies is not filterable, we have to re-implement it. * * @param \WC_Abstract_Order $order Order object. * @param array $sanitized_tax_input Sanitized taxonomy input. * * @return void */ public function set_custom_taxonomies( \WC_Abstract_Order $order, array $sanitized_tax_input ) { if ( empty( $sanitized_tax_input ) ) { return; } foreach ( $sanitized_tax_input as $taxonomy => $tags ) { $taxonomy_obj = get_taxonomy( $taxonomy ); if ( ! $taxonomy_obj ) { /* translators: %s: Taxonomy name. */ _doing_it_wrong( __FUNCTION__, esc_html( sprintf( __( 'Invalid taxonomy: %s.', 'woocommerce' ), $taxonomy ) ), '7.9.0' ); continue; } // array = hierarchical, string = non-hierarchical. if ( is_array( $tags ) ) { $tags = array_filter( $tags ); } if ( current_user_can( $taxonomy_obj->cap->assign_terms ) ) { wp_set_post_terms( $order->get_id(), $tags, $taxonomy ); } } } /** * Generates an array of rows with all the details required to insert or update an order in the database. * * @param \WC_Abstract_Order $order The order. * @param string $context The context: 'create' or 'update'. * @param boolean $only_changes Whether to consider only changes in the order for generating the rows. * * @return array * @throws \Exception When invalid data is found for the given context. * * @since 6.8.0 */ protected function get_db_rows_for_order( \WC_Abstract_Order $order, string $context = 'create', bool $only_changes = false ): array { $result = array(); $row = $this->get_db_row_from_order( $order, $this->order_column_mapping, $only_changes ); if ( 'create' === $context && ! $row ) { throw new \Exception( 'No data for new record.' ); // This shouldn't occur. } if ( $row ) { $result[] = array( 'table' => self::get_orders_table_name(), 'data' => array_merge( $row['data'], array( 'id' => $order->get_id(), 'type' => $order->get_type(), ) ), 'format' => array_merge( $row['format'], array( 'id' => '%d', 'type' => '%s', ) ), ); } // wc_order_operational_data. $row = $this->get_db_row_from_order( $order, $this->operational_data_column_mapping, $only_changes ); if ( $row ) { $result[] = array( 'table' => self::get_operational_data_table_name(), 'data' => array_merge( $row['data'], array( 'order_id' => $order->get_id() ) ), 'format' => array_merge( $row['format'], array( 'order_id' => '%d' ) ), ); } // wc_order_addresses. foreach ( array( 'billing', 'shipping' ) as $address_type ) { $row = $this->get_db_row_from_order( $order, $this->{$address_type . '_address_column_mapping'}, $only_changes ); if ( $row ) { $result[] = array( 'table' => self::get_addresses_table_name(), 'data' => array_merge( $row['data'], array( 'order_id' => $order->get_id(), 'address_type' => $address_type, ) ), 'format' => array_merge( $row['format'], array( 'order_id' => '%d', 'address_type' => '%s', ) ), ); } } /** * Allow third parties to include rows that need to be inserted/updated in custom tables when persisting an order. * * @since 6.8.0 * * @param array Array of rows to be inserted/updated when persisting an order. Each entry should be an array with * keys 'table', 'data' (the row), 'format' (row format), 'where' and 'where_format'. * @param \WC_Order The order object. * @param string The context of the operation: 'create' or 'update'. */ $ext_rows = apply_filters( 'woocommerce_orders_table_datastore_extra_db_rows_for_order', array(), $order, $context ); /** * Filters the rows that are going to be inserted or updated during an order save. * * @since 8.8.0 * @internal Use 'woocommerce_orders_table_datastore_extra_db_rows_for_order' for adding rows to the database save. * * @param array $rows Array of rows to be inserted/updated. See 'woocommerce_orders_table_datastore_extra_db_rows_for_order' for exact format. * @param \WC_Order $order The order object. * @param string $context The context of the operation: 'create' or 'update'. */ $result = apply_filters( 'woocommerce_orders_table_datastore_db_rows_for_order', array_merge( $result, $ext_rows ), $order, $context ); return $result; } /** * Produces an array with keys 'row' and 'format' that can be passed to `$wpdb->update()` as the `$data` and * `$format` parameters. Values are taken from the order changes array and properly formatted for inclusion in the * database. * * @param \WC_Abstract_Order $order Order. * @param array $column_mapping Table column mapping. * @param bool $only_changes Whether to consider only changes in the order object or all fields. * @return array * * @since 6.8.0 */ protected function get_db_row_from_order( $order, $column_mapping, $only_changes = false ) { $changes = $only_changes ? $order->get_changes() : array_merge( $order->get_data(), $order->get_changes() ); // Make sure 'status' is correctly prefixed. if ( array_key_exists( 'status', $column_mapping ) && array_key_exists( 'status', $changes ) ) { $changes['status'] = $this->get_post_status( $order ); } $row = array(); $row_format = array(); foreach ( $column_mapping as $column => $details ) { if ( ! isset( $details['name'] ) || ! array_key_exists( $details['name'], $changes ) ) { continue; } $row[ $column ] = $this->database_util->format_object_value_for_db( $changes[ $details['name'] ], $details['type'] ); $row_format[ $column ] = $this->database_util->get_wpdb_format_for_type( $details['type'] ); } if ( ! $row ) { return false; } return array( 'data' => $row, 'format' => $row_format, ); } /** * Method to delete an order from the database. * * @param \WC_Abstract_Order $order Order object. * @param array $args Array of args to pass to the delete method. * * @return void */ public function delete( &$order, $args = array() ) { $order_id = $order->get_id(); if ( ! $order_id ) { return; } $args = wp_parse_args( $args, array( 'force_delete' => false, 'suppress_filters' => false, ) ); $do_filters = ! $args['suppress_filters']; if ( $args['force_delete'] ) { if ( $do_filters ) { /** * Fires immediately before an order is deleted from the database. * * @since 7.1.0 * * @param int $order_id ID of the order about to be deleted. * @param WC_Order $order Instance of the order that is about to be deleted. */ do_action( 'woocommerce_before_delete_order', $order_id, $order ); } $this->upshift_or_delete_child_orders( $order ); $this->delete_order_data_from_custom_order_tables( $order_id ); $this->delete_items( $order ); $order->set_id( 0 ); /** We can delete the post data if: * 1. The HPOS table is authoritative and synchronization is enabled. * 2. The post record is of type `shop_order_placehold`, since this is created by the HPOS in the first place. * * In other words, we do not delete the post record when HPOS table is authoritative and synchronization is disabled but post record is a full record and not just a placeholder, because it implies that the order was created before HPOS was enabled. */ $orders_table_is_authoritative = $order->get_data_store()->get_current_class_name() === self::class; if ( $orders_table_is_authoritative ) { $data_synchronizer = wc_get_container()->get( DataSynchronizer::class ); if ( $data_synchronizer->data_sync_is_enabled() ) { // Delete the associated post, which in turn deletes order items, etc. through {@see WC_Post_Data}. // Once we stop creating posts for orders, we should do the cleanup here instead. wp_delete_post( $order_id ); } else { $this->handle_order_deletion_with_sync_disabled( $order_id ); } } if ( $do_filters ) { /** * Fires immediately after an order is deleted. * * @since 2.7.0 * * @param int $order_id ID of the order that has been deleted. */ do_action( 'woocommerce_delete_order', $order_id ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment } } else { if ( $do_filters ) { /** * Fires immediately before an order is trashed. * * @since 7.1.0 * * @param int $order_id ID of the order about to be trashed. * @param WC_Order $order Instance of the order that is about to be trashed. */ do_action( 'woocommerce_before_trash_order', $order_id, $order ); } $this->trash_order( $order ); if ( $do_filters ) { /** * Fires immediately after an order is trashed. * * @since 2.7.0 * * @param int $order_id ID of the order that has been trashed. */ do_action( 'woocommerce_trash_order', $order_id ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment } } } /** * Handles the deletion of an order from the orders table when sync is disabled: * * If the corresponding row in the posts table is of placeholder type, * it's just deleted; otherwise a "deleted_from" record is created in the meta table * and the sync process will detect these and take care of deleting the appropriate post records. * * @param int $order_id Th id of the order that has been deleted from the orders table. * @return void */ protected function handle_order_deletion_with_sync_disabled( $order_id ): void { global $wpdb; $post_type = $wpdb->get_var( $wpdb->prepare( "SELECT post_type FROM {$wpdb->posts} WHERE ID=%d", $order_id ) ); if ( DataSynchronizer::PLACEHOLDER_ORDER_POST_TYPE === $post_type ) { $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->posts} WHERE ID=%d OR post_parent=%d", $order_id, $order_id ) ); } else { // phpcs:disable WordPress.DB.SlowDBQuery $wpdb->insert( self::get_meta_table_name(), array( 'order_id' => $order_id, 'meta_key' => DataSynchronizer::DELETED_RECORD_META_KEY, 'meta_value' => DataSynchronizer::DELETED_FROM_ORDERS_META_VALUE, ) ); // phpcs:enable WordPress.DB.SlowDBQuery // Note that at this point upshift_or_delete_child_orders will already have been invoked, // thus all the child orders either still exist but have a different parent id, // or have been deleted and got their own deletion record already. // So there's no need to do anything about them. } } /** * Set the parent id of child orders to the parent order's parent if the post type * for the order is hierarchical, just delete the child orders otherwise. * * @param \WC_Abstract_Order $order Order object. * * @return void */ private function upshift_or_delete_child_orders( $order ): void { global $wpdb; $order_table = self::get_orders_table_name(); $order_parent_id = $order->get_parent_id(); if ( $this->legacy_proxy->call_function( 'is_post_type_hierarchical', $order->get_type() ) ) { $wpdb->update( $order_table, array( 'parent_order_id' => $order_parent_id ), array( 'parent_order_id' => $order->get_id() ), array( '%d' ), array( '%d' ) ); } else { // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared $child_order_ids = $wpdb->get_col( $wpdb->prepare( "SELECT id FROM $order_table WHERE parent_order_id=%d", $order->get_id() ) ); // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared foreach ( $child_order_ids as $child_order_id ) { $child_order = wc_get_order( $child_order_id ); if ( $child_order ) { $child_order->delete( true ); } } } } /** * Trashes an order. * * @param WC_Order $order The order object. * * @return void */ public function trash_order( $order ) { global $wpdb; if ( 'trash' === $order->get_status( 'edit' ) ) { return; } $trash_metadata = array( '_wp_trash_meta_status' => 'wc-' . $order->get_status( 'edit' ), '_wp_trash_meta_time' => time(), ); $wpdb->update( self::get_orders_table_name(), array( 'status' => 'trash', 'date_updated_gmt' => current_time( 'Y-m-d H:i:s', true ), ), array( 'id' => $order->get_id() ), array( '%s', '%s' ), array( '%d' ) ); $order->set_status( 'trash' ); foreach ( $trash_metadata as $meta_key => $meta_value ) { $this->add_meta( $order, (object) array( 'key' => $meta_key, 'value' => $meta_value, ) ); } $data_synchronizer = wc_get_container()->get( DataSynchronizer::class ); if ( $data_synchronizer->data_sync_is_enabled() ) { wp_trash_post( $order->get_id() ); } } /** * Attempts to restore the specified order back to its original status (after having been trashed). * * @param WC_Order $order The order to be untrashed. * * @return bool If the operation was successful. */ public function untrash_order( WC_Order $order ): bool { $id = $order->get_id(); $status = $order->get_status(); if ( 'trash' !== $status ) { wc_get_logger()->warning( sprintf( /* translators: 1: order ID, 2: order status */ __( 'Order %1$d cannot be restored from the trash: it has already been restored to status "%2$s".', 'woocommerce' ), $id, $status ) ); return false; } $previous_status = $order->get_meta( '_wp_trash_meta_status' ); $valid_statuses = wc_get_order_statuses(); $previous_state_is_invalid = ! array_key_exists( $previous_status, $valid_statuses ); $pending_is_valid_status = array_key_exists( 'wc-pending', $valid_statuses ); if ( $previous_state_is_invalid && $pending_is_valid_status ) { // If the previous status is no longer valid, let's try to restore it to "pending" instead. wc_get_logger()->warning( sprintf( /* translators: 1: order ID, 2: order status */ __( 'The previous status of order %1$d ("%2$s") is invalid. It has been restored to "pending" status instead.', 'woocommerce' ), $id, $previous_status ) ); $previous_status = 'pending'; } elseif ( $previous_state_is_invalid ) { // If we cannot restore to pending, we should probably stand back and let the merchant intervene some other way. wc_get_logger()->warning( sprintf( /* translators: 1: order ID, 2: order status */ __( 'The previous status of order %1$d ("%2$s") is invalid. It could not be restored.', 'woocommerce' ), $id, $previous_status ) ); return false; } /** * Fires before an order is restored from the trash. * * @since 7.2.0 * * @param int $order_id Order ID. * @param string $previous_status The status of the order before it was trashed. */ do_action( 'woocommerce_untrash_order', $order->get_id(), $previous_status ); $order->set_status( $previous_status ); $order->save(); // Was the status successfully restored? Let's clean up the meta and indicate success... if ( 'wc-' . $order->get_status() === $previous_status ) { $order->delete_meta_data( '_wp_trash_meta_status' ); $order->delete_meta_data( '_wp_trash_meta_time' ); $order->delete_meta_data( '_wp_trash_meta_comments_status' ); $order->save_meta_data(); return true; } // ...Or log a warning and bail. wc_get_logger()->warning( sprintf( /* translators: 1: order ID, 2: order status */ __( 'Something went wrong when trying to restore order %d from the trash. It could not be restored.', 'woocommerce' ), $id ) ); return false; } /** * Deletes order data from custom order tables. * * @param int $order_id The order ID. * @return void */ public function delete_order_data_from_custom_order_tables( $order_id ) { global $wpdb; $order_cache = wc_get_container()->get( OrderCache::class ); // Delete COT-specific data. foreach ( $this->get_all_table_names() as $table ) { $wpdb->delete( $table, ( self::get_orders_table_name() === $table ) ? array( 'id' => $order_id ) : array( 'order_id' => $order_id ), array( '%d' ) ); $order_cache->remove( $order_id ); } } /** * Method to create an order in the database. * * @param \WC_Order $order Order object. */ public function create( &$order ) { if ( '' === $order->get_order_key() ) { $order->set_order_key( wc_generate_order_key() ); } $this->persist_save( $order ); // Do not fire 'woocommerce_new_order' for draft statuses for backwards compatibility. if ( 'auto-draft' === $order->get_status( 'edit' ) ) { return; } /** * Fires when a new order is created. * * @since 2.7.0 * * @param int Order ID. * @param \WC_Order Order object. */ do_action( 'woocommerce_new_order', $order->get_id(), $order ); } /** * Helper method responsible for persisting new data to order table. * * This should not contain and specific meta or actions, so that it can be used other order types safely. * * @param \WC_Order $order Order object. * @param bool $force_all_fields Force update all fields, instead of calculating and updating only changed fields. * @param bool $backfill Whether to backfill data to post datastore. * * @return void * * @throws \Exception When unable to save data. */ protected function persist_save( &$order, bool $force_all_fields = false, $backfill = true ) { $order->set_version( Constants::get_constant( 'WC_VERSION' ) ); $order->set_currency( $order->get_currency() ? $order->get_currency() : get_woocommerce_currency() ); if ( ! $order->get_date_created( 'edit' ) ) { $order->set_date_created( time() ); } if ( ! $order->get_date_modified( 'edit' ) ) { $order->set_date_modified( current_time( 'mysql' ) ); } $this->persist_order_to_db( $order, $force_all_fields ); $this->update_order_meta( $order ); $order->save_meta_data(); $order->apply_changes(); if ( $backfill ) { self::$backfilling_order_ids[] = $order->get_id(); $r_order = wc_get_order( $order->get_id() ); // Refresh order to account for DB changes from post hooks. $this->maybe_backfill_post_record( $r_order ); self::$backfilling_order_ids = array_diff( self::$backfilling_order_ids, array( $order->get_id() ) ); } $this->clear_caches( $order ); } /** * Method to update an order in the database. * * @param \WC_Order $order Order object. */ public function update( &$order ) { $previous_status = ArrayUtil::get_value_or_default( $order->get_data(), 'status' ); $changes = $order->get_changes(); // Before updating, ensure date paid is set if missing. if ( ! $order->get_date_paid( 'edit' ) && version_compare( $order->get_version( 'edit' ), '3.0', '<' ) && $order->has_status( apply_filters( 'woocommerce_payment_complete_order_status', $order->needs_processing() ? 'processing' : 'completed', $order->get_id(), $order ) ) // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment ) { $order->set_date_paid( $order->get_date_created( 'edit' ) ); } if ( null === $order->get_date_created( 'edit' ) ) { $order->set_date_created( time() ); } $order->set_version( Constants::get_constant( 'WC_VERSION' ) ); // Fetch changes. $changes = $order->get_changes(); $this->persist_updates( $order ); // Update download permissions if necessary. if ( array_key_exists( 'billing_email', $changes ) || array_key_exists( 'customer_id', $changes ) ) { $data_store = \WC_Data_Store::load( 'customer-download' ); $data_store->update_user_by_order_id( $order->get_id(), $order->get_customer_id(), $order->get_billing_email() ); } // Mark user account as active. if ( array_key_exists( 'customer_id', $changes ) ) { wc_update_user_last_active( $order->get_customer_id() ); } $order->apply_changes(); $this->clear_caches( $order ); // For backwards compatibility, moving an auto-draft order to a valid status triggers the 'woocommerce_new_order' hook. if ( ! empty( $changes['status'] ) && 'auto-draft' === $previous_status ) { do_action( 'woocommerce_new_order', $order->get_id(), $order ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment return; } // For backwards compat with CPT, trashing/untrashing and changing previously datastore-level props does not trigger the update hook. if ( ( ! empty( $changes['status'] ) && in_array( 'trash', array( $changes['status'], $previous_status ), true ) ) || ( ! empty( $changes ) && ! array_diff_key( $changes, array_flip( $this->get_post_data_store_for_backfill()->get_internal_data_store_key_getters() ) ) ) ) { return; } do_action( 'woocommerce_update_order', $order->get_id(), $order ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment } /** * Proxy to udpating order meta. Here for backward compatibility reasons. * * @param \WC_Order $order Order object. * * @return void */ protected function update_post_meta( &$order ) { $this->update_order_meta( $order ); } /** * Helper method that is responsible for persisting order updates to the database. * * This is expected to be reused by other order types, and should not contain any specific metadata updates or actions. * * @param \WC_Order $order Order object. * @param bool $backfill Whether to backfill data to post tables. * * @return array $changes Array of changes. * * @throws \Exception When unable to persist order. */ protected function persist_updates( &$order, $backfill = true ) { // Fetch changes. $changes = $order->get_changes(); if ( ! isset( $changes['date_modified'] ) ) { $order->set_date_modified( current_time( 'mysql' ) ); } $this->persist_order_to_db( $order ); $this->update_order_meta( $order ); $order->save_meta_data(); if ( $backfill ) { self::$backfilling_order_ids[] = $order->get_id(); $this->clear_caches( $order ); $r_order = wc_get_order( $order->get_id() ); // Refresh order to account for DB changes from post hooks. $this->maybe_backfill_post_record( $r_order ); self::$backfilling_order_ids = array_diff( self::$backfilling_order_ids, array( $order->get_id() ) ); } return $changes; } /** * Helper method to check whether to backfill post record. * * @return bool */ private function should_backfill_post_record() { $data_sync = wc_get_container()->get( DataSynchronizer::class ); return $data_sync->data_sync_is_enabled(); } /** * Helper function to decide whether to backfill post record. * * @param \WC_Abstract_Order $order Order object. * * @return void */ private function maybe_backfill_post_record( $order ) { if ( $this->should_backfill_post_record() ) { $this->backfill_post_record( $order ); } } /** * Helper method that updates post meta based on an order object. * Mostly used for backwards compatibility purposes in this datastore. * * @param \WC_Order $order Order object. * * @since 7.0.0 */ public function update_order_meta( &$order ) { $changes = $order->get_changes(); $this->update_address_index_meta( $order, $changes ); } /** * Helper function to update billing and shipping address metadata. * * @param \WC_Abstract_Order $order Order Object. * @param array $changes Array of changes. * * @return void */ private function update_address_index_meta( $order, $changes ) { // If address changed, store concatenated version to make searches faster. foreach ( array( 'billing', 'shipping' ) as $address_type ) { $index_meta_key = "_{$address_type}_address_index"; if ( isset( $changes[ $address_type ] ) || ( is_a( $order, 'WC_Order' ) && empty( $order->get_meta( $index_meta_key ) ) ) ) { $order->update_meta_data( $index_meta_key, implode( ' ', $order->get_address( $address_type ) ) ); } } } /** * Return array of coupon_code => meta_key for coupon which have usage limit and have tentative keys. * Pass $coupon_id if key for only one of the coupon is needed. * * @param WC_Order $order Order object. * @param int $coupon_id If passed, will return held key for that coupon. * * @return array|string Key value pair for coupon code and meta key name. If $coupon_id is passed, returns meta_key for only that coupon. */ public function get_coupon_held_keys( $order, $coupon_id = null ) { $held_keys = $order->get_meta( '_coupon_held_keys' ); if ( $coupon_id ) { return isset( $held_keys[ $coupon_id ] ) ? $held_keys[ $coupon_id ] : null; } return $held_keys; } /** * Return array of coupon_code => meta_key for coupon which have usage limit per customer and have tentative keys. * * @param WC_Order $order Order object. * @param int $coupon_id If passed, will return held key for that coupon. * * @return mixed */ public function get_coupon_held_keys_for_users( $order, $coupon_id = null ) { $held_keys_for_user = $order->get_meta( '_coupon_held_keys_for_users' ); if ( $coupon_id ) { return isset( $held_keys_for_user[ $coupon_id ] ) ? $held_keys_for_user[ $coupon_id ] : null; } return $held_keys_for_user; } /** * Add/Update list of meta keys that are currently being used by this order to hold a coupon. * This is used to figure out what all meta entries we should delete when order is cancelled/completed. * * @param WC_Order $order Order object. * @param array $held_keys Array of coupon_code => meta_key. * @param array $held_keys_for_user Array of coupon_code => meta_key for held coupon for user. * * @return mixed */ public function set_coupon_held_keys( $order, $held_keys, $held_keys_for_user ) { if ( is_array( $held_keys ) && 0 < count( $held_keys ) ) { $order->update_meta_data( '_coupon_held_keys', $held_keys ); } if ( is_array( $held_keys_for_user ) && 0 < count( $held_keys_for_user ) ) { $order->update_meta_data( '_coupon_held_keys_for_users', $held_keys_for_user ); } } /** * Release all coupons held by this order. * * @param WC_Order $order Current order object. * @param bool $save Whether to delete keys from DB right away. Could be useful to pass `false` if you are building a bulk request. */ public function release_held_coupons( $order, $save = true ) { $coupon_held_keys = $this->get_coupon_held_keys( $order ); if ( is_array( $coupon_held_keys ) ) { foreach ( $coupon_held_keys as $coupon_id => $meta_key ) { $coupon = new \WC_Coupon( $coupon_id ); $coupon->delete_meta_data( $meta_key ); $coupon->save_meta_data(); } } $order->delete_meta_data( '_coupon_held_keys' ); $coupon_held_keys_for_users = $this->get_coupon_held_keys_for_users( $order ); if ( is_array( $coupon_held_keys_for_users ) ) { foreach ( $coupon_held_keys_for_users as $coupon_id => $meta_key ) { $coupon = new \WC_Coupon( $coupon_id ); $coupon->delete_meta_data( $meta_key ); $coupon->save_meta_data(); } } $order->delete_meta_data( '_coupon_held_keys_for_users' ); if ( $save ) { $order->save_meta_data(); } } /** * Performs actual query to get orders. Uses `OrdersTableQuery` to build and generate the query. * * @param array $query_vars Query variables. * * @return array|object List of orders and count of orders. */ public function query( $query_vars ) { if ( ! isset( $query_vars['paginate'] ) || ! $query_vars['paginate'] ) { $query_vars['no_found_rows'] = true; } if ( isset( $query_vars['anonymized'] ) ) { $query_vars['meta_query'] = $query_vars['meta_query'] ?? array(); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query if ( $query_vars['anonymized'] ) { $query_vars['meta_query'][] = array( 'key' => '_anonymized', 'value' => 'yes', ); } else { $query_vars['meta_query'][] = array( 'key' => '_anonymized', 'compare' => 'NOT EXISTS', ); } } try { $query = new OrdersTableQuery( $query_vars ); } catch ( \Exception $e ) { $query = (object) array( 'orders' => array(), 'found_orders' => 0, 'max_num_pages' => 0, ); } if ( isset( $query_vars['return'] ) && 'ids' === $query_vars['return'] ) { $orders = $query->orders; } else { $orders = WC()->order_factory->get_orders( $query->orders ); } if ( isset( $query_vars['paginate'] ) && $query_vars['paginate'] ) { return (object) array( 'orders' => $orders, 'total' => $query->found_orders, 'max_num_pages' => $query->max_num_pages, ); } return $orders; } //phpcs:enable Squiz.Commenting, Generic.Commenting /** * Get the SQL needed to create all the tables needed for the custom orders table feature. * * @return string */ public function get_database_schema() { global $wpdb; $collate = $wpdb->has_cap( 'collation' ) ? $wpdb->get_charset_collate() : ''; $orders_table_name = $this->get_orders_table_name(); $addresses_table_name = $this->get_addresses_table_name(); $operational_data_table_name = $this->get_operational_data_table_name(); $meta_table = $this->get_meta_table_name(); $max_index_length = $this->database_util->get_max_index_length(); $composite_meta_value_index_length = max( $max_index_length - 8 - 100 - 1, 20 ); // 8 for order_id, 100 for meta_key, 10 minimum for meta_value. $composite_customer_id_email_length = max( $max_index_length - 20, 20 ); // 8 for customer_id, 20 minimum for email. $sql = " CREATE TABLE $orders_table_name ( id bigint(20) unsigned, status varchar(20) null, currency varchar(10) null, type varchar(20) null, tax_amount decimal(26,8) null, total_amount decimal(26,8) null, customer_id bigint(20) unsigned null, billing_email varchar(320) null, date_created_gmt datetime null, date_updated_gmt datetime null, parent_order_id bigint(20) unsigned null, payment_method varchar(100) null, payment_method_title text null, transaction_id varchar(100) null, ip_address varchar(100) null, user_agent text null, customer_note text null, PRIMARY KEY (id), KEY status (status), KEY date_created (date_created_gmt), KEY customer_id_billing_email (customer_id, billing_email({$composite_customer_id_email_length})), KEY billing_email (billing_email($max_index_length)), KEY type_status_date (type, status, date_created_gmt), KEY parent_order_id (parent_order_id), KEY date_updated (date_updated_gmt) ) $collate; CREATE TABLE $addresses_table_name ( id bigint(20) unsigned auto_increment primary key, order_id bigint(20) unsigned NOT NULL, address_type varchar(20) null, first_name text null, last_name text null, company text null, address_1 text null, address_2 text null, city text null, state text null, postcode text null, country text null, email varchar(320) null, phone varchar(100) null, KEY order_id (order_id), UNIQUE KEY address_type_order_id (address_type, order_id), KEY email (email($max_index_length)), KEY phone (phone) ) $collate; CREATE TABLE $operational_data_table_name ( id bigint(20) unsigned auto_increment primary key, order_id bigint(20) unsigned NULL, created_via varchar(100) NULL, woocommerce_version varchar(20) NULL, prices_include_tax tinyint(1) NULL, coupon_usages_are_counted tinyint(1) NULL, download_permission_granted tinyint(1) NULL, cart_hash varchar(100) NULL, new_order_email_sent tinyint(1) NULL, order_key varchar(100) NULL, order_stock_reduced tinyint(1) NULL, date_paid_gmt datetime NULL, date_completed_gmt datetime NULL, shipping_tax_amount decimal(26,8) NULL, shipping_total_amount decimal(26,8) NULL, discount_tax_amount decimal(26,8) NULL, discount_total_amount decimal(26,8) NULL, recorded_sales tinyint(1) NULL, UNIQUE KEY order_id (order_id), KEY order_key (order_key) ) $collate; CREATE TABLE $meta_table ( id bigint(20) unsigned auto_increment primary key, order_id bigint(20) unsigned null, meta_key varchar(255), meta_value text null, KEY meta_key_value (meta_key(100), meta_value($composite_meta_value_index_length)), KEY order_id_meta_key_meta_value (order_id, meta_key(100), meta_value($composite_meta_value_index_length)) ) $collate; "; return $sql; } /** * Returns an array of meta for an object. * * @param WC_Data $object WC_Data object. * @return array */ public function read_meta( &$object ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.objectFound $raw_meta_data = $this->data_store_meta->read_meta( $object ); return $this->filter_raw_meta_data( $object, $raw_meta_data ); } /** * Deletes meta based on meta ID. * * @param WC_Data $object WC_Data object. * @param \stdClass $meta (containing at least ->id). * * @return bool */ public function delete_meta( &$object, $meta ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.objectFound global $wpdb; if ( $this->should_backfill_post_record() && isset( $meta->id ) ) { // Let's get the actual meta key before its deleted for backfilling. We cannot delete just by ID because meta IDs are different in HPOS and posts tables. $db_meta = $this->data_store_meta->get_metadata_by_id( $meta->id ); if ( $db_meta ) { $meta->key = $db_meta->meta_key; $meta->value = $db_meta->meta_value; } } $delete_meta = $this->data_store_meta->delete_meta( $object, $meta ); $changes_applied = $this->after_meta_change( $object, $meta ); if ( ! $changes_applied && $object instanceof WC_Abstract_Order && $this->should_backfill_post_record() && isset( $meta->key ) ) { self::$backfilling_order_ids[] = $object->get_id(); if ( is_object( $meta->value ) && '__PHP_Incomplete_Class' === get_class( $meta->value ) ) { $meta_value = maybe_serialize( $meta->value ); $wpdb->delete( _get_meta_table( 'post' ), array( 'post_id' => $object->get_id(), 'meta_key' => $meta->key, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key 'meta_value' => $meta_value, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value ), array( '%d', '%s', '%s' ) ); wp_cache_delete( $object->get_id(), 'post_meta' ); $logger = wc_get_container()->get( LegacyProxy::class )->call_function( 'wc_get_logger' ); $logger->warning( sprintf( 'encountered an order meta value of type __PHP_Incomplete_Class during `delete_meta` in order with ID %d: "%s"', $object->get_id(), var_export( $meta_value, true ) ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_var_export } else { delete_post_meta( $object->get_id(), $meta->key, $meta->value ); } self::$backfilling_order_ids = array_diff( self::$backfilling_order_ids, array( $object->get_id() ) ); } return $delete_meta; } /** * Add new piece of meta. * * @param WC_Data $object WC_Data object. * @param \stdClass $meta (containing ->key and ->value). * * @return int|bool meta ID or false on failure */ public function add_meta( &$object, $meta ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.objectFound $add_meta = $this->data_store_meta->add_meta( $object, $meta ); $meta->id = $add_meta; $changes_applied = $this->after_meta_change( $object, $meta ); if ( ! $changes_applied && $object instanceof WC_Abstract_Order && $this->should_backfill_post_record() ) { self::$backfilling_order_ids[] = $object->get_id(); add_post_meta( $object->get_id(), $meta->key, $meta->value ); self::$backfilling_order_ids = array_diff( self::$backfilling_order_ids, array( $object->get_id() ) ); } return $add_meta; } /** * Update meta. * * @param WC_Data $object WC_Data object. * @param \stdClass $meta (containing ->id, ->key and ->value). * * @return bool The number of rows updated, or false on error. */ public function update_meta( &$object, $meta ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.objectFound $update_meta = $this->data_store_meta->update_meta( $object, $meta ); $changes_applied = $this->after_meta_change( $object, $meta ); if ( ! $changes_applied && $object instanceof WC_Abstract_Order && $this->should_backfill_post_record() ) { self::$backfilling_order_ids[] = $object->get_id(); update_post_meta( $object->get_id(), $meta->key, $meta->value ); self::$backfilling_order_ids = array_diff( self::$backfilling_order_ids, array( $object->get_id() ) ); } return $update_meta; } /** * Perform after meta change operations, including updating the date_modified field, clearing caches and applying changes. * * @param WC_Abstract_Order $order Order object. * @param \WC_Meta_Data $meta Metadata object. * * @return bool True if changes were applied, false otherwise. */ protected function after_meta_change( &$order, $meta ) { method_exists( $meta, 'apply_changes' ) && $meta->apply_changes(); // Prevent this happening multiple time in same request. if ( $this->should_save_after_meta_change( $order, $meta ) ) { $order->set_date_modified( current_time( 'mysql' ) ); $order->save(); return true; } else { $order_cache = wc_get_container()->get( OrderCache::class ); $order_cache->remove( $order->get_id() ); } return false; } /** * Helper function to check whether the modified date needs to be updated after a meta save. * * This method prevents order->save() call multiple times in the same request after any meta update by checking if: * 1. Order modified date is already the current date, no updates needed in this case. * 2. If there are changes already queued for order object, then we don't need to update the modified date as it will be updated ina subsequent save() call. * * @param WC_Order $order Order object. * @param \WC_Meta_Data|null $meta Metadata object. * * @return bool Whether the modified date needs to be updated. */ private function should_save_after_meta_change( $order, $meta = null ) { $current_time = $this->legacy_proxy->call_function( 'current_time', 'mysql', 1 ); $current_date_time = new \WC_DateTime( $current_time, new \DateTimeZone( 'GMT' ) ); $should_save = $order->get_date_modified() < $current_date_time && empty( $order->get_changes() ) && ( ! is_object( $meta ) || ! in_array( $meta->key, $this->ephemeral_meta_keys, true ) ); /** * Allows code to skip a full order save() when metadata is changed. * * @since 8.8.0 * * @param bool $should_save Whether to trigger a full save after metadata is changed. */ return apply_filters( 'woocommerce_orders_table_datastore_should_save_after_meta_change', $should_save ); } } E15 Rede wireless earphone – alibabatelecom
ADD ANYTHING HERE OR JUST REMOVE IT…
  • NEWSLETTER
  • CONTACT US
  • FAQs
alibabatelecom
Select category
  • Select category
  • Accessories
    • Mouse , Keyboard
    • phone card holder
    • Phone holder
    • Pop socket
    • Selfi
    • USB-SD card
  • brands
    • ACEFAST
    • Adidas
    • AMA Book Case
    • AMA Extra pas Book Case
    • Anti shock
      • Iphone
    • Apple
    • Back case card holder
    • back case color
      • Luxury clear magnetic back case
    • BOROFONE
    • Fashion Case
    • Hoco
    • ideal of Sweden
    • KEY Book Case
    • kingston Memory
    • Magnet leather case
    • OG Tempered Glass
    • Samsung
    • selly
  • Childeren toys
    • Car , Motor
  • Electronics
    • Adapters
    • Air Tag
    • Bluetooth Speaker
    • Cables
    • Car adapter , cables
    • Gaming
    • HDMI , converter
    • Headset , audio jack
    • Oudio Other
    • Wirless charger
  • Mobile , Tab , Watch parts
    • Ipad
      • Ipad battery
      • Ipad charging port
      • Ipad display
    • Iphone
      • Iphone back camera
      • Iphone Back cover
      • Iphone battery
      • Iphone camera lens
      • Iphone charging port
      • Iphone display
      • Iphone earspeaker
      • Iphone front camera
      • Iphone loudspeaker
      • iphone parts
      • Iphone Simcard holder
    • Samsung
      • Main Flex
      • Power And Volume Flex Cable
      • Samsung back camera
      • Samsung back cover
      • Samsung battery
      • Samsung camera lens
      • Samsung charging port
      • Samsung display
      • Samsung earspeaker
      • Samsung front camera
      • Samsung LCD Flex
      • Samsung loudspeaker
      • Samsung Signal Antenna
      • Samsung Simcard holder
  • Mobile , Tablets Accessories
    • Apple
      • AirPods
      • Apple Watch
        • Apple watch 3 serie 40mm
        • Apple watch 3 serie 42mm
        • Apple watch 4 serie 38mm
        • Apple watch 4 serie 42mm
        • Apple watch 5 serie 40mm
        • Apple watch 5 serie 44mm
        • Apple watch 6 serie 40mm
        • Apple watch 6 serie 44mm
        • Apple watch 7 serie 41mm
        • Apple watch 7 serie 45mm
        • Apple watch 8 serie 41mm
        • Apple watch 8 serie 45mm
        • Apple watch Ultra 49mm 1st Gen
      • IPad
        • iPad 10.2 7th Ge (2019)
        • iPad 10.2 8th Ge (2020)
        • iPad 10.2 9th Ge (2021)
        • iPad 10.9 (10th 2022)
        • iPad 11 (11Gen 2025 )
        • Ipad 3
        • Ipad 4
        • iPad 9.7 (5th 2017)
        • iPad 9.7 (6th 2018)
        • iPad Air (2013)
        • iPad Air 11 (2024)
        • iPad Air 11 (2025)
        • iPad Air 13 (2024)
        • iPad Air 13 (2025)
        • Ipad Air 2 (2014)
        • iPad Air 3rd Ge (2019)
        • iPad Air 4th Ge (2020)
        • iPad Air 5th Ge (2022)
        • ipad mini 4th Ge (2015)
        • ipad mini 5th Ge (2019)
        • ipad mini 6th Ge (2021)
        • iPad Pro 10.5 (2017)
        • iPad Pro 11 (1Gen 2018)
        • iPad Pro 11 (2 Gen: 2020)
        • iPad Pro 11 (3Gen 2021)
        • iPad Pro 11 (4 Gen: 2022)
        • iPad Pro 11 (5 Gen: 2024) M4
        • iPad Pro 12.9 (1nd 2015)
        • iPad Pro 12.9 (2nd 2017)
        • iPad Pro 12.9 (3nd 2018)
        • iPad Pro 12.9 (4nd 2020)
        • iPad Pro 12.9 (5nd 2021)
        • iPad Pro 12.9 (6nd 2022)
        • IPad Pro 13 (2024)(13-inch (M4)
        • iPad Pro 13 (2025)(13-inch (M5)
        • iPad Pro 9.7 (2016)
      • Iphone
        • iphone 11
        • iphone 11 pro
        • iphone 11 pro max
        • iphone 12
        • iphone 12 mini
        • iphone 12 pro
        • iphone 12 pro max
        • iphone 13
        • iphone 13 mini
        • iphone 13 pro
        • iphone 13 pro max
        • iphone 14
        • iphone 14 plus
        • iphone 14 pro
        • iphone 14 pro max
        • Iphone 15
        • Iphone 15 Plus
        • Iphone 15 Pro
        • Iphone 15 Pro Max
        • Iphone 16
        • Iphone 16 Plus
        • Iphone 16 Pro
        • Iphone 16 Pro Max
        • Iphone 16e
        • Iphone 17
        • Iphone 17 Air
        • Iphone 17 Pro
        • Iphone 17 Pro Max
        • Iphone 17e
        • iphone 5
        • iphone 5S
        • Iphone 6
        • iphone 6 plus
        • iphone 6s
        • iphone 6s plus
        • iphone 7
        • iphone 7 plus
        • iphone 8
        • iphone 8 plus
        • iphone SE
        • iphone SE 2020
        • Iphone SE 2022
        • iphone X
        • iphone XR
        • iphone XS
        • iphone XS max
    • google
      • Google Pixel 5
      • Google Pixel 5A
      • Google Pixel 6
      • Google Pixel 6 Pro
      • Google Pixel 6A
      • Google Pixel 7
      • Google Pixel 7 Pro
      • Google Pixel 7A
      • Google Pixel 8
      • Google Pixel 8 Pro
      • Google Pixel 8A
      • Google Pixel 9
      • Google Pixel 9 Pro
      • Google Pixel 9 Pro XL
    • Huawei
      • Huawei Honor Models
        • Huawei Honor 10
        • Huawei Honor 20
        • Huawei Honor 20 Lite
        • Huawei Honor 20 Pro
        • Huawei Honor 6
        • Huawei Honor 7
        • Huawei Honor 8
        • Huawei Honor 8 Lite
        • Huawei Honor 9
        • Huawei Honor View 10
        • Huawei Honor View 20
      • Huawei Mate Models
        • Huawei Mate 10
        • Huawei Mate 10 Lite
        • Huawei Mate 10 Pro
        • Huawei Mate 20
        • Huawei Mate 20 Lite
        • Huawei Mate 20 Pro
        • Huawei Mate 30
        • Huawei Mate 30 Lite
        • Huawei Mate 30 Pro
        • Huawei Mate 40
        • Huawei Mate 40 Pro
        • Huawei Mate 7
        • Huawei Mate 8
        • Huawei Mate 9
        • Huawei Mate 9 pro
      • Huawei P Models
        • Huawei P10
        • Huawei P10 Lite
        • Huawei P20
        • Huawei P20 Lite
        • Huawei P20 Lite 2019
        • Huawei P20 Pro
        • Huawei P30
        • Huawei P30 Lite
        • Huawei P30 Pro
        • Huawei P40
        • Huawei P40 Lite
        • Huawei P40 pro
        • Huawei P7
        • Huawei P8
        • Huawei P8 Lite
        • Huawei P9
        • Huawei P9 Lite
      • Huawei P smart Models
        • Huawei P smart
        • Huawei P smart 2019
        • Huawei P smart 2020
        • Huawei P smart 2021
        • Huawei P smart pro
        • Huawei P smart Z
    • Nokia
      • HMD Series
        • Nokia 2.4
        • Nokia 5.4
    • Samsung
      • Samsung A model
        • |Samsung A34 (A346)
        • Samsung A01
        • Samsung A02
        • samsung A02s
        • Samsung A03
        • Samsung A03s
        • Samsung A04s
        • Samsung A05S
        • Samsung A06
        • Samsung A07
        • Samsung A10
        • Samsung A10s
        • Samsung A11
        • Samsung A12
        • Samsung A13 4G
        • Samsung A13 5G
        • Samsung A14 4G
        • Samsung A14 5G
        • Samsung A15
        • Samsung A16 4G (A165F)
        • Samsung A16 5G (A166B)
        • Samsung A17
        • Samsung A20e (A202F)
        • Samsung A20s (A207F)
        • Samsung A21 (A215)
        • Samsung A21s (A217F)
        • Samsung A22 4G (A225F)
        • Samsung A22 5G (A226B)
        • Samsung A23 4G (SM-A236)
        • Samsung A23 5G (SM-A236)
        • Samsung A24 (A245F)
        • Samsung A25 (A256)
        • Samsung A26 (A266)
        • Samsung A27
        • Samsung A30 (A305F)
        • Samsung A30s (A307F)
        • Samsung A31 (A315F)
        • Samsung A32 4G (A325)
        • Samsung A32 5G (A326)
        • Samsung A33 5G (A336B)
        • Samsung A35 (A356)
        • Samsung A36 (A366)
        • Samsung A37
        • Samsung A40 (A405F)
        • Samsung A41 (A415F)
        • Samsung A42 (A426B)
        • Samsung A5 2015
        • Samsung A50 (A505F)
        • Samsung A50s
        • Samsung A51 (A515F)
        • Samsung A52 (A525F)
        • Samsung A52s (A528B)
        • Samsung A53 (A536B/DS)
        • Samsung A54 (A546B)
        • Samsung A55 (A556)
        • Samsung A56 (A566)
        • Samsung A60 (A606F)
        • Samsung A70 (A705F)
        • Samsung A71 5G (A716F)
        • Samsung A72 (A725)
        • Samsung A73
        • Samsung A80 (A805F)
        • Samsung A90 (A908F)
      • Samsung Buds case
      • Samsung note model
        • Samsung Note 10
        • Samsung Note 10 Lite
        • Samsung Note 10 plus
        • Samsung Note 20
        • Samsung Note 20 ultra
        • Samsung Note 8
        • Samsung Note 9
      • Samsung S model
        • Samsung s10
        • Samsung S10 lite
        • Samsung s10 plus
        • Samsung s10e
        • Samsung s20
        • Samsung s20 FE
        • Samsung s20 plus
        • Samsung s20 ultra
        • Samsung s21
        • Samsung s21 FE
        • Samsung s21 plus
        • Samsung s21 ultra
        • Samsung s22
        • Samsung s22 plus
        • Samsung s22 ultra
        • Samsung S23
        • Samsung S23 FE
        • Samsung S23 Plus
        • Samsung S23 Ultra
        • Samsung S24
        • Samsung S24 FE
        • Samsung S24 Plus
        • Samsung S24 Ultra
        • Samsung S25
        • Samsung S25 Edge
        • Samsung S25 FE
        • Samsung S25 Plus
        • Samsung S25 Ultra
        • Samsung S26
        • Samsung S26 Edge
        • Samsung S26 FE
        • Samsung S26 Plus
        • Samsung S26 Ultra
        • Samsung s4
        • Samsung s5
        • Samsung s6
        • Samsung s6 edge
        • Samsung s7
        • Samsung s7 edge
        • Samsung s8
        • Samsung s8 plus
        • Samsung s9
        • Samsung s9 plus
      • Samsung X cover model
        • Samsung x cover 3
        • Samsung x cover 4
        • Samsung x cover 4s
        • Samsung x cover 5
        • Samsung x cover 6 pro
        • Samsung X cover 7
        • Samsung x cover pro
      • Samsung Z Fold , Z flip models
        • Samsung Z Flip 3
        • Samsung Z Flip 4
        • Samsung Z Fold 3
        • Samsung Z Fold 4
  • Mobile, tablet , smart watches
    • Mobile
      • Android Mobile
      • IOS Mobile
    • Smart watches
  • Personal care, beauty and well-being
    • Hair dryer
    • Shaving and hair removal
  • Tempered Glass
    • Apple Watch
    • Ipad 3D
    • Iphone camera Lens
    • OG tempered Glass
      • Iphone
      • Samsung
    • Samsung camera lens
    • UV tempered Glass
      • Samsung
Login / Register
0 Wishlist
0 Compare
2 items / 605.89 €
Menu
alibabatelecom
2 items / 605.89 €
Browse Categories
  • Mobile, tablet , smart watches
    • Mobile
      • IOS Mobile
      • Android Mobile
      • Doro
    • Tablets
      • Ipad
      • Samsung TAB
    • Smart watches
Browse Categories
  • Apple
    • Iphone
      • Iphone 17 Pro Max
      • Iphone 17 Air
      • Iphone 17 Pro
      • Iphone 17e
      • Iphone 17
      • Iphone 16 Pro Max
      • Iphone 16 Plus
      • Iphone 16 Pro
      • Iphone 16e
      • Iphone 16
      • Iphone 15 Pro Max
      • Iphone 15 Plus
      • Iphone 15 Pro
      • Iphone 15
      • iphone 14 pro max
      • iphone 14 plus
      • iphone 14 pro
      • iphone 14
      • iphone 13 pro max
      • iphone 13 pro
      • iphone 13 mini
      • iphone 13
      • iphone 12 pro max
      • iphone 12 pro
      • iphone 12 mini
      • iphone 12
      • iphone 11 pro max
      • iphone 11 pro
      • iphone 11
      • iphone XS max
      • iphone XR
      • iphone XS
      • iphone X
      • iphone 8 plus
      • iphone 8
      • Iphone SE 2022
      • iphone SE 2020
      • iphone 7 plus
      • iphone 7
      • iphone 6s plus
      • iphone 6s
      • iphone 6 plus
      • Iphone 6
      • iphone SE
      • iphone 5S
      • iphone 5
    • IPad
      • iPad Pro 13 (2025)(13-inch (M5)
      • IPad Pro 13 (2024)(13-inch (M4)
      • iPad Pro 12.9 (6nd 2022)
      • iPad Pro 12.9 (5Gen 2021)
      • iPad Pro 12.9 (4Gen 2020)
      • iPad Pro 12.9 (3Gen 2018)
      • iPad Pro 12.9 (2Gen 2017)
      • iPad Pro 12.9 (1Gen 2015)
      • iPad Pro 11 (5 Gen: 2024) M4
      • iPad Pro 11 (4 Gen: 2022)
      • iPad Pro 11 (3Gen 2021)
      • iPad Pro 11 (2 Gen: 2020)
      • iPad Pro 11 (1Gen 2018)
      • iPad Pro 10.5 (2017)
      • iPad Pro 9.7 (2016)
      • iPad 10.9 (10th 2022)
      • iPad 10.2 9th Ge (2021)
      • iPad 10.2 8th Ge (2020)
      • iPad 10.2 7th Ge (2019)
      • iPad 9.7 (6th 2018)
      • iPad 9.7 (5th 2017)
      • iPad Air 13 (2024)
      • iPad Air 11 (2024) M2
      • iPad Air 5th Ge (2022)
      • iPad Air 4th Ge (2020)
      • iPad Air 3rd Ge (2019)
      • Ipad Air 2 (2014)
      • iPad Air (2013)
      • Ipad 4
      • Ipad 3
      • Ipad 2
      • Ipad mini 7th Ge (2023)
      • ipad mini 6th Ge (2021)
      • ipad mini 5th Ge (2019)
      • ipad mini 4th Ge (2015)
      • ipad mini 3rd Ge (2014)
      • ipad mini 2 (2013)
    • Apple Watch
      • Apple watch Ultra 49mm 2st Gen
      • Apple watch Ultra 49mm 1st Gen
      • Apple watch 9 serie 45mm
      • Apple watch 9 serie 41mm
      • Apple watch 8 serie 45mm
      • Apple watch 8 serie 41mm
      • Apple watch 7 serie 45mm
      • Apple watch 7 serie 41mm
      • Apple watch 6 serie 44mm
      • Apple watch 6 serie 40mm
      • Apple watch SE 2022 serie 44mm
      • Apple watch SE 2022 serie 40mm
      • Apple watch SE serie 44mm
      • Apple watch SE serie 40mm
      • Apple watch 5 serie 44mm
      • Apple watch 5 serie 40mm
      • Apple watch 4 serie 42mm
      • Apple watch 4 serie 38mm
      • Apple watch 3 serie 42mm
      • Apple watch 3 serie 40mm
    • AirPods
      • AirPods Pro (2st generation)
      • AirPods Pro (1st generation)
      • AirPods 4 (4st generation)
      • AirPods 3 (3st generation)
      • AirPods 2 (2st generation)
      • AirPods 1 (1st generation)
Browse Categories
  • Motorola
    • Moto G Models
      • Moto G200
      • Moto G100
      • Moto G85
      • Moto G84
      • Moto G82
      • Moto G75
      • Moto G73
      • Moto G72
      • Moto G71 5G
      • Moto G64
      • Moto G62
      • Moto G60s
      • Moto G60
      • Moto G56
      • Moto G55
      • Moto G54 Power
      • Moto G54
      • Moto G53
      • Moto G52
      • Moto G51 5G
      • Moto G50 5G
      • Moto G50 4G
      • Moto G45
      • Moto G42
      • Moto G41
      • Moto G35
      • Moto G34
      • Moto G32
      • Moto G31
      • Moto G30
      • Moto G24
      • Moto G23
      • Moto G22
      • Moto G20
      • Moto G15
      • Moto G14
      • Moto G13
      • Moto G10 play
      • Moto G10
      • Moto G Power (2021)
    • Moto E Models
      • Moto E40
      • Motorola Moto E32s
      • Motorola Moto E32
      • Motorola Moto E30
      • Motorola Moto E22
      • Motorola Moto E22i
      • Motorola Moto E20
      • Motorola Moto E14
      • Motorola Moto E15
      • Motorola Moto E13
Browse Categories
  • Accessories
    • Mouse , Keyboard
    • touch pen
    • Phone holder
    • phone card holder
    • Pop socket
    • USB-SD card
    • Selfi
Browse Categories
  • Samsung
    • Samsung S model
      • Samsung S26 Ultra
      • Samsung S26 Plus
      • Samsung S26 Edge
      • Samsung S26 FE
      • Samsung S26
      • Samsung S25 Ultra
      • Samsung S25 Plus
      • Samsung S25 Edge
      • Samsung S25 FE
      • Samsung S25
      • Samsung S24 Ultra
      • Samsung S24 Plus
      • Samsung S24 FE
      • Samsung S24
      • Samsung S23 Ultra
      • Samsung S23 Plus
      • Samsung S23 FE
      • Samsung S23
      • Samsung s22 ultra
      • Samsung s22 plus
      • Samsung s22
      • Samsung s21 ultra
      • Samsung s21 plus
      • Samsung s21 FE
      • Samsung s21
      • Samsung s20 ultra
      • Samsung s20 plus
      • Samsung s20 FE
      • Samsung s20
      • Samsung s10 plus
      • Samsung S10 lite
      • Samsung s10e
      • Samsung s10
      • Samsung s9 plus
      • Samsung s9
      • Samsung s8 plus
      • Samsung s8
      • Samsung s7 edge
      • Samsung s7
      • Samsung s6 edge
      • Samsung s6
      • Samsung s5
      • Samsung s4
    • Samsung A model,
      • Samsung A90 (A908F)
      • Samsung A80 (A805F)
      • Samsung A73
      • Samsung A50 (A505F)
      • Samsung A72 (A725)
      • Samsung A71 5G (A716F)
      • Samsung A71 (A715F)
      • Samsung A70 (A705F)
      • Samsung A60 (A606F)
      • Samsung A56 (A566)
      • Samsung A55 (A556)
      • Samsung A54 (A546B)
      • Samsung A53 (A536B/DS)
      • Samsung A52s (A528B)
      • Samsung A52 (A525F)
      • Samsung A51 5G (A516B/DS)
      • Samsung A51 (A515F)
      • Samsung A50s
      • Samsung A42 (A426B)
      • Samsung A41 (A415F)
      • Samsung A40 (A405F)
      • Samsung A36 (A366)
      • Samsung A35 (A356)
      • |Samsung A34 (A346)
      • Samsung A33 5G (A336B)
      • Samsung A32 5G (A326)
      • Samsung A32 4G (A325)
      • Samsung A31 (A315F)
      • Samsung A30s (A307F)
      • Samsung A30 (A305F)
      • Samsung A26 (A266)
      • Samsung A25 (A256)
      • Samsung A24 (A245F)
      • Samsung A23 5G (SM-A236)
      • Samsung A23 4G (SM-A236)
      • Samsung A22 5G (A226B)
      • Samsung A22 4G (A225F)
      • Samsung A21s (A217F)
      • Samsung A21 (A215)
      • Samsung A20e (A202F)
      • Samsung A17
      • Samsung A16 5G (A166B)
      • Samsung A16 4G (A165F)
      • Samsung A15
      • Samsung A14 5G
      • Samsung A14 4G
      • Samsung A13 5G
      • Samsung A13 4G
      • Samsung A12
      • Samsung A11
      • Samsung A10s
      • Samsung A10
      • Samsung A07
      • Samsung A06
      • Samsung A05S
      • Samsung A04s
      • Samsung A03s
      • Samsung A03
      • samsung A02s
      • Samsung A02
      • Samsung A01
    • Samsung note model
      • Samsung Note 20 ultra
      • Samsung Note 20
      • Samsung Note 10 plus
      • Samsung Note 10 Lite
      • Samsung Note 10
      • Samsung Note 9
      • Samsung Note 8
      • Samsung Note 5
      • Samsung Note 4
    • Samsung X cover model
      • Samsung X cover 7
      • Samsung x cover 6 pro
      • Samsung x cover pro
      • Samsung x cover 5
      • Samsung x cover 4s
      • Samsung x cover 4
      • Samsung x cover 3
    • Samsung Z Fold , Z flip models
      • Samsung Z flip 7
      • Samsung Z flip 6
      • Samsung Z flip 5
      • Samsung Z Flip 4
      • Samsung Z Flip 3
      • Samsung Z fold 7
      • Samsung Z fold 7 FE
      • Samsung Z fold 6
      • Samsung Z fold 5
      • Samsung Z Fold 4
      • Samsung Z Fold 3
  • Samsung TAB models
  • Samsung TAB A series
  • Samsung TAB S Series
  • Samsung TAB E series
Browse Categories
  • Personal care, beauty and well-being
    • Hair dryer
    • Shaving and hair removal
Browse Categories
  • Huawei
    • Huawei P Models
      • Huawei P40 pro
      • Huawei P40 Lite
      • Huawei P40
      • Huawei P30 Pro
      • Huawei P30 Lite
      • Huawei P30
      • Huawei P20 Pro
      • Huawei P20 Lite 2019
      • Huawei P20 Lite
      • Huawei P20
      • Huawei P10 Lite
      • Huawei P10
      • Huawei P9 Lite
      • Huawei P9
      • Huawei P8 Lite
      • Huawei P8
      • Huawei P7
    • Huawei Mate Models
      • Huawei Mate 40 Pro
      • Huawei Mate 40
      • Huawei Mate 30 Pro
      • Huawei Mate 30 Lite
      • Huawei Mate 30
      • Huawei Mate 20 Pro
      • Huawei Mate 20 Lite
      • Huawei Mate 20
      • Huawei Mate 10 Pro
      • Huawei Mate 10 Lite
      • Huawei Mate 10
      • Huawei Mate 9 pro
      • Huawei Mate 9
      • Huawei Mate 8
      • Huawei Mate 7
    • Huawei P smart Models
      • Huawei P smart 2021
      • Huawei P smart 2020
      • Huawei P smart 2019
      • Huawei P smart pro
      • Huawei P smart Z
    • Huawei Honor Models
      • Huawei Honor 20 Pro
      • Huawei Honor 20 Lite
      • Huawei Honor View 20
      • Huawei Honor 20
      • Huawei Honor View 10
      • Huawei Honor 10
      • Huawei Honor 9
      • Huawei Honor 8 Lite
      • Huawei Honor 8
      • Huawei Honor 7
      • Huawei Honor 6
Browse Categories
  • Electronics
    • Headset , audio jack
    • Adapters
    • Cables
    • Car adapter , cables
    • Wirless charger
    • Bluetooth Speaker
    • HDMI , converter
    • Oudio Other
    • Gaming
    • Internet cables
    • Power bank
Browse Categories
  • Tempered Glass
    • OG tempered Glass
      • Iphone
      • Samsung
    • UV tempered Glass
      • Samsung
      • Huawei
    • Iphone camera Lens
    • Samsung camera lens
    • Ipad 3D
    • Samsung TAB
    • Apple Watch
    • Samsung watch
Browse Categories
  • Childeren toys
    • Car , Motor
Reparation
  • Home
  • Electronics
  • Mobile, tablet , smart watches
  • Repare Phone Price
  • Accessories
  • Tempered Glass
View cart “Apple 5W home adapter” has been added to your cart.
Click to enlarge
HomebrandsHoco E15 Rede wireless earphone
Previous product
Samsung galaxcy A56 , A 55 tempered glass 279.57 €
Back to products
Next product
Samsung galaxcy A60 tempered glass 279.57 €
Hoco

E15 Rede wireless earphone

747.07 €

1. Material: ABS

2. Size: 105*55*30mm; Weight: 23g

3. Wireless version: 4.1; Wireless chip: JL AC6973

4. Battery capacity: 90mAh; Charging time: 3h

5. Talk and music time: 4h, standby time: 80h

6. Language supported: Chinese and English

7. The part contacting ears is 360 soft material, providing comfortable wearing

8. The Mic rod rotating in 270°, the earhook rotating in 180°, applicable to both ears for wearing

9..Voice prompt switch:When powered on, press and hold the music play/pause button for 2 seconds and there will be a beep

Brand

Hoco

29 in stock

Compare
Add to wishlist
SKU: A101A Categories: Electronics, Headset , audio jack, Hoco Tags: electronics, headset
  • Description
  • Reviews (0)
  • About brand
  • Shipping & Delivery
Description

1. Material: ABS

2. Size: 105*55*30mm; Weight: 23g

3. Wireless version: 4.1; Wireless chip: JL AC6973

4. Battery capacity: 90mAh; Charging time: 3h

5. Talk and music time: 4h, standby time: 80h

6. Language supported: Chinese and English

7. The part contacting ears is 360 soft material, providing comfortable wearing

8. The Mic rod rotating in 270°, the earhook rotating in 180°, applicable to both ears for wearing

9..Voice prompt switch:When powered on, press and hold the music play/pause button for 2 seconds and there will be a beep

Reviews (0)

Reviews

There are no reviews yet.

Be the first to review “E15 Rede wireless earphone” Cancel reply

Your email address will not be published. Required fields are marked *

About brand
HOCO TECHNOLOGY has established the brand “hoco.” since its initial establishment in 2009. Through many years development, the brand “hoco.” has developed into a globally famous brand of digital and mobile phone spare parts.
Shipping & Delivery

MAECENAS IACULIS

Vestibulum curae torquent diam diam commodo parturient penatibus nunc dui adipiscing convallis bulum parturient suspendisse parturient a.Parturient in parturient scelerisque nibh lectus quam a natoque adipiscing a vestibulum hendrerit et pharetra fames nunc natoque dui.

ADIPISCING CONVALLIS BULUM

  • Vestibulum penatibus nunc dui adipiscing convallis bulum parturient suspendisse.
  • Abitur parturient praesent lectus quam a natoque adipiscing a vestibulum hendre.
  • Diam parturient dictumst parturient scelerisque nibh lectus.

Scelerisque adipiscing bibendum sem vestibulum et in a a a purus lectus faucibus lobortis tincidunt purus lectus nisl class eros.Condimentum a et ullamcorper dictumst mus et tristique elementum nam inceptos hac parturient scelerisque vestibulum amet elit ut volutpat.

Related products

Compare
Quick view
Add to wishlist
Close

IDeal Wireless QI Charger

Rated 0 out of 5
13 left in stock
373.07 €
Add to cart
Compare
Quick view
Add to wishlist
Close

EW29 True wireless headset

Rated 0 out of 5
9 left in stock
840.57 €
Add to cart
Compare
Quick view
Add to wishlist
Close

Apple 18W USB-C Adapter

Rated 0 out of 5
10 left in stock
204.77 €
Add to cart
Compare
Quick view
Add to wishlist
Close

X71 charging cable for IPhone 1M

Rated 0 out of 5
24 left in stock
139.32 €
Add to cart
Compare
Quick view
Add to wishlist
Close

Apple USB-C Headphone Jack

Rated 0 out of 5
22 left in stock
167.37 €
Add to cart
Compare
Quick view
Add to wishlist
Close

X71 PD charging cable for Iphone 1M

Rated 0 out of 5
42 left in stock
139.32 €
Add to cart
Compare
Quick view
Add to wishlist
Close

Samsung Jack USB-C til 3.5 mm

Rated 0 out of 5
Only 1 left in stock
167.37 €
Add to cart
Compare
Quick view
Add to wishlist
Close

Apple 20W USB-C Adapter

Rated 0 out of 5
10 left in stock
232.82 €
Add to cart
Samsung
OG
Luxury clear magnetic
IDEAL OF SWEDEN
Hoco
Gorilla Anti-Shock
Fashion
Celly Hello world
BOROFONE
Apple
AMA Extra pas
AMA
Adidas

Vi startet reisen vår i 2017, da etterspørselen etter reparasjoner og reservedeler til mobiltelefoner og nettbrett økte betraktelig. Alibaba Telecom AS åpnet sin første butikk på AMFI sentrum i Larvik og videre åpnet nye avdelinger i forskjellige byer. Alibaba Telecom AS ble en av de største leverandøren i Norden, med et stort lager på mer enn 100 000 høykvalitetsprodukter. .

Storgata 107, 3921 Porsgrunn, Norway
Phone: (0047) 48473337
Phone: (0047) 41201616
Recent Posts
  • Protected: drammen
    December 12, 2022 No Comments
  • Protected: stathelle
    December 12, 2022 No Comments
Useful links
  • ALIBABA TELECOM
  • Electronics
  • Accessories
  • Contact Us
  • Abuot US
Footer Menu
  • Home
  • reparation
  • faq
  • Contact Us
  • abute us
  • Shop
Hinet.co 2022 All rights of this website belong to alibabatelecom
payments
  • Home
  • Electronics
  • Mobile, tablet , smart watches
  • Repare Phone Price
  • Accessories
  • Tempered Glass
Shopping cart
close
Select your currency
NOK Norwegian krone
USD United States (US) dollar
EUR Euro

Sign in

close

Lost your password?

No account yet?

Create an Account