model = new \app\common\model\MallOrder(); } /** * 查看 * @throws Throwable */ public function index(Request $request): Response { $response = $this->initializeBackend($request); if ($response !== null) { return $response; } if ($request->get('select') || $request->post('select')) { return $this->select($request); } [$where, $alias, $limit, $order] = $this->queryBuilder(); $res = $this->model ->with(['mallItem' => function ($query) { $query->field('id,title'); }]) ->visible(['mallItem' => ['title']]) ->alias($alias) ->where($where) ->order($order) ->paginate($limit); return $this->success('', [ 'list' => $res->items(), 'total' => $res->total(), 'remark' => get_route_remark(), ]); } /** * PHYSICAL 发货:更新 shipping_company/shipping_no,并将状态置为 SHIPPED */ public function ship(Request $request): Response { $response = $this->initializeBackend($request); if ($response !== null) { return $response; } if ($request->method() !== 'POST') { return $this->error(__('Parameter error')); } $data = $request->post(); $id = $data['id'] ?? 0; $shippingCompany = $data['shipping_company'] ?? ''; $shippingNo = $data['shipping_no'] ?? ''; if (!$id || $shippingCompany === '' || $shippingNo === '') { return $this->error(__('Missing required fields')); } $order = MallOrder::where('id', $id)->find(); if (!$order) { return $this->error(__('Record not found')); } if ($order->type !== MallOrder::TYPE_PHYSICAL) { return $this->error(__('Order type not PHYSICAL')); } if ($order->status !== MallOrder::STATUS_PENDING) { return $this->error(__('Order status must be PENDING')); } Db::startTrans(); try { $order->shipping_company = $shippingCompany; $order->shipping_no = $shippingNo; $order->status = MallOrder::STATUS_SHIPPED; $order->save(); Db::commit(); } catch (Throwable $e) { Db::rollback(); return $this->error($e->getMessage()); } return $this->success(__('Shipped successfully')); } /** * 审核通过(非 PHYSICAL):更新状态为 COMPLETED */ public function approve(Request $request): Response { $response = $this->initializeBackend($request); if ($response !== null) { return $response; } if ($request->method() !== 'POST') { return $this->error(__('Parameter error')); } $id = $request->post('id', 0); if (!$id) { return $this->error(__('Missing required fields')); } $order = MallOrder::where('id', $id)->find(); if (!$order) { return $this->error(__('Record not found')); } if ($order->status !== MallOrder::STATUS_PENDING) { return $this->error(__('Order status must be PENDING')); } if ($order->type === MallOrder::TYPE_PHYSICAL) { return $this->error(__('Order type not supported')); } Db::startTrans(); try { $order->status = MallOrder::STATUS_COMPLETED; $order->update_time = time(); $order->save(); Db::commit(); } catch (Throwable $e) { Db::rollback(); return $this->error($e->getMessage()); } return $this->success(__('Approved successfully')); } /** * 审核驳回:更新状态为 REJECTED,并退回积分到 available_points(所有类型通用) */ public function reject(Request $request): Response { $response = $this->initializeBackend($request); if ($response !== null) { return $response; } if ($request->method() !== 'POST') { return $this->error(__('Parameter error')); } $data = $request->post(); $id = $data['id'] ?? 0; $rejectReason = $data['reject_reason'] ?? ''; if (!$id) { return $this->error(__('Missing required fields')); } $order = MallOrder::where('id', $id)->find(); if (!$order) { return $this->error(__('Record not found')); } if ($order->status !== MallOrder::STATUS_PENDING) { return $this->error(__('Order status must be PENDING')); } if ($order->type === MallOrder::TYPE_PHYSICAL && $rejectReason === '') { return $this->error(__('Missing required fields')); } Db::startTrans(); try { $asset = MallUserAsset::where('playx_user_id', $order->user_id ?? '')->find(); if (!$asset) { throw new \RuntimeException('User asset not found'); } $refund = $order->points_cost ?? 0; if ($refund > 0) { $asset->available_points += $refund; $asset->save(); } $order->status = MallOrder::STATUS_REJECTED; $order->reject_reason = $rejectReason; if ($order->type === MallOrder::TYPE_BONUS) { $order->grant_status = MallOrder::GRANT_FAILED_FINAL; } else { $order->grant_status = MallOrder::GRANT_NOT_APPLICABLE; } $order->update_time = time(); $order->save(); Db::commit(); } catch (Throwable $e) { Db::rollback(); return $this->error($e->getMessage()); } return $this->success(__('Rejected successfully')); } /** * 手动推送红利(同步调用 PlayX,不限制自动重试次数;成功则 ACCEPTED,失败写入 fail_reason) */ public function retry(Request $request): Response { $response = $this->initializeBackend($request); if ($response !== null) { return $response; } if ($request->method() !== 'POST') { return $this->error(__('Parameter error')); } $id = $request->post('id', 0); if (!$id) { return $this->error(__('Missing required fields')); } $order = MallOrder::where('id', $id)->find(); if (!$order) { return $this->error(__('Record not found')); } if ($order->type !== MallOrder::TYPE_BONUS) { return $this->error(__('Only BONUS can retry')); } if ($order->status !== MallOrder::STATUS_PENDING) { return $this->error(__('Order status must be PENDING')); } $allowedStatuses = [ MallOrder::GRANT_NOT_SENT, MallOrder::GRANT_SENT_PENDING, MallOrder::GRANT_FAILED_RETRYABLE, MallOrder::GRANT_FAILED_FINAL, ]; if (!in_array($order->grant_status, $allowedStatuses, true)) { return $this->error(__('Current grant status cannot be manually pushed')); } if (strval(config('playx.api.base_url', '')) === '') { return $this->error(__('PlayX API not configured')); } $result = MallBonusGrantPush::push($order); if ($result['ok']) { $order->grant_status = MallOrder::GRANT_ACCEPTED; $order->playx_transaction_id = $result['playx_transaction_id']; $order->fail_reason = null; $order->update_time = time(); $order->save(); return $this->success(__('Push succeeded')); } $failReason = __('Manual push failed') . ': ' . $result['message']; $order->fail_reason = $failReason; $order->grant_status = MallOrder::GRANT_FAILED_FINAL; $order->update_time = time(); $order->save(); return $this->error($failReason); } }