success(['data' => ['items' => [], 'total' => 0, 'page' => 1, 'max_pages' => 1]]); } $page = max(1, (int) $request->get_param('page')); $per_page = max(1, min(100, (int) $request->get_param('per_page'))) ?: 20; $status = sanitize_key((string) $request->get_param('status')); $stage = sanitize_key((string) $request->get_param('stage')); $order = sanitize_text_field((string) $request->get_param('order_number')); $type = sanitize_key((string) $request->get_param('type')); $date_from = sanitize_text_field((string) $request->get_param('date_from')); $date_to = sanitize_text_field((string) $request->get_param('date_to')); $result = \AKSRT\Payment\AfterSale::get_instance()->get_list([ 'limit' => $per_page, 'offset' => ($page - 1) * $per_page, 'status' => $status, 'stage' => $stage, 'order_number' => $order, 'type' => $type, 'date_from' => $date_from, 'date_to' => $date_to, 'include_order_context' => true, ]); $stats = \AKSRT\Payment\AfterSale::get_instance()->get_stats(); return $this->success(['data' => array_merge($result, [ 'stats' => $stats, 'filters' => [ 'status' => $status, 'stage' => $stage, 'order_number' => $order, 'type' => $type, 'date_from' => $date_from, 'date_to' => $date_to, ], 'options' => [ 'status' => \AKSRT\Payment\AfterSale::get_status_options(), 'stage' => \AKSRT\Payment\AfterSale::get_stage_options(), 'type' => \AKSRT\Payment\AfterSale::get_type_options(), ], ])]); } /** * POST /shop/after-sale — 创建售后工单 */ public function create_after_sale(\WP_REST_Request $request): \WP_REST_Response { if (!class_exists('\AKSRT\Payment\AfterSale')) { return $this->error('售后系统未启用', 500); } $params = $this->get_json_params($request); $order_number = sanitize_text_field((string) ($params['order_number'] ?? '')); $reason = sanitize_textarea_field((string) ($params['reason'] ?? '')); if ($order_number === '' || $reason === '') { return $this->error('订单号和原因不能为空'); } $order = class_exists('\AKSRT\Payment\OrderRepository') ? \AKSRT\Payment\OrderRepository::get_instance()->get($order_number) : null; if (!$order) { return $this->error(__('订单不存在', 'aksrt'), 404); } unset($params['user_id'], $params['applicant_user_id']); $id = \AKSRT\Payment\AfterSale::get_instance()->create($params); if (is_wp_error($id)) { return $this->error($id->get_error_message(), 422); } if ($id > 0) { return $this->success([ 'message' => __('售后工单已创建', 'aksrt'), 'data' => ['id' => $id], ], 201); } return $this->error(__('创建失败', 'aksrt')); } /** * POST /shop/after-sale/{id}/update-status — 更新售后工单状态 */ public function update_after_sale_status(\WP_REST_Request $request): \WP_REST_Response { if (!class_exists('\AKSRT\Payment\AfterSale')) { return $this->error('售后系统未启用', 500); } $id = (int) $request->get_param('id'); $params = $this->get_json_params($request); $new_status = sanitize_key((string) ($params['status'] ?? '')); $note = sanitize_textarea_field((string) ($params['operator_note'] ?? '')); if ($id <= 0 || $new_status === '') { return $this->error('参数无效'); } $success = \AKSRT\Payment\AfterSale::get_instance()->update_status( $id, $new_status, get_current_user_id(), $note ); if ($success) { return $this->success(['message' => __('状态已更新', 'aksrt')]); } return $this->error(__('更新失败', 'aksrt')); } /** * GET /shop/shipping — 发货记录列表 */ public function get_shipping_list(\WP_REST_Request $request): \WP_REST_Response { if (!class_exists('\AKSRT\Payment\Shipping')) { return $this->success(['data' => ['items' => [], 'total' => 0, 'page' => 1, 'max_pages' => 1]]); } $page = max(1, (int) $request->get_param('page')); $per_page = max(1, min(100, (int) $request->get_param('per_page'))) ?: 20; $status = sanitize_key((string) $request->get_param('status')); $order = sanitize_text_field((string) $request->get_param('order_number')); $date_from = sanitize_text_field((string) $request->get_param('date_from')); $date_to = sanitize_text_field((string) $request->get_param('date_to')); $tracking_no = sanitize_text_field((string) $request->get_param('tracking_no')); $result = \AKSRT\Payment\Shipping::get_instance()->get_list([ 'limit' => $per_page, 'offset' => ($page - 1) * $per_page, 'status' => $status, 'order_number' => $order, 'date_from' => $date_from, 'date_to' => $date_to, 'tracking_no' => $tracking_no, 'include_order_context' => true, ]); $stats = \AKSRT\Payment\Shipping::get_instance()->get_stats(); return $this->success(['data' => array_merge($result, [ 'stats' => $stats, 'filters' => [ 'status' => $status, 'order_number' => $order, 'date_from' => $date_from, 'date_to' => $date_to, 'tracking_no' => $tracking_no, ], 'options' => [ 'status' => \AKSRT\Payment\Shipping::get_status_options(), 'carrier' => \AKSRT\Payment\Shipping::get_carrier_options(), ], ])]); } /** * POST /shop/shipping — 创建发货记录 */ public function create_shipping(\WP_REST_Request $request): \WP_REST_Response { if (!class_exists('\AKSRT\Payment\Shipping')) { return $this->error('物流系统未启用', 500); } $params = $this->get_json_params($request); $order_number = sanitize_text_field((string) ($params['order_number'] ?? '')); $carrier = sanitize_text_field((string) ($params['carrier'] ?? '')); $tracking_no = sanitize_text_field((string) ($params['tracking_no'] ?? '')); if ($order_number === '' || $carrier === '' || $tracking_no === '') { return $this->error('订单号、快递公司和物流单号不能为空'); } $order = class_exists('\AKSRT\Payment\OrderRepository') ? \AKSRT\Payment\OrderRepository::get_instance()->get($order_number) : null; if (!$order) { return $this->error(__('订单不存在', 'aksrt'), 404); } $params['operator_id'] = get_current_user_id(); $id = \AKSRT\Payment\Shipping::get_instance()->create($params); if ($id > 0) { return $this->success([ 'message' => __('发货记录已创建', 'aksrt'), 'data' => ['id' => $id], ], 201); } return $this->error(__('创建失败', 'aksrt')); } /** * POST /shop/shipping/{id}/update-status — 更新发货状态 */ public function update_shipping_status(\WP_REST_Request $request): \WP_REST_Response { if (!class_exists('\AKSRT\Payment\Shipping')) { return $this->error('物流系统未启用', 500); } $id = (int) $request->get_param('id'); $params = $this->get_json_params($request); $new_status = sanitize_key((string) ($params['status'] ?? '')); $note = sanitize_textarea_field((string) ($params['note'] ?? '')); if ($id <= 0 || $new_status === '') { return $this->error('参数无效'); } $success = \AKSRT\Payment\Shipping::get_instance()->update_status($id, $new_status, $note, get_current_user_id()); if ($success) { return $this->success(['message' => __('状态已更新', 'aksrt')]); } return $this->error(__('更新失败', 'aksrt')); } public function get_after_sale_detail(\WP_REST_Request $request): \WP_REST_Response { if (!class_exists('\AKSRT\Payment\AfterSale')) { return $this->error('售后系统未启用', 500); } $id = (int) $request->get_param('id'); if ($id <= 0) { return $this->error('参数无效'); } $record = \AKSRT\Payment\AfterSale::get_instance()->get_with_order_context($id); if (!$record) { return $this->error(__('售后工单不存在', 'aksrt'), 404); } return $this->success([ 'data' => [ 'record' => $record, 'timeline' => $this->build_after_sale_timeline($record), ], ]); } public function get_shipping_detail(\WP_REST_Request $request): \WP_REST_Response { if (!class_exists('\AKSRT\Payment\Shipping')) { return $this->error('物流系统未启用', 500); } $id = (int) $request->get_param('id'); if ($id <= 0) { return $this->error('参数无效'); } $record = \AKSRT\Payment\Shipping::get_instance()->get_with_order_context($id); if (!$record) { return $this->error(__('发货记录不存在', 'aksrt'), 404); } return $this->success([ 'data' => [ 'record' => $record, 'timeline' => $this->build_shipping_timeline($record), ], ]); } public function batch_update_shipping_status(\WP_REST_Request $request): \WP_REST_Response { if (!class_exists('\AKSRT\Payment\Shipping')) { return $this->error('物流系统未启用', 500); } $params = $this->get_json_params($request); $ids = is_array($params['ids'] ?? null) ? $params['ids'] : []; $status = sanitize_key((string) ($params['status'] ?? '')); $note = sanitize_textarea_field((string) ($params['note'] ?? '')); if (empty($ids) || $status === '') { return $this->error('参数无效'); } $result = \AKSRT\Payment\Shipping::get_instance()->batch_update_status($ids, $status, $note, get_current_user_id()); return $this->success([ 'message' => __('批量状态更新已执行', 'aksrt'), 'data' => $result, ]); } private function build_shipping_timeline(array $record): array { $timeline = []; foreach ([ 'created_at' => __('创建发货记录', 'aksrt'), 'updated_at' => __('更新物流状态', 'aksrt'), 'delivered_at' => __('确认签收', 'aksrt'), ] as $field => $label) { if (!empty($record[$field])) { $timeline[] = [ 'time' => (string) $record[$field], 'label' => $label, ]; } } usort($timeline, static function ($a, $b) { return strcmp((string) ($a['time'] ?? ''), (string) ($b['time'] ?? '')); }); return $timeline; } private function build_after_sale_timeline(array $record): array { $timeline = []; foreach ([ 'created_at' => __('提交售后申请', 'aksrt'), 'updated_at' => __('更新售后状态', 'aksrt'), 'resolved_at' => __('售后处理结束', 'aksrt'), ] as $field => $label) { if (!empty($record[$field])) { $timeline[] = [ 'time' => (string) $record[$field], 'label' => $label, ]; } } usort($timeline, static function ($a, $b) { return strcmp((string) ($a['time'] ?? ''), (string) ($b['time'] ?? '')); }); return $timeline; } }