cart_svc) { $this->cart_svc = new CartService($this); } return $this->cart_svc; } private function checkout_service(): CheckoutService { if (!$this->checkout_svc) { $this->checkout_svc = new CheckoutService($this); } return $this->checkout_svc; } private function address_service(): AddressService { if (!$this->address_svc) { $this->address_svc = new AddressService($this); } return $this->address_svc; } private function product_service(): ProductService { if ($this->product_svc === null) { $this->product_svc = new ProductService($this); } return $this->product_svc; } public function get_config(): array { if (class_exists('\AKSRT\Settings\Settings')) { return \AKSRT\Settings\Settings::get_shop_settings(); } return ['enabled' => false]; } public function get_products(array $args = []): array { $limit = max(1, (int) ($args['limit'] ?? 20)); $offset = max(0, (int) ($args['offset'] ?? 0)); $search = sanitize_text_field((string) ($args['search'] ?? '')); $status = sanitize_key((string) ($args['status'] ?? '')); $query_args = [ 'post_type' => 'aksrt_product', 'posts_per_page' => $limit, 'offset' => $offset, 'post_status' => $status !== '' ? $status : ['publish', 'draft', 'pending'], 'orderby' => 'date', 'order' => 'DESC', ]; if ($search !== '') { $query_args['s'] = $search; } $query = new \WP_Query($query_args); $products = []; while ($query->have_posts()) { $query->the_post(); $products[] = $this->build_product_card_view(get_the_ID()); } wp_reset_postdata(); return $products; } public function get_product_detail_view(int $product_id): array { $product = get_post($product_id); if (!$product || $product->post_type !== 'aksrt_product') { return []; } $detail = $this->build_product_card_view($product_id); $detail['content'] = (string) $product->post_content; $detail['excerpt'] = (string) $product->post_excerpt; $detail['permalink'] = get_permalink($product_id) ?: ''; $detail['status'] = (string) get_post_status($product_id); $detail['gallery'] = $this->product_service()->get_product_gallery($product_id); $detail['categories'] = wp_get_post_terms($product_id, 'aksrt_product_cat', ['fields' => 'all']) ?: []; $detail['tags'] = wp_get_post_terms($product_id, 'aksrt_product_tag', ['fields' => 'all']) ?: []; $detail['shipping'] = $this->product_service()->get_product_shipping_profile($product_id); $detail['after_sale'] = $this->product_service()->get_product_after_sale_profile($product_id); $detail['marketing'] = $this->product_service()->get_product_marketing_profile($product_id); $detail['checkout_hint'] = $this->checkout_service()->get_checkout_hint($detail); $detail['purchase_enabled'] = ($detail['is_unlimited'] || $detail['stock'] > 0) && $detail['status'] === 'publish'; $detail['default_quantity'] = 1; $detail['options'] = $this->get_product_options($product_id); $detail['has_options'] = $this->has_options($product_id); $detail['price_range'] = $this->get_price_range($product_id); $detail['pay_modo'] = sanitize_key((string) get_post_meta($product_id, '_aksrt_pay_modo', true)) ?: '0'; $detail['start_price'] = (float) get_post_meta($product_id, '_aksrt_start_price', true); $detail['shipping_type'] = sanitize_key((string) get_post_meta($product_id, '_aksrt_shipping_type', true)) ?: 'express'; $detail['auto_delivery'] = $this->get_auto_delivery_config($product_id); $detail['limit_buy'] = $this->get_limit_buy_config($product_id); $detail['services'] = $this->get_product_services($product_id); $detail['params'] = $this->get_product_params($product_id); return $detail; } public function get_product_edit_view(int $user_id, int $product_id = 0): array { $view = [ 'allowed' => true, 'is_edit' => false, 'product' => [ 'id' => 0, 'title' => '', 'price' => 0, 'stock' => 0, 'excerpt' => '', 'content' => '', 'image' => '', 'gallery' => [], 'categories' => [], 'tags' => [], 'shipping_mode' => 'express', 'shipping_fee' => 0, 'after_sale_policy' => '', 'support_refund' => true, 'status' => 'draft', 'options' => [], 'pay_modo' => '0', 'start_price' => 0, 'product_video' => [], 'product_params' => '', ], 'taxonomy' => [ 'categories' => $this->product_service()->get_term_options('aksrt_product_cat'), 'tags' => $this->product_service()->get_term_options('aksrt_product_tag'), ], 'shipping_modes' => $this->get_shipping_method_options(), 'status_options' => [ ['value' => 'draft', 'label' => __('草稿', 'aksrt')], ['value' => 'publish', 'label' => __('发布', 'aksrt')], ['value' => 'pending', 'label' => __('待审核', 'aksrt')], ], ]; if ($product_id <= 0) { return $view; } $product = get_post($product_id); if (!$product || $product->post_type !== 'aksrt_product') { return $view; } $is_owner = (int) $product->post_author === $user_id || current_user_can('manage_options'); if (!$is_owner) { $view['allowed'] = false; return $view; } $view['is_edit'] = true; $videos = get_post_meta($product_id, '_aksrt_product_video', true); if (!is_array($videos)) { $videos = []; } $view['product'] = [ 'id' => $product_id, 'title' => (string) $product->post_title, 'price' => (float) get_post_meta($product_id, '_aksrt_price', true), 'stock' => (int) get_post_meta($product_id, '_aksrt_stock', true), 'excerpt' => (string) $product->post_excerpt, 'content' => (string) $product->post_content, 'image' => $this->resolve_main_image($product_id), 'gallery' => $this->product_service()->get_product_gallery($product_id), 'categories' => wp_get_post_terms($product_id, 'aksrt_product_cat', ['fields' => 'ids']) ?: [], 'tags' => wp_get_post_terms($product_id, 'aksrt_product_tag', ['fields' => 'names']) ?: [], 'shipping_mode' => sanitize_key((string) get_post_meta($product_id, '_aksrt_shipping_mode', true)) ?: 'express', 'shipping_fee' => (float) get_post_meta($product_id, '_aksrt_shipping_fee', true), 'after_sale_policy' => (string) get_post_meta($product_id, '_aksrt_after_sale_policy', true), 'support_refund' => get_post_meta($product_id, '_aksrt_support_refund', true) !== '0', 'status' => (string) get_post_status($product_id), 'options' => method_exists($this, 'get_product_options') ? $this->get_product_options($product_id) : [], 'pay_modo' => sanitize_key((string) get_post_meta($product_id, '_aksrt_pay_modo', true)) ?: '0', 'start_price' => (float) get_post_meta($product_id, '_aksrt_start_price', true), 'product_video' => array_values(array_filter(array_map('esc_url_raw', $videos))), 'product_params' => (string) get_post_meta($product_id, '_aksrt_product_params', true), ]; return $view; } public function get_cart_page_view(int $user_id): array { $pending_orders = $this->get_order_center_view($user_id, [ 'page' => 1, 'per_page' => 5, 'status' => \AKSRT\Payment\Order::STATUS_PENDING, ]); return [ 'payment_methods' => $this->get_payment_method_options(), 'shipping_methods' => $this->get_shipping_method_options(), 'address_book' => $this->get_address_book($user_id), 'coupon_enabled' => class_exists('\AKSRT\Payment\Coupon'), 'currency_symbol' => '¥', 'pending_orders' => $pending_orders['items'] ?? [], 'cart_items' => $this->get_cart($user_id), 'cart_count' => $this->get_cart_count($user_id), ]; } public function get_cart(int $user_id): array { return $this->cart_service()->get_cart($user_id); } public function get_cart_count(int $user_id): int { return $this->cart_service()->get_cart_count($user_id); } public function add_to_cart(int $user_id, int $product_id, string $options_string = '', int $count = 1): array { return $this->cart_service()->add_to_cart($user_id, $product_id, $options_string, $count); } public function reduce_from_cart(int $user_id, int $product_id, string $options_string = '', int $count = 1): array { return $this->cart_service()->reduce_from_cart($user_id, $product_id, $options_string, $count); } public function remove_from_cart(int $user_id, int $product_id, string $options_string = ''): array { return $this->cart_service()->remove_from_cart($user_id, $product_id, $options_string); } public function remove_multi_from_cart(int $user_id, array $items): array { return $this->cart_service()->remove_multi_from_cart($user_id, $items); } public function empty_cart(int $user_id): array { return $this->cart_service()->empty_cart($user_id); } public function validate_cart_item(int $product_id, string $options_string = '') { return $this->cart_service()->validate_cart_item($product_id, $options_string); } public function get_order_center_view(int $user_id, array $args = []): array { if (class_exists('\AKSRT\Payment\UserOrders')) { return \AKSRT\Payment\UserOrders::get_instance()->get_order_center_view($user_id, $args); } return ['items' => [], 'total' => 0, 'total_pages' => 1, 'page' => 1, 'stats' => [], 'product_types' => []]; } public function get_order_detail_view(int $user_id, string $order_number): ?array { if (class_exists('\AKSRT\Payment\UserOrders')) { return \AKSRT\Payment\UserOrders::get_instance()->get_order_detail_view($user_id, $order_number); } return null; } public function preview_checkout(int $user_id, array $payload): array { return $this->checkout_service()->preview_checkout($user_id, $payload); } public function create_checkout_order(int $user_id, array $payload): array { return $this->checkout_service()->create_checkout_order($user_id, $payload); } public function pay_order(int $user_id, string $order_number, string $payment_method): array { return $this->checkout_service()->pay_order($user_id, $order_number, $payment_method); } public function get_user_favorites(int $user_id, int $page = 1, int $per_page = 20): array { if ($user_id <= 0) { return ['items' => [], 'total' => 0]; } $fav_ids = get_user_meta($user_id, 'aksrt_product_favorites', true); if (!is_array($fav_ids) || empty($fav_ids)) { return ['items' => [], 'total' => 0]; } $total = count($fav_ids); $paged = array_slice(array_reverse($fav_ids), ($page - 1) * $per_page, $per_page); $items = []; foreach ($paged as $pid) { $card = $this->build_product_card_view((int) $pid); if (!empty($card)) { $items[] = $card; } } return ['items' => $items, 'total' => $total]; } public function toggle_favorite(int $user_id, int $product_id): array { if ($user_id <= 0 || $product_id <= 0) { return ['success' => false]; } $fav_ids = get_user_meta($user_id, 'aksrt_product_favorites', true); if (!is_array($fav_ids)) { $fav_ids = []; } $key = array_search($product_id, $fav_ids, true); if ($key !== false) { unset($fav_ids[$key]); $fav_ids = array_values($fav_ids); $is_fav = false; } else { $fav_ids[] = $product_id; $is_fav = true; } update_user_meta($user_id, 'aksrt_product_favorites', $fav_ids); $count = (int) get_post_meta($product_id, '_aksrt_favorite_count', true); update_post_meta($product_id, '_aksrt_favorite_count', max(0, $count + ($is_fav ? 1 : -1))); if ($is_fav) { do_action('aksrt_product_favorited', $user_id, $product_id); } else { do_action('aksrt_product_unfavorited', $user_id, $product_id); } return ['success' => true, 'is_favorite' => $is_fav, 'count' => count($fav_ids)]; } public function is_favorite(int $user_id, int $product_id): bool { if ($user_id <= 0) return false; $fav_ids = get_user_meta($user_id, 'aksrt_product_favorites', true); return is_array($fav_ids) && in_array($product_id, $fav_ids, true); } public function re_purchase(int $user_id, string $order_number): array { $items = $this->get_order_items($order_number); if (empty($items)) { return ['success' => false, 'message' => __('订单无商品记录', 'aksrt')]; } $added = 0; foreach ($items as $item) { $pid = (int) $item['product_id']; $qty = max(1, (int) $item['quantity']); $opt_key = (string) $item['options_key']; $result = $this->add_to_cart($user_id, $pid, $opt_key, $qty); if (!empty($result['success'])) { $added++; } } return ['success' => $added > 0, 'added' => $added, 'cart_count' => $this->get_cart_count($user_id)]; } public function cancel_order(int $user_id, string $order_number): array { if ($user_id <= 0 || $order_number === '' || !class_exists('\AKSRT\Payment\OrderRepository')) { return ['success' => false, 'message' => __('订单不存在。', 'aksrt')]; } $repo = \AKSRT\Payment\OrderRepository::get_instance(); $order = $repo->get_user_order($user_id, $order_number); if (!$order) { return ['success' => false, 'message' => __('订单不存在。', 'aksrt')]; } $status = (string) ($order['status'] ?? ''); if (!in_array($status, [\AKSRT\Payment\Order::STATUS_PENDING, \AKSRT\Payment\Order::STATUS_CREATED, \AKSRT\Payment\Order::STATUS_EXPIRED], true)) { return ['success' => false, 'message' => __('当前订单不可取消。', 'aksrt')]; } $repo->update_status($order_number, \AKSRT\Payment\Order::STATUS_CANCELLED, [ 'force' => true, 'note' => __('用户在前台取消订单。', 'aksrt'), ]); return [ 'success' => true, 'data' => [ 'order' => $this->get_order_detail_view($user_id, $order_number), ], ]; } }