vendorInfluencerModel = new VendorInfluencerMappingModel(); $this->influencerPartnershipModel = new InfluencerPartnershipModel(); $this->statusHistoryModel = new VendorInfluencerStatusHistoryModel(); $this->vendorModel = new VendorModel(); $this->influencerModel = new InfluencerModel(); } /** * 벤더사 검색 (상태 정보 포함) */ public function searchVendors() { try { $request = $this->request->getJSON(); $influencerSeq = $request->influencerSeq ?? null; $keyword = $request->keyword ?? ''; $category = $request->category ?? ''; $region = $request->region ?? ''; $sortBy = $request->sortBy ?? 'latest'; $page = (int)($request->page ?? 1); $size = (int)($request->size ?? 12); if (!$influencerSeq) { return $this->response->setStatusCode(400)->setJSON([ 'success' => false, 'message' => '인플루언서 SEQ는 필수입니다.' ]); } // 필터 배열 구성 (VendorModel에 맞는 형식) $filters = [ 'keyword' => $keyword, 'category' => $category, 'region' => $region, 'sortBy' => $sortBy ]; // 벤더사 목록 조회 $vendors = $this->vendorModel->searchVendors($filters, $page, $size); $totalCount = $this->vendorModel->countSearchResults($filters); // 각 벤더사와의 파트너십 상태 확인 foreach ($vendors as &$vendor) { $partnership = $this->vendorInfluencerModel ->select('VENDOR_INFLUENCER_MAPPING.SEQ, VENDOR_INFLUENCER_MAPPING.REQUEST_TYPE, VENDOR_INFLUENCER_STATUS_HISTORY.STATUS as CURRENT_STATUS, VENDOR_INFLUENCER_STATUS_HISTORY.STATUS_MESSAGE, VENDOR_INFLUENCER_STATUS_HISTORY.CHANGED_DATE') ->join('VENDOR_INFLUENCER_STATUS_HISTORY', 'VENDOR_INFLUENCER_STATUS_HISTORY.MAPPING_SEQ = VENDOR_INFLUENCER_MAPPING.SEQ AND VENDOR_INFLUENCER_STATUS_HISTORY.IS_CURRENT = "Y"', 'left') ->where('VENDOR_SEQ', $vendor['SEQ']) ->where('INFLUENCER_SEQ', $influencerSeq) ->where('VENDOR_INFLUENCER_MAPPING.IS_ACT', 'Y') ->orderBy('VENDOR_INFLUENCER_MAPPING.REG_DATE', 'DESC') ->first(); if ($partnership) { $vendor['PARTNERSHIP_STATUS'] = $partnership['CURRENT_STATUS']; $vendor['PARTNERSHIP_SEQ'] = $partnership['SEQ']; $vendor['REQUEST_TYPE'] = $partnership['REQUEST_TYPE']; $vendor['STATUS_MESSAGE'] = $partnership['STATUS_MESSAGE']; $vendor['STATUS_DATE'] = $partnership['CHANGED_DATE']; } else { $vendor['PARTNERSHIP_STATUS'] = null; $vendor['PARTNERSHIP_SEQ'] = null; $vendor['REQUEST_TYPE'] = null; $vendor['STATUS_MESSAGE'] = null; $vendor['STATUS_DATE'] = null; } } // 페이지네이션 정보 계산 $totalPages = ceil($totalCount / $size); return $this->response->setJSON([ 'success' => true, 'data' => [ 'items' => $vendors, 'pagination' => [ 'currentPage' => $page, 'totalPages' => $totalPages, 'totalCount' => $totalCount, 'pageSize' => $size ] ] ]); } catch (\Exception $e) { log_message('error', '벤더사 검색 오류: ' . $e->getMessage()); log_message('error', '스택 트레이스: ' . $e->getTraceAsString()); return $this->response->setStatusCode(500)->setJSON([ 'success' => false, 'message' => '벤더사 검색 중 오류가 발생했습니다.', 'error' => $e->getMessage() ]); } } /** * 승인 요청 생성 */ public function createApprovalRequest() { try { $request = $this->request->getJSON(); $vendorSeq = $request->vendorSeq ?? null; $influencerSeq = $request->influencerSeq ?? null; $requestMessage = $request->requestMessage ?? ''; $requestedBy = $request->requestedBy ?? null; $commissionRate = $request->commissionRate ?? null; $specialConditions = $request->specialConditions ?? ''; if (!$vendorSeq || !$influencerSeq || !$requestedBy) { return $this->response->setStatusCode(400)->setJSON([ 'success' => false, 'message' => '필수 파라미터가 누락되었습니다.' ]); } // 데이터 구성 $data = [ 'VENDOR_SEQ' => $vendorSeq, 'INFLUENCER_SEQ' => $influencerSeq, 'REQUEST_MESSAGE' => $requestMessage, 'REQUESTED_BY' => $requestedBy, 'COMMISSION_RATE' => $commissionRate, 'SPECIAL_CONDITIONS' => $specialConditions ]; // InfluencerPartnershipModel을 통해 요청 생성 $mappingSeq = $this->influencerPartnershipModel->createApprovalRequest($data); return $this->response->setStatusCode(201)->setJSON([ 'success' => true, 'message' => '승인 요청이 성공적으로 생성되었습니다.', 'data' => [ 'mappingSeq' => $mappingSeq, 'status' => 'PENDING' ] ]); } catch (\Exception $e) { log_message('error', '승인 요청 생성 오류: ' . $e->getMessage()); log_message('error', '스택 트레이스: ' . $e->getTraceAsString()); return $this->response->setStatusCode(500)->setJSON([ 'success' => false, 'message' => '승인 요청 생성에 실패했습니다.', 'error' => $e->getMessage() ]); } } /** * 재승인 요청 생성 (히스토리 테이블 기반) */ public function createReapplyRequest() { try { $request = $this->request->getJSON(); $vendorSeq = $request->vendorSeq ?? null; $influencerSeq = $request->influencerSeq ?? null; $requestMessage = $request->requestMessage ?? ''; $requestedBy = $request->requestedBy ?? null; $commissionRate = $request->commissionRate ?? null; $specialConditions = $request->specialConditions ?? ''; log_message('debug', '재승인 요청 파라미터: ' . json_encode([ 'vendorSeq' => $vendorSeq, 'influencerSeq' => $influencerSeq, 'requestedBy' => $requestedBy ])); if (!$vendorSeq || !$influencerSeq || !$requestedBy) { return $this->response->setStatusCode(400)->setJSON([ 'success' => false, 'message' => '필수 파라미터가 누락되었습니다.' ]); } // 재승인 가능한 파트너십 확인 (TERMINATED 또는 REJECTED 상태) $eligiblePartnership = $this->vendorInfluencerModel->checkReapplyEligiblePartnership($vendorSeq, $influencerSeq); if (!$eligiblePartnership) { return $this->response->setStatusCode(400)->setJSON([ 'success' => false, 'message' => '재승인을 요청할 수 있는 이전 파트너십이 없습니다.' ]); } // 이미 재승인 요청 중인지 확인 $existingReapply = $this->vendorInfluencerModel->checkExistingPendingRequest($vendorSeq, $influencerSeq); if ($existingReapply) { return $this->response->setStatusCode(409)->setJSON([ 'success' => false, 'message' => '이미 재승인 요청이 진행 중입니다.' ]); } // 재승인 요청 생성 $data = [ 'VENDOR_SEQ' => $vendorSeq, 'INFLUENCER_SEQ' => $influencerSeq, 'REQUEST_TYPE' => 'INFLUENCER_REAPPLY', 'REQUEST_MESSAGE' => $requestMessage, 'REQUESTED_BY' => $requestedBy, 'COMMISSION_RATE' => $commissionRate ?: $eligiblePartnership['COMMISSION_RATE'], 'SPECIAL_CONDITIONS' => $specialConditions ?: $eligiblePartnership['SPECIAL_CONDITIONS'], 'ADD_INFO1' => 'REAPPLY', 'ADD_INFO2' => $eligiblePartnership['SEQ'], // 이전 파트너십 SEQ 'ADD_INFO3' => date('Y-m-d H:i:s') // 재신청 일시 ]; $mappingSeq = $this->vendorInfluencerModel->insert($data); // afterInsert 콜백에서 자동으로 PENDING 상태 히스토리 생성됨 if ($mappingSeq) { log_message('debug', "재승인 요청 성공 - 새 매핑 SEQ: " . $mappingSeq); return $this->response->setStatusCode(201)->setJSON([ 'success' => true, 'message' => '재승인 요청이 성공적으로 생성되었습니다.', 'data' => [ 'mappingSeq' => $mappingSeq, 'status' => 'PENDING', 'isReapply' => true, 'previousPartnership' => $eligiblePartnership['SEQ'] ] ]); } else { log_message('error', '재승인 요청 삽입 실패'); return $this->response->setStatusCode(500)->setJSON([ 'success' => false, 'message' => '재승인 요청 데이터 삽입에 실패했습니다.' ]); } } catch (\Exception $e) { log_message('error', '재승인 요청 처리 중 예외 발생: ' . $e->getMessage()); log_message('error', '재승인 요청 스택 트레이스: ' . $e->getTraceAsString()); return $this->response->setStatusCode(500)->setJSON([ 'success' => false, 'message' => '재승인 요청 생성 중 오류가 발생했습니다.', 'error' => $e->getMessage() ]); } } /** * 내 파트너십 목록 조회 (상태 히스토리 포함) */ public function getMyPartnerships() { try { $request = $this->request->getJSON(); $influencerSeq = $request->influencerSeq ?? null; $status = $request->status ?? null; $page = $request->page ?? 1; $size = $request->size ?? 20; if (!$influencerSeq) { return $this->response->setStatusCode(400)->setJSON([ 'success' => false, 'message' => '인플루언서 SEQ는 필수입니다.' ]); } $result = $this->influencerPartnershipModel->getInfluencerPartnerships($influencerSeq, $page, $size, $status); return $this->response->setJSON([ 'success' => true, 'data' => $result['data'], 'pagination' => $result['pagination'] ]); } catch (\Exception $e) { log_message('error', '파트너십 목록 조회 오류: ' . $e->getMessage()); return $this->response->setStatusCode(500)->setJSON([ 'success' => false, 'message' => '파트너십 목록 조회 중 오류가 발생했습니다.', 'error' => $e->getMessage() ]); } } /** * 파트너십 해지 (히스토리 테이블 기반) */ public function terminatePartnership() { try { $request = $this->request->getJSON(); $mappingSeq = $request->mappingSeq ?? null; $reason = $request->reason ?? ''; $terminatedBy = $request->terminatedBy ?? null; if (!$mappingSeq || !$terminatedBy) { return $this->response->setStatusCode(400)->setJSON([ 'success' => false, 'message' => '필수 파라미터가 누락되었습니다.' ]); } // 현재 상태 확인 $mapping = $this->vendorInfluencerModel->getWithCurrentStatus($mappingSeq); if (!$mapping) { return $this->response->setStatusCode(404)->setJSON([ 'success' => false, 'message' => '해당 파트너십을 찾을 수 없습니다.' ]); } if ($mapping['CURRENT_STATUS'] !== 'APPROVED') { return $this->response->setStatusCode(400)->setJSON([ 'success' => false, 'message' => '승인된 파트너십만 해지할 수 있습니다.' ]); } // 상태를 TERMINATED로 변경 $this->statusHistoryModel->changeStatus($mappingSeq, 'TERMINATED', '파트너십 해지: ' . $reason, $terminatedBy); // 해지 날짜 업데이트 $this->vendorInfluencerModel->update($mappingSeq, [ 'PARTNERSHIP_END_DATE' => date('Y-m-d H:i:s') ]); return $this->response->setJSON([ 'success' => true, 'message' => '파트너십이 해지되었습니다.', 'data' => [ 'mappingSeq' => $mappingSeq, 'status' => 'TERMINATED' ] ]); } catch (\Exception $e) { log_message('error', '파트너십 해지 오류: ' . $e->getMessage()); return $this->response->setStatusCode(500)->setJSON([ 'success' => false, 'message' => '파트너십 해지 중 오류가 발생했습니다.', 'error' => $e->getMessage() ]); } } /** * 인플루언서 프로필 조회 */ public function getProfile() { try { $request = $this->request->getJSON(); $influencerSeq = $request->influencerSeq ?? null; if (!$influencerSeq) { return $this->response->setStatusCode(400)->setJSON([ 'success' => false, 'message' => '인플루언서 SEQ는 필수입니다.' ]); } $profile = $this->influencerModel ->where('SEQ', $influencerSeq) ->where('IS_ACT', 'Y') ->first(); if (!$profile) { return $this->response->setStatusCode(404)->setJSON([ 'success' => false, 'message' => '인플루언서를 찾을 수 없습니다.' ]); } return $this->response->setJSON([ 'success' => true, 'data' => $profile ]); } catch (\Exception $e) { log_message('error', '인플루언서 프로필 조회 오류: ' . $e->getMessage()); return $this->response->setStatusCode(500)->setJSON([ 'success' => false, 'message' => '프로필 조회 중 오류가 발생했습니다.', 'error' => $e->getMessage() ]); } } }