*/ public function toArray(Request $request): array { if (!$this->resource) { return []; } return [ 'customer' => [ 'fullname' => $this->fullname, 'email' => $this->email, 'phone' => $this->phone, 'address' => $this->address, 'city' => $this->city, 'ward' => $this->ward->name ?? '', 'province' => $this->province->name ?? '', 'gender' => $this->gender_label, 'date' => $this->created_at ? $this->created_at->format('Y-m-d H:i:s') : null, 'company' => $this->company ?? '', 'avatar' => $this->avatar, 'cmnd_before' => $this->cccdUrl('front', $this->front_identity_number), 'cmnd_after' => $this->cccdUrl('back', $this->back_identity_number), 'cmnd' => $this->identity_number ? Str::mask($this->identity_number, '*', 0, -4) : null, 'fb_link' => null, 'active_2fa' => 0, 'off_mail_marketing' => $this->off_mail_marketing, 'is_recharge_zalo' => 0, 'is_verify_telegram' => 0, ], 'credit' => [ 'credit' => $this->credit, 'total' => $this->total, 'total_pending' => $this->total_pending ?? 0, 'point' => $this->point, 'point_used' => 0, 'point_total' => $this->point, ], 'service' => [ 'proxy' => 0, ...app(ServiceClientService::class)->countByType((int) $this->id), ] ]; } /** * Ảnh CCCD trên disk private → URL ký tương đối (/v1/client/cccd/...), hết hạn 60 phút. */ private function cccdUrl(string $side, ?string $path): string { if (!$path) { return ''; } // Giá trị import từ portal cũ (/uploads/... trên host cũ) cũng chỉ trả URL ký — không lộ đường dẫn gốc; // route trả 404 cho chúng vì file không có trên disk private. Vẫn khác rỗng để hasCccd giữ nguyên hành vi. return URL::temporarySignedRoute('api.client.cccd', now()->addHour(), ['customer' => $this->id, 'side' => $side], false); } }