637 lines
36 KiB
PHP
637 lines
36 KiB
PHP
<?php
|
|
header("Content-Type: application/json; charset=utf-8");
|
|
require_once(__DIR__ . "/../../lib/mydb.php");
|
|
|
|
session_start();
|
|
|
|
$method = $_SERVER['REQUEST_METHOD'];
|
|
$action = $_GET['action'] ?? '';
|
|
|
|
if (!isset($_SESSION['sales_user'])) {
|
|
echo json_encode(['success' => false, 'error' => '로그인이 필요합니다.']);
|
|
exit;
|
|
}
|
|
|
|
$currentUser = $_SESSION['sales_user'];
|
|
$pdo = db_connect();
|
|
|
|
/**
|
|
* 테넌트에 대한 접근 권한 확인
|
|
*/
|
|
function checkTenantPermission($pdo, $tenant_id, $currentUser) {
|
|
if (!$tenant_id) return false;
|
|
if ($currentUser['role'] === 'operator') return true;
|
|
|
|
$stmt = $pdo->prepare("SELECT manager_id, sales_manager_id FROM sales_tenants WHERE id = ?");
|
|
$stmt->execute([$tenant_id]);
|
|
$tenant = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$tenant) return false;
|
|
|
|
// 매니저는 본인이 '담당 매니저'로 배정된 경우만 가능
|
|
if ($currentUser['role'] === 'manager') {
|
|
return $tenant['sales_manager_id'] == $currentUser['id'];
|
|
}
|
|
|
|
// 영업관리자는 본인이 등록했거나, 본인이 담당 매니저인 경우 가능
|
|
return ($tenant['manager_id'] == $currentUser['id'] || $tenant['sales_manager_id'] == $currentUser['id']);
|
|
}
|
|
|
|
// 테이블 자동 생성 (없을 경우)
|
|
$pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS `sales_tenants` (
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
`manager_id` int(11) NOT NULL COMMENT '영업한 영업관리자 ID',
|
|
`sales_manager_id` int(11) DEFAULT NULL COMMENT '매칭된 매니저 ID (영업관리자 본인 또는 별도 매니저)',
|
|
`tenant_name` varchar(200) NOT NULL,
|
|
`representative` varchar(100) DEFAULT NULL,
|
|
`business_no` varchar(20) DEFAULT NULL,
|
|
`contact_phone` varchar(20) DEFAULT NULL,
|
|
`email` varchar(100) DEFAULT NULL,
|
|
`address` varchar(500) DEFAULT NULL,
|
|
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
|
`updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
PRIMARY KEY (`id`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
CREATE TABLE IF NOT EXISTS `sales_tenant_products` (
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
`tenant_id` int(11) NOT NULL,
|
|
`product_name` varchar(200) NOT NULL,
|
|
`contract_amount` decimal(15,2) NOT NULL DEFAULT 0.00,
|
|
`commission_rate` decimal(5,2) NOT NULL DEFAULT 0.00,
|
|
`commission_amount` decimal(15,2) DEFAULT 0.00,
|
|
`contract_date` date DEFAULT NULL,
|
|
`operator_confirmed` tinyint(1) DEFAULT 0,
|
|
`sub_models` text DEFAULT NULL COMMENT '선택모델인 경우 모델 ID 목록 (JSON)',
|
|
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
|
`updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
PRIMARY KEY (`id`),
|
|
KEY `idx_tenant_id` (`tenant_id`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
CREATE TABLE IF NOT EXISTS `sales_tenant_scenarios` (
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
`tenant_id` int(11) NOT NULL,
|
|
`scenario_type` varchar(20) NOT NULL DEFAULT 'manager' COMMENT 'sales or manager',
|
|
`step_id` int(11) NOT NULL,
|
|
`checkpoint_index` int(11) NOT NULL,
|
|
`is_checked` tinyint(1) DEFAULT 0,
|
|
`updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
PRIMARY KEY (`id`),
|
|
UNIQUE KEY `idx_unique_step` (`tenant_id`, `scenario_type`, `step_id`, `checkpoint_index`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
CREATE TABLE IF NOT EXISTS `sales_tenant_consultations` (
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
`tenant_id` int(11) NOT NULL,
|
|
`manager_id` int(11) NOT NULL,
|
|
`scenario_type` varchar(20) NOT NULL DEFAULT 'manager' COMMENT 'sales or manager',
|
|
`step_id` int(11) DEFAULT NULL,
|
|
`log_text` text NOT NULL,
|
|
`audio_file_path` varchar(500) DEFAULT NULL,
|
|
`attachment_paths` text DEFAULT NULL,
|
|
`consultation_type` varchar(20) DEFAULT 'text' COMMENT 'text, audio, file',
|
|
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
|
PRIMARY KEY (`id`),
|
|
KEY `idx_tenant_id` (`tenant_id`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
");
|
|
|
|
// --- DB Migration (기존 테이블 업데이트) ---
|
|
try {
|
|
// 1. sales_tenant_scenarios 테이블에 scenario_type 컬럼 추가
|
|
$check = $pdo->query("SHOW COLUMNS FROM `sales_tenant_scenarios` LIKE 'scenario_type'")->fetch();
|
|
if (!$check) {
|
|
$pdo->exec("ALTER TABLE `sales_tenant_scenarios` ADD COLUMN `scenario_type` varchar(20) NOT NULL DEFAULT 'manager' AFTER `tenant_id` ");
|
|
}
|
|
|
|
// 2. sales_tenant_consultations 테이블에 scenario_type 컬럼 추가
|
|
$check2 = $pdo->query("SHOW COLUMNS FROM `sales_tenant_consultations` LIKE 'scenario_type'")->fetch();
|
|
if (!$check2) {
|
|
$pdo->exec("ALTER TABLE `sales_tenant_consultations` ADD COLUMN `scenario_type` varchar(20) NOT NULL DEFAULT 'manager' AFTER `manager_id` ");
|
|
}
|
|
|
|
// 3. sales_tenant_scenarios 테이블의 유니크 키 업데이트 (scenario_type 포함)
|
|
// 인덱스 구성을 확인하여 scenario_type이 포함되어 있지 않으면 재구성
|
|
$indices = $pdo->query("SHOW INDEX FROM `sales_tenant_scenarios` WHERE Key_name = 'idx_unique_step'")->fetchAll();
|
|
$hasScenarioTypeInIndex = false;
|
|
foreach ($indices as $index) {
|
|
if ($index['Column_name'] === 'scenario_type') {
|
|
$hasScenarioTypeInIndex = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!$hasScenarioTypeInIndex) {
|
|
try {
|
|
$pdo->exec("ALTER TABLE `sales_tenant_scenarios` DROP INDEX `idx_unique_step` ");
|
|
} catch (Exception $e) {}
|
|
$pdo->exec("ALTER TABLE `sales_tenant_scenarios` ADD UNIQUE KEY `idx_unique_step` (`tenant_id`, `scenario_type`, `step_id`, `checkpoint_index`) ");
|
|
}
|
|
// 4. sales_tenant_consultations 테이블에 오디오/첨부파일 컬럼 추가
|
|
$cols = $pdo->query("SHOW COLUMNS FROM `sales_tenant_consultations`")->fetchAll(PDO::FETCH_COLUMN);
|
|
if (!in_array('audio_file_path', $cols)) {
|
|
$pdo->exec("ALTER TABLE `sales_tenant_consultations` ADD COLUMN `audio_file_path` varchar(500) DEFAULT NULL AFTER `log_text` ");
|
|
}
|
|
if (!in_array('attachment_paths', $cols)) {
|
|
$pdo->exec("ALTER TABLE `sales_tenant_consultations` ADD COLUMN `attachment_paths` text DEFAULT NULL AFTER `audio_file_path` ");
|
|
}
|
|
if (!in_array('consultation_type', $cols)) {
|
|
$pdo->exec("ALTER TABLE `sales_tenant_consultations` ADD COLUMN `consultation_type` varchar(20) DEFAULT 'text' AFTER `attachment_paths` ");
|
|
}
|
|
// 5. sales_tenants 테이블에 sales_manager_id 컬럼 추가
|
|
$check5 = $pdo->query("SHOW COLUMNS FROM `sales_tenants` LIKE 'sales_manager_id'")->fetch();
|
|
if (!$check5) {
|
|
$pdo->exec("ALTER TABLE `sales_tenants` ADD COLUMN `sales_manager_id` int(11) DEFAULT NULL AFTER `manager_id` ");
|
|
}
|
|
|
|
// 6. sales_tenant_products 테이블 컬럼 확인 및 추가
|
|
$prodCols = $pdo->query("SHOW COLUMNS FROM `sales_tenant_products`")->fetchAll(PDO::FETCH_COLUMN);
|
|
if (!in_array('operator_confirmed', $prodCols)) {
|
|
$pdo->exec("ALTER TABLE `sales_tenant_products` ADD COLUMN `operator_confirmed` tinyint(1) DEFAULT 0 AFTER `contract_date` ");
|
|
}
|
|
if (!in_array('sub_models', $prodCols)) {
|
|
$pdo->exec("ALTER TABLE `sales_tenant_products` ADD COLUMN `sub_models` text DEFAULT NULL AFTER `operator_confirmed` ");
|
|
}
|
|
if (!in_array('commission_amount', $prodCols)) {
|
|
$pdo->exec("ALTER TABLE `sales_tenant_products` ADD COLUMN `commission_amount` decimal(15,2) DEFAULT 0.00 AFTER `commission_rate` ");
|
|
}
|
|
|
|
} catch (Exception $e) {
|
|
error_log("Migration error: " . $e->getMessage());
|
|
}
|
|
|
|
try {
|
|
switch ($method) {
|
|
case 'GET':
|
|
if ($action === 'list_tenants') {
|
|
// 운영자는 모든 테넌트, 영업관리/매니저는 본인 소속 테넌트만
|
|
if ($currentUser['role'] === 'operator') {
|
|
$stmt = $pdo->prepare("
|
|
SELECT t.*, m.name as register_name, m.role as register_role, m2.name as manager_name, m2.role as manager_role
|
|
FROM sales_tenants t
|
|
JOIN sales_member m ON t.manager_id = m.id
|
|
LEFT JOIN sales_member m2 ON t.sales_manager_id = m2.id
|
|
ORDER BY t.created_at DESC
|
|
");
|
|
$stmt->execute();
|
|
} else {
|
|
if ($currentUser['role'] === 'manager') {
|
|
// 매니저는 본인이 담당 매니저로 배정된 테넌트만 조회
|
|
$stmt = $pdo->prepare("
|
|
SELECT t.*, m.name as register_name, m.role as register_role, m2.name as manager_name, m2.role as manager_role
|
|
FROM sales_tenants t
|
|
JOIN sales_member m ON t.manager_id = m.id
|
|
LEFT JOIN sales_member m2 ON t.sales_manager_id = m2.id
|
|
WHERE t.sales_manager_id = ?
|
|
ORDER BY t.created_at DESC
|
|
");
|
|
$stmt->execute([$currentUser['id']]);
|
|
} else {
|
|
// 영업관리자는 본인이 영업했거나, 본인이 매니저로 배정된 테넌트 조회
|
|
$stmt = $pdo->prepare("
|
|
SELECT t.*, m.name as register_name, m.role as register_role, m2.name as manager_name, m2.role as manager_role
|
|
FROM sales_tenants t
|
|
JOIN sales_member m ON t.manager_id = m.id
|
|
LEFT JOIN sales_member m2 ON t.sales_manager_id = m2.id
|
|
WHERE t.manager_id = ? OR t.sales_manager_id = ?
|
|
ORDER BY t.created_at DESC
|
|
");
|
|
$stmt->execute([$currentUser['id'], $currentUser['id']]);
|
|
}
|
|
}
|
|
$tenants = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
echo json_encode(['success' => true, 'data' => $tenants]);
|
|
|
|
} elseif ($action === 'tenant_products') {
|
|
$tenant_id = $_GET['tenant_id'] ?? null;
|
|
if (!checkTenantPermission($pdo, $tenant_id, $currentUser)) throw new Exception("권한이 없습니다.");
|
|
|
|
$stmt = $pdo->prepare("SELECT * FROM sales_tenant_products WHERE tenant_id = ? ORDER BY created_at DESC");
|
|
$stmt->execute([$tenant_id]);
|
|
$products = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
echo json_encode(['success' => true, 'data' => $products]);
|
|
|
|
} elseif ($action === 'my_stats') {
|
|
// 현재 로그인한 사용자의 요약 통계
|
|
$sql = "
|
|
SELECT
|
|
COUNT(DISTINCT t.id) as tenant_count,
|
|
SUM(p.contract_amount) as total_revenue,
|
|
SUM(p.commission_amount) as total_commission,
|
|
SUM(CASE WHEN p.operator_confirmed = 1 THEN p.commission_amount ELSE 0 END) as confirmed_commission
|
|
FROM sales_tenants t
|
|
LEFT JOIN sales_tenant_products p ON t.id = p.tenant_id
|
|
";
|
|
|
|
if ($currentUser['role'] === 'manager') {
|
|
$sql .= " WHERE t.sales_manager_id = ?";
|
|
} else {
|
|
$sql .= " WHERE t.manager_id = ? OR t.sales_manager_id = ?";
|
|
}
|
|
|
|
$stmt = $pdo->prepare($sql);
|
|
if ($currentUser['role'] === 'manager') {
|
|
$stmt->execute([$currentUser['id']]);
|
|
} else {
|
|
$stmt->execute([$currentUser['id'], $currentUser['id']]);
|
|
}
|
|
$stats = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
echo json_encode(['success' => true, 'data' => $stats]);
|
|
} elseif ($action === 'get_scenario') {
|
|
$tenant_id = $_GET['tenant_id'] ?? null;
|
|
$scenario_type = $_GET['scenario_type'] ?? 'manager';
|
|
if (!checkTenantPermission($pdo, $tenant_id, $currentUser)) throw new Exception("권한이 없습니다.");
|
|
|
|
$stmt = $pdo->prepare("SELECT * FROM sales_tenant_scenarios WHERE tenant_id = ? AND scenario_type = ?");
|
|
$stmt->execute([$tenant_id, $scenario_type]);
|
|
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
echo json_encode(['success' => true, 'data' => $results]);
|
|
|
|
} elseif ($action === 'get_consultations') {
|
|
$tenant_id = $_GET['tenant_id'] ?? null;
|
|
$scenario_type = $_GET['scenario_type'] ?? 'manager';
|
|
$step_id = $_GET['step_id'] ?? null;
|
|
if (!checkTenantPermission($pdo, $tenant_id, $currentUser)) throw new Exception("권한이 없습니다.");
|
|
|
|
$sql = "SELECT * FROM sales_tenant_consultations WHERE tenant_id = ? AND scenario_type = ?";
|
|
$params = [$tenant_id, $scenario_type];
|
|
if ($step_id) {
|
|
$sql .= " AND step_id = ?";
|
|
$params[] = $step_id;
|
|
}
|
|
$sql .= " ORDER BY created_at DESC";
|
|
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute($params);
|
|
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
echo json_encode(['success' => true, 'data' => $results]);
|
|
} elseif ($action === 'list_managers') {
|
|
// 매니저로 매칭 가능한 사람 목록 (영업관리 또는 매니저 직급)
|
|
$stmt = $pdo->prepare("SELECT id, name, role, member_id, parent_id FROM sales_member WHERE role IN ('sales_admin', 'manager') AND is_active = 1 ORDER BY name ASC");
|
|
$stmt->execute();
|
|
$managers = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
echo json_encode(['success' => true, 'data' => $managers]);
|
|
}
|
|
break;
|
|
|
|
case 'POST':
|
|
// multipart/form-data인 경우 $_POST 사용, 아니면 JSON 입력 사용
|
|
if (empty($_POST)) {
|
|
$data = json_decode(file_get_contents('php://input'), true);
|
|
} else {
|
|
$data = $_POST;
|
|
}
|
|
|
|
if ($action === 'create_tenant') {
|
|
if ($currentUser['role'] === 'manager') {
|
|
throw new Exception("매니저는 테넌트를 등록할 권한이 없습니다.");
|
|
}
|
|
$tenant_name = $data['tenant_name'] ?? '';
|
|
$representative = $data['representative'] ?? '';
|
|
$business_no = $data['business_no'] ?? '';
|
|
$contact_phone = $data['contact_phone'] ?? '';
|
|
$email = $data['email'] ?? '';
|
|
$address = $data['address'] ?? '';
|
|
$sales_manager_id = $data['sales_manager_id'] ?? $currentUser['id']; // 지정 안하면 본인
|
|
|
|
if (!$tenant_name) throw new Exception("업체명은 필수입니다.");
|
|
|
|
$stmt = $pdo->prepare("INSERT INTO sales_tenants (manager_id, sales_manager_id, tenant_name, representative, business_no, contact_phone, email, address) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
|
|
$stmt->execute([$currentUser['id'], $sales_manager_id, $tenant_name, $representative, $business_no, $contact_phone, $email, $address]);
|
|
|
|
echo json_encode(['success' => true, 'id' => $pdo->lastInsertId(), 'message' => '테넌트가 등록되었습니다.']);
|
|
|
|
} elseif ($action === 'add_product') {
|
|
$tenant_id = $data['tenant_id'] ?? null;
|
|
if (!checkTenantPermission($pdo, $tenant_id, $currentUser)) throw new Exception("권한이 없습니다.");
|
|
|
|
$product_name = $data['product_name'] ?? '';
|
|
$contract_amount = $data['contract_amount'] ?? 0;
|
|
$commission_rate = $data['commission_rate'] ?? 0;
|
|
$contract_date = $data['contract_date'] ?? date('Y-m-d');
|
|
$sub_models = isset($data['sub_models']) ? json_encode($data['sub_models']) : null;
|
|
|
|
if (!$tenant_id || !$product_name) throw new Exception("필수 정보가 누락되었습니다.");
|
|
|
|
$commission_amount = ($contract_amount * $commission_rate) / 100;
|
|
|
|
$stmt = $pdo->prepare("INSERT INTO sales_tenant_products (tenant_id, product_name, contract_amount, commission_rate, commission_amount, contract_date, sub_models) VALUES (?, ?, ?, ?, ?, ?, ?)");
|
|
$stmt->execute([$tenant_id, $product_name, $contract_amount, $commission_rate, $commission_amount, $contract_date, $sub_models]);
|
|
|
|
echo json_encode(['success' => true, 'message' => '상품 계약 정보가 등록되었습니다.']);
|
|
|
|
} elseif ($action === 'confirm_product') {
|
|
if ($currentUser['role'] !== 'operator') throw new Exception("권한이 없습니다.");
|
|
|
|
$product_id = $data['id'] ?? null;
|
|
$confirmed = $data['confirmed'] ? 1 : 0;
|
|
|
|
if (!$product_id) throw new Exception("ID가 누락되었습니다.");
|
|
|
|
$stmt = $pdo->prepare("UPDATE sales_tenant_products SET operator_confirmed = ? WHERE id = ?");
|
|
$stmt->execute([$confirmed, $product_id]);
|
|
|
|
echo json_encode(['success' => true, 'message' => $confirmed ? '승인되었습니다.' : '승인이 취소되었습니다.']);
|
|
} elseif ($action === 'update_checklist') {
|
|
$tenant_id = isset($data['tenant_id']) ? intval($data['tenant_id']) : null;
|
|
$step_id = isset($data['step_id']) ? intval($data['step_id']) : null;
|
|
$checkpoint_index = isset($data['checkpoint_index']) ? intval($data['checkpoint_index']) : null;
|
|
$is_checked = (isset($data['is_checked']) && ($data['is_checked'] === true || $data['is_checked'] == 1)) ? 1 : 0;
|
|
$scenario_type = $data['scenario_type'] ?? 'manager';
|
|
|
|
if ($tenant_id === null || $step_id === null || $checkpoint_index === null) {
|
|
throw new Exception("필수 파라미터가 누락되었습니다. (T: $tenant_id, S: $step_id, C: $checkpoint_index)");
|
|
}
|
|
|
|
if (!checkTenantPermission($pdo, $tenant_id, $currentUser)) throw new Exception("권한이 없습니다.");
|
|
|
|
$stmt = $pdo->prepare("
|
|
INSERT INTO sales_tenant_scenarios (tenant_id, scenario_type, step_id, checkpoint_index, is_checked)
|
|
VALUES (?, ?, ?, ?, ?)
|
|
ON DUPLICATE KEY UPDATE is_checked = VALUES(is_checked)
|
|
");
|
|
$stmt->execute([$tenant_id, $scenario_type, $step_id, $checkpoint_index, $is_checked]);
|
|
|
|
echo json_encode(['success' => true]);
|
|
|
|
} elseif ($action === 'save_consultation') {
|
|
$tenant_id = $data['tenant_id'] ?? null;
|
|
if (!checkTenantPermission($pdo, $tenant_id, $currentUser)) throw new Exception("권한이 없습니다.");
|
|
|
|
$scenario_type = $data['scenario_type'] ?? 'manager';
|
|
$step_id = $data['step_id'] ?? null;
|
|
$log_text = $data['log_text'] ?? '';
|
|
$consultation_type = $data['consultation_type'] ?? 'text';
|
|
$audio_file_path = null;
|
|
|
|
if (!$tenant_id || !$step_id) throw new Exception("필수 정보가 누락되었습니다.");
|
|
|
|
// 오디오 파일 업로드 처리
|
|
if ($consultation_type === 'audio' && isset($_FILES['audio_file'])) {
|
|
$upload_dir = __DIR__ . "/../uploads/consultations/" . $tenant_id . "/";
|
|
if (!file_exists($upload_dir)) mkdir($upload_dir, 0777, true);
|
|
|
|
$file_ext = pathinfo($_FILES['audio_file']['name'], PATHINFO_EXTENSION) ?: 'webm';
|
|
$file_name = "audio_" . date('Ymd_His') . "_" . uniqid() . "." . $file_ext;
|
|
$audio_file_path = "uploads/consultations/" . $tenant_id . "/" . $file_name;
|
|
|
|
if (!move_uploaded_file($_FILES['audio_file']['tmp_name'], __DIR__ . "/../" . $audio_file_path)) {
|
|
throw new Exception("오디오 파일 저장 실패");
|
|
}
|
|
}
|
|
|
|
$stmt = $pdo->prepare("INSERT INTO sales_tenant_consultations (tenant_id, manager_id, scenario_type, step_id, log_text, audio_file_path, consultation_type) VALUES (?, ?, ?, ?, ?, ?, ?)");
|
|
$stmt->execute([$tenant_id, $currentUser['id'], $scenario_type, $step_id, $log_text, $audio_file_path, $consultation_type]);
|
|
|
|
echo json_encode(['success' => true, 'message' => '기록이 저장되었습니다.']);
|
|
} elseif ($action === 'upload_chunk') {
|
|
$upload_id = $data['uploadId'] ?? '';
|
|
$chunk_index = intval($data['chunkIndex'] ?? 0);
|
|
$total_chunks = intval($data['totalChunks'] ?? 1);
|
|
$filename = $data['fileName'] ?? 'uploaded_file';
|
|
$tenant_id = $data['tenant_id'] ?? null;
|
|
$scenario_type = $data['scenario_type'] ?? 'manager';
|
|
$step_id = $data['step_id'] ?? null;
|
|
|
|
if (!$upload_id || !isset($_FILES['file'])) throw new Exception("청크 데이터가 유효하지 않습니다.");
|
|
|
|
$chunk_dir = __DIR__ . "/../uploads/chunks/" . $upload_id;
|
|
if (!file_exists($chunk_dir)) mkdir($chunk_dir, 0777, true);
|
|
|
|
$chunk_file = $chunk_dir . "/" . $chunk_index;
|
|
if (!move_uploaded_file($_FILES['file']['tmp_name'], $chunk_file)) {
|
|
throw new Exception("청크 저장 실패");
|
|
}
|
|
|
|
// 모든 청크가 도착했는지 확인
|
|
$received_chunks = count(glob($chunk_dir . "/*"));
|
|
if ($received_chunks === $total_chunks) {
|
|
$upload_dir = __DIR__ . "/../uploads/attachments/" . $tenant_id . "/";
|
|
if (!file_exists($upload_dir)) mkdir($upload_dir, 0777, true);
|
|
|
|
$file_ext = pathinfo($filename, PATHINFO_EXTENSION);
|
|
$file_name_only = pathinfo($filename, PATHINFO_FILENAME);
|
|
$new_filename = date('Ymd_His') . "_" . uniqid() . "_" . $filename;
|
|
$final_path = $upload_dir . $new_filename;
|
|
|
|
$out = fopen($final_path, "wb");
|
|
for ($i = 0; $i < $total_chunks; $i++) {
|
|
$chunk_path = $chunk_dir . "/" . $i;
|
|
if (!file_exists($chunk_path)) throw new Exception("청크 누락: " . $i);
|
|
$in = fopen($chunk_path, "rb");
|
|
while ($buff = fread($in, 4096)) {
|
|
fwrite($out, $buff);
|
|
}
|
|
fclose($in);
|
|
unlink($chunk_path);
|
|
}
|
|
fclose($out);
|
|
rmdir($chunk_dir);
|
|
|
|
$save_path = "uploads/attachments/" . $tenant_id . "/" . $new_filename;
|
|
$saved_paths = [[
|
|
'name' => $filename,
|
|
'path' => $save_path,
|
|
'size' => filesize($final_path)
|
|
]];
|
|
|
|
$stmt = $pdo->prepare("INSERT INTO sales_tenant_consultations (tenant_id, manager_id, scenario_type, step_id, log_text, attachment_paths, consultation_type) VALUES (?, ?, ?, ?, ?, ?, ?)");
|
|
$stmt->execute([$tenant_id, $currentUser['id'], $scenario_type, $step_id, '첨부파일 업로드 (대용량)', json_encode($saved_paths, JSON_UNESCAPED_UNICODE), 'file']);
|
|
|
|
echo json_encode(['success' => true, 'completed' => true, 'message' => '업로드 완료']);
|
|
} else {
|
|
echo json_encode(['success' => true, 'completed' => false, 'chunk' => $chunk_index]);
|
|
}
|
|
} elseif ($action === 'upload_attachments') {
|
|
$tenant_id = $data['tenant_id'] ?? null;
|
|
if (!checkTenantPermission($pdo, $tenant_id, $currentUser)) throw new Exception("권한이 없습니다.");
|
|
|
|
$scenario_type = $data['scenario_type'] ?? 'manager';
|
|
$step_id = $data['step_id'] ?? null;
|
|
|
|
if (!$tenant_id || !$step_id || !isset($_FILES['files'])) throw new Exception("필수 정보가 누락되었습니다.");
|
|
|
|
$upload_dir = __DIR__ . "/../uploads/attachments/" . $tenant_id . "/";
|
|
if (!file_exists($upload_dir)) mkdir($upload_dir, 0777, true);
|
|
|
|
$saved_paths = [];
|
|
$files = $_FILES['files'];
|
|
$count = is_array($files['name']) ? count($files['name']) : 1;
|
|
|
|
for ($i = 0; $i < $count; $i++) {
|
|
$tmp_name = is_array($files['tmp_name']) ? $files['tmp_name'][$i] : $files['tmp_name'];
|
|
$name = is_array($files['name']) ? $files['name'][$i] : $files['name'];
|
|
|
|
if (is_uploaded_file($tmp_name)) {
|
|
$file_name = date('Ymd_His') . "_" . uniqid() . "_" . $name;
|
|
$save_path = "uploads/attachments/" . $tenant_id . "/" . $file_name;
|
|
if (move_uploaded_file($tmp_name, __DIR__ . "/../" . $save_path)) {
|
|
$saved_paths[] = [
|
|
'name' => $name,
|
|
'path' => $save_path,
|
|
'size' => is_array($files['size']) ? $files['size'][$i] : $files['size']
|
|
];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (empty($saved_paths)) throw new Exception("저장된 파일이 없습니다.");
|
|
|
|
$stmt = $pdo->prepare("INSERT INTO sales_tenant_consultations (tenant_id, manager_id, scenario_type, step_id, log_text, attachment_paths, consultation_type) VALUES (?, ?, ?, ?, ?, ?, ?)");
|
|
$stmt->execute([$tenant_id, $currentUser['id'], $scenario_type, $step_id, '첨부파일 업로드', json_encode($saved_paths, JSON_UNESCAPED_UNICODE), 'file']);
|
|
|
|
echo json_encode(['success' => true, 'message' => '파일이 업로드되었습니다.']);
|
|
} elseif ($action === 'delete_consultation') {
|
|
$id = $data['id'] ?? null;
|
|
if (!$id) throw new Exception("ID가 누락되었습니다.");
|
|
|
|
// 권한 확인을 위해 정보 조회
|
|
$stmt = $pdo->prepare("SELECT tenant_id, audio_file_path, attachment_paths FROM sales_tenant_consultations WHERE id = ?");
|
|
$stmt->execute([$id]);
|
|
$c = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$c) throw new Exception("해당 기록을 찾을 수 없습니다.");
|
|
if (!checkTenantPermission($pdo, $c['tenant_id'], $currentUser)) throw new Exception("권한이 없습니다.");
|
|
|
|
// 파일 삭제 처리
|
|
if ($c['audio_file_path'] && file_exists(__DIR__ . "/../" . $c['audio_file_path'])) {
|
|
@unlink(__DIR__ . "/../" . $c['audio_file_path']);
|
|
}
|
|
if ($c['attachment_paths']) {
|
|
$paths = json_decode($c['attachment_paths'], true);
|
|
if (is_array($paths)) {
|
|
foreach ($paths as $p) {
|
|
if (isset($p['path']) && file_exists(__DIR__ . "/../" . $p['path'])) {
|
|
@unlink(__DIR__ . "/../" . $p['path']);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$stmt = $pdo->prepare("DELETE FROM sales_tenant_consultations WHERE id = ?");
|
|
$stmt->execute([$id]);
|
|
echo json_encode(['success' => true, 'message' => '성공적으로 삭제되었습니다.']);
|
|
} elseif ($action === 'delete_product') {
|
|
$product_id = $data['id'] ?? null;
|
|
if (!$product_id) throw new Exception("ID가 누락되었습니다.");
|
|
|
|
// 정보 및 권한 조회
|
|
$stmt = $pdo->prepare("SELECT tenant_id, operator_confirmed FROM sales_tenant_products WHERE id = ?");
|
|
$stmt->execute([$product_id]);
|
|
$p = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$p) throw new Exception("해당 정보를 찾을 수 없습니다.");
|
|
if (!checkTenantPermission($pdo, $p['tenant_id'], $currentUser)) throw new Exception("권한이 없습니다.");
|
|
if ($p['operator_confirmed'] == 1) throw new Exception("이미 승인된 계약은 삭제할 수 없습니다.");
|
|
|
|
$stmt = $pdo->prepare("DELETE FROM sales_tenant_products WHERE id = ?");
|
|
$stmt->execute([$product_id]);
|
|
|
|
echo json_encode(['success' => true, 'message' => '성공적으로 삭제되었습니다.']);
|
|
} elseif ($action === 'update_tenant_manager') {
|
|
$tenant_id = isset($data['tenant_id']) ? intval($data['tenant_id']) : null;
|
|
$sales_manager_id = isset($data['sales_manager_id']) ? $data['sales_manager_id'] : null;
|
|
|
|
if (!$tenant_id) throw new Exception("테넌트 ID가 누락되었습니다.");
|
|
|
|
// 권한 확인: 배지 지정은 운영자 또는 해당 테넌트를 등록한 영업관리자만 가능
|
|
$stmt = $pdo->prepare("SELECT manager_id FROM sales_tenants WHERE id = ?");
|
|
$stmt->execute([$tenant_id]);
|
|
$t = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$t) throw new Exception("테넌트를 찾을 수 없습니다.");
|
|
if ($currentUser['role'] !== 'operator' && $t['manager_id'] != $currentUser['id']) {
|
|
throw new Exception("배정 권한이 없습니다.");
|
|
}
|
|
|
|
// manager_id가 0이거나 empty면 null로 처리 (지정 취소)
|
|
$manager_val = (!empty($sales_manager_id)) ? intval($sales_manager_id) : null;
|
|
|
|
$stmt = $pdo->prepare("UPDATE sales_tenants SET sales_manager_id = ? WHERE id = ?");
|
|
$stmt->execute([$manager_val, $tenant_id]);
|
|
|
|
echo json_encode(['success' => true, 'message' => $manager_val ? '담당 매니저가 지정되었습니다.' : '담당 매니저 지정이 취소되었습니다.']);
|
|
|
|
} elseif ($action === 'update_product') {
|
|
$product_id = $data['id'] ?? null;
|
|
if (!$product_id) throw new Exception("ID가 누락되었습니다.");
|
|
|
|
// 정보 및 권한 조회
|
|
$stmt = $pdo->prepare("SELECT tenant_id, operator_confirmed FROM sales_tenant_products WHERE id = ?");
|
|
$stmt->execute([$product_id]);
|
|
$p = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$p) throw new Exception("해당 정보를 찾을 수 없습니다.");
|
|
if (!checkTenantPermission($pdo, $p['tenant_id'], $currentUser)) throw new Exception("권한이 없습니다.");
|
|
if ($p['operator_confirmed'] == 1) throw new Exception("이미 승인된 계약은 수정할 수 없습니다.");
|
|
|
|
$product_name = $data['product_name'] ?? '';
|
|
$contract_amount = $data['contract_amount'] ?? 0;
|
|
$commission_rate = $data['commission_rate'] ?? 0;
|
|
$contract_date = $data['contract_date'] ?? date('Y-m-d');
|
|
$sub_models = isset($data['sub_models']) ? json_encode($data['sub_models']) : null;
|
|
|
|
$commission_amount = ($contract_amount * $commission_rate) / 100;
|
|
|
|
$stmt = $pdo->prepare("UPDATE sales_tenant_products SET product_name = ?, contract_amount = ?, commission_rate = ?, commission_amount = ?, contract_date = ?, sub_models = ? WHERE id = ?");
|
|
$stmt->execute([$product_name, $contract_amount, $commission_rate, $commission_amount, $contract_date, $sub_models, $product_id]);
|
|
|
|
echo json_encode(['success' => true, 'message' => '계약 정보가 수정되었습니다.']);
|
|
|
|
} elseif ($action === 'update_tenant') {
|
|
$tenant_id = $data['id'] ?? null;
|
|
if (!checkTenantPermission($pdo, $tenant_id, $currentUser)) throw new Exception("권한이 없습니다.");
|
|
|
|
// 운영팀 등록 여부 확인
|
|
$stmtCheck = $pdo->prepare("SELECT m.role FROM sales_tenants t JOIN sales_member m ON t.manager_id = m.id WHERE t.id = ?");
|
|
$stmtCheck->execute([$tenant_id]);
|
|
$reg = $stmtCheck->fetch();
|
|
if ($reg && $reg['role'] === 'operator' && $currentUser['role'] !== 'operator') {
|
|
throw new Exception("운영팀에서 등록한 테넌트는 수정할 수 없습니다.");
|
|
}
|
|
|
|
$tenant_name = $data['tenant_name'] ?? '';
|
|
$representative = $data['representative'] ?? '';
|
|
$business_no = $data['business_no'] ?? '';
|
|
$contact_phone = $data['contact_phone'] ?? '';
|
|
$email = $data['email'] ?? '';
|
|
$address = $data['address'] ?? '';
|
|
$sales_manager_id = $data['sales_manager_id'] ?? null;
|
|
|
|
if (!$tenant_name) throw new Exception("업체명은 필수입니다.");
|
|
|
|
$stmt = $pdo->prepare("UPDATE sales_tenants SET tenant_name = ?, representative = ?, business_no = ?, contact_phone = ?, email = ?, address = ?, sales_manager_id = ? WHERE id = ?");
|
|
$stmt->execute([$tenant_name, $representative, $business_no, $contact_phone, $email, $address, $sales_manager_id, $tenant_id]);
|
|
|
|
echo json_encode(['success' => true, 'message' => '테넌트 정보가 수정되었습니다.']);
|
|
|
|
} elseif ($action === 'delete_tenant') {
|
|
$tenant_id = $data['id'] ?? null;
|
|
if (!checkTenantPermission($pdo, $tenant_id, $currentUser)) throw new Exception("권한이 없습니다.");
|
|
|
|
// 운영팀 등록 여부 확인
|
|
$stmtCheck = $pdo->prepare("SELECT m.role FROM sales_tenants t JOIN sales_member m ON t.manager_id = m.id WHERE t.id = ?");
|
|
$stmtCheck->execute([$tenant_id]);
|
|
$reg = $stmtCheck->fetch();
|
|
if ($reg && $reg['role'] === 'operator' && $currentUser['role'] !== 'operator') {
|
|
throw new Exception("운영팀에서 등록한 테넌트는 삭제할 수 없습니다.");
|
|
}
|
|
|
|
// 관련 데이터 삭제 (계약, 시나리오, 상담기록)
|
|
$pdo->prepare("DELETE FROM sales_tenant_products WHERE tenant_id = ?")->execute([$tenant_id]);
|
|
$pdo->prepare("DELETE FROM sales_tenant_scenarios WHERE tenant_id = ?")->execute([$tenant_id]);
|
|
$pdo->prepare("DELETE FROM sales_tenant_consultations WHERE tenant_id = ?")->execute([$tenant_id]);
|
|
$pdo->prepare("DELETE FROM sales_tenants WHERE id = ?")->execute([$tenant_id]);
|
|
|
|
echo json_encode(['success' => true, 'message' => '테넌트가 삭제되었습니다.']);
|
|
}
|
|
break;
|
|
}
|
|
} catch (Exception $e) {
|
|
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
|
}
|
|
?>
|