Files
sam-sales/salesmanagement/api/sales_tenants.php
2025-12-30 21:34:17 +09:00

509 lines
28 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` ");
}
} 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, 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, 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, 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_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'] ?? '';
$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' => '계약 정보가 수정되었습니다.']);
}
break;
}
} catch (Exception $e) {
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
}
?>