where('sales_progress', 100) ->where('manager_progress', 100) ->where('hq_status', SalesTenantManagement::HQ_STATUS_PENDING) ->count(); // 개발 진행 중 (review ~ int_test) $progressStatuses = [ SalesTenantManagement::HQ_STATUS_REVIEW, SalesTenantManagement::HQ_STATUS_PLANNING, SalesTenantManagement::HQ_STATUS_CODING, SalesTenantManagement::HQ_STATUS_DEV_TEST, SalesTenantManagement::HQ_STATUS_DEV_DONE, SalesTenantManagement::HQ_STATUS_INT_TEST, ]; $inProgressCount = SalesTenantManagement::query() ->where('sales_progress', 100) ->where('manager_progress', 100) ->whereIn('hq_status', $progressStatuses) ->count(); // 오늘 완료 (handover 상태이고 오늘 업데이트된) $todayCompletedCount = SalesTenantManagement::query() ->where('hq_status', SalesTenantManagement::HQ_STATUS_HANDOVER) ->whereDate('updated_at', today()) ->count(); // 총 완료 $totalCompletedCount = SalesTenantManagement::query() ->where('hq_status', SalesTenantManagement::HQ_STATUS_HANDOVER) ->count(); return [ 'pending' => $pendingCount, 'in_progress' => $inProgressCount, 'today_completed' => $todayCompletedCount, 'total_completed' => $totalCompletedCount, ]; } /** * 승인 대기 목록 조회 */ public function getPendingApprovals(?string $search = null, int $perPage = 10): LengthAwarePaginator { $query = SalesTenantManagement::query() ->with(['tenant', 'tenantProspect.registeredBy', 'salesPartner.user', 'manager']) ->where('sales_progress', 100) ->where('manager_progress', 100) ->where('hq_status', SalesTenantManagement::HQ_STATUS_PENDING); // 검색 if ($search) { $query->whereHas('tenant', function ($q) use ($search) { $q->where('company_name', 'like', "%{$search}%") ->orWhere('business_number', 'like', "%{$search}%"); }); } return $query->latest('updated_at')->paginate($perPage, ['*'], 'pending_page'); } /** * 개발 진행 중 목록 조회 */ public function getInProgressItems(?string $search = null, int $perPage = 10): LengthAwarePaginator { $progressStatuses = [ SalesTenantManagement::HQ_STATUS_REVIEW, SalesTenantManagement::HQ_STATUS_PLANNING, SalesTenantManagement::HQ_STATUS_CODING, SalesTenantManagement::HQ_STATUS_DEV_TEST, SalesTenantManagement::HQ_STATUS_DEV_DONE, SalesTenantManagement::HQ_STATUS_INT_TEST, ]; $query = SalesTenantManagement::query() ->with(['tenant', 'tenantProspect.registeredBy', 'salesPartner.user', 'manager']) ->where('sales_progress', 100) ->where('manager_progress', 100) ->whereIn('hq_status', $progressStatuses); // 검색 if ($search) { $query->whereHas('tenant', function ($q) use ($search) { $q->where('company_name', 'like', "%{$search}%") ->orWhere('business_number', 'like', "%{$search}%"); }); } return $query->latest('updated_at')->paginate($perPage, ['*'], 'progress_page'); } /** * 완료 목록 조회 */ public function getCompletedItems(?string $search = null, int $perPage = 10): LengthAwarePaginator { $query = SalesTenantManagement::query() ->with(['tenant', 'tenantProspect.registeredBy', 'salesPartner.user', 'manager']) ->where('hq_status', SalesTenantManagement::HQ_STATUS_HANDOVER); // 검색 if ($search) { $query->whereHas('tenant', function ($q) use ($search) { $q->where('company_name', 'like', "%{$search}%") ->orWhere('business_number', 'like', "%{$search}%"); }); } return $query->latest('updated_at')->paginate($perPage, ['*'], 'completed_page'); } /** * 개발 승인 처리 (pending → review) */ public function approve(int $id): SalesTenantManagement { $management = SalesTenantManagement::findOrFail($id); // 승인 조건 확인 if ($management->sales_progress < 100 || $management->manager_progress < 100) { throw new \InvalidArgumentException('영업/매니저 진행률이 100%가 아닙니다.'); } if ($management->hq_status !== SalesTenantManagement::HQ_STATUS_PENDING) { throw new \InvalidArgumentException('이미 승인된 항목입니다.'); } $management->update([ 'hq_status' => SalesTenantManagement::HQ_STATUS_REVIEW, ]); return $management->fresh(); } /** * 반려 처리 */ public function reject(int $id, string $reason): SalesTenantManagement { $management = SalesTenantManagement::findOrFail($id); if ($management->hq_status !== SalesTenantManagement::HQ_STATUS_PENDING) { throw new \InvalidArgumentException('승인 대기 상태가 아닙니다.'); } // notes 필드에 반려 사유 추가 $currentNotes = $management->notes ?? ''; $rejectionNote = '[반려 '.now()->format('Y-m-d H:i').'] '.$reason; $newNotes = $currentNotes ? $currentNotes."\n".$rejectionNote : $rejectionNote; $management->update([ 'notes' => $newNotes, ]); return $management->fresh(); } /** * 본사 진행 상태 업데이트 */ public function updateHqStatus(int $id, string $status): SalesTenantManagement { $management = SalesTenantManagement::findOrFail($id); // 유효한 상태인지 확인 if (! array_key_exists($status, SalesTenantManagement::$hqStatusLabels)) { throw new \InvalidArgumentException('유효하지 않은 상태입니다.'); } // pending 상태에서는 review로만 변경 가능 (승인 처리) if ($management->hq_status === SalesTenantManagement::HQ_STATUS_PENDING && $status !== SalesTenantManagement::HQ_STATUS_REVIEW) { throw new \InvalidArgumentException('승인 대기 상태에서는 검토 상태로만 변경 가능합니다. 먼저 승인 처리를 해주세요.'); } $management->update([ 'hq_status' => $status, ]); return $management->fresh(); } /** * 승인대기로 되돌리기 (진행중 → pending) */ public function revertToPending(int $id): SalesTenantManagement { $management = SalesTenantManagement::findOrFail($id); // 이미 pending 상태인 경우 if ($management->hq_status === SalesTenantManagement::HQ_STATUS_PENDING) { throw new \InvalidArgumentException('이미 승인대기 상태입니다.'); } // handover(인계) 상태에서는 되돌리기 불가 if ($management->hq_status === SalesTenantManagement::HQ_STATUS_HANDOVER) { throw new \InvalidArgumentException('인계 완료된 항목은 되돌릴 수 없습니다.'); } $management->update([ 'hq_status' => SalesTenantManagement::HQ_STATUS_PENDING, ]); return $management->fresh(); } /** * 상세 정보 조회 */ public function getDetail(int $id): SalesTenantManagement { return SalesTenantManagement::with([ 'tenant', 'tenantProspect', 'salesPartner.user', 'manager', 'contractProducts.product', ])->findOrFail($id); } }