2025-12-23 09:00:57 +09:00
< ? 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 ();
2025-12-30 21:34:17 +09:00
/**
* 테넌트에 대한 접근 권한 확인
*/
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' ];
}
2026-01-06 14:06:32 +09:00
// 영업파트너는 본인이 등록했거나, 본인이 담당 매니저인 경우 가능
2025-12-30 21:34:17 +09:00
return ( $tenant [ 'manager_id' ] == $currentUser [ 'id' ] || $tenant [ 'sales_manager_id' ] == $currentUser [ 'id' ]);
}
2025-12-24 09:46:07 +09:00
// 테이블 자동 생성 (없을 경우)
$pdo -> exec ( "
CREATE TABLE IF NOT EXISTS `sales_tenants` (
`id` int ( 11 ) NOT NULL AUTO_INCREMENT ,
2026-01-06 14:06:32 +09:00
`manager_id` int ( 11 ) NOT NULL COMMENT '영업한 영업파트너 ID' ,
`sales_manager_id` int ( 11 ) DEFAULT NULL COMMENT '매칭된 매니저 ID (영업파트너 본인 또는 별도 매니저)' ,
2025-12-24 09:46:07 +09:00
`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` " );
}
2026-01-04 19:19:49 +09:00
// 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` " );
}
2026-01-05 04:25:12 +09:00
if ( ! in_array ( 'join_approved' , $prodCols )) {
$pdo -> exec ( " ALTER TABLE `sales_tenant_products` ADD COLUMN `join_approved` tinyint(1) DEFAULT 0 AFTER `operator_confirmed` " );
if ( in_array ( 'operator_confirmed' , $prodCols )) {
$pdo -> exec ( " UPDATE `sales_tenant_products` SET `join_approved` = `operator_confirmed` " );
}
}
if ( ! in_array ( 'payment_approved' , $prodCols )) {
$pdo -> exec ( " ALTER TABLE `sales_tenant_products` ADD COLUMN `payment_approved` tinyint(1) DEFAULT 0 AFTER `join_approved` " );
}
if ( ! in_array ( 'payout_rate' , $prodCols )) {
$pdo -> exec ( " ALTER TABLE `sales_tenant_products` ADD COLUMN `payout_rate` float DEFAULT 0 AFTER `payment_approved` " );
}
if ( ! in_array ( 'payout_amount' , $prodCols )) {
$pdo -> exec ( " ALTER TABLE `sales_tenant_products` ADD COLUMN `payout_amount` decimal(15,2) DEFAULT 0.00 AFTER `payout_rate` " );
}
2026-01-04 19:19:49 +09:00
if ( ! in_array ( 'sub_models' , $prodCols )) {
2026-01-05 04:25:12 +09:00
$pdo -> exec ( " ALTER TABLE `sales_tenant_products` ADD COLUMN `sub_models` text DEFAULT NULL AFTER `payout_amount` " );
2026-01-04 19:19:49 +09:00
}
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` " );
}
2025-12-24 09:46:07 +09:00
} catch ( Exception $e ) {
error_log ( " Migration error: " . $e -> getMessage ());
}
2025-12-23 09:00:57 +09:00
try {
switch ( $method ) {
case 'GET' :
if ( $action === 'list_tenants' ) {
2026-01-06 14:06:32 +09:00
// 운영자는 모든 테넌트, 영업파트너/매니저는 본인 소속 테넌트만
2025-12-23 09:00:57 +09:00
if ( $currentUser [ 'role' ] === 'operator' ) {
2025-12-24 09:46:07 +09:00
$stmt = $pdo -> prepare ( "
2026-01-04 17:52:14 +09:00
SELECT t .* , m . name as register_name , m . role as register_role , m2 . name as manager_name , m2 . role as manager_role
2025-12-24 09:46:07 +09:00
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
" );
2025-12-23 09:00:57 +09:00
$stmt -> execute ();
} else {
2025-12-30 21:34:17 +09:00
if ( $currentUser [ 'role' ] === 'manager' ) {
// 매니저는 본인이 담당 매니저로 배정된 테넌트만 조회
$stmt = $pdo -> prepare ( "
2026-01-04 17:52:14 +09:00
SELECT t .* , m . name as register_name , m . role as register_role , m2 . name as manager_name , m2 . role as manager_role
2025-12-30 21:34:17 +09:00
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 {
2026-01-06 14:06:32 +09:00
// 영업파트너는 본인이 영업했거나, 본인이 매니저로 배정된 테넌트 조회
2025-12-30 21:34:17 +09:00
$stmt = $pdo -> prepare ( "
2026-01-04 17:52:14 +09:00
SELECT t .* , m . name as register_name , m . role as register_role , m2 . name as manager_name , m2 . role as manager_role
2025-12-30 21:34:17 +09:00
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' ]]);
}
2025-12-23 09:00:57 +09:00
}
$tenants = $stmt -> fetchAll ( PDO :: FETCH_ASSOC );
echo json_encode ([ 'success' => true , 'data' => $tenants ]);
} elseif ( $action === 'tenant_products' ) {
$tenant_id = $_GET [ 'tenant_id' ] ? ? null ;
2025-12-30 21:34:17 +09:00
if ( ! checkTenantPermission ( $pdo , $tenant_id , $currentUser )) throw new Exception ( " 권한이 없습니다. " );
2025-12-23 09:00:57 +09:00
$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' ) {
// 현재 로그인한 사용자의 요약 통계
2025-12-30 21:34:17 +09:00
$sql = "
2025-12-23 09:00:57 +09:00
SELECT
COUNT ( DISTINCT t . id ) as tenant_count ,
SUM ( p . contract_amount ) as total_revenue ,
SUM ( p . commission_amount ) as total_commission ,
2026-01-05 04:25:12 +09:00
SUM ( CASE WHEN p . payment_approved = 1 THEN p . commission_amount ELSE 0 END ) as confirmed_commission
2025-12-23 09:00:57 +09:00
FROM sales_tenants t
LEFT JOIN sales_tenant_products p ON t . id = p . tenant_id
2025-12-30 21:34:17 +09:00
" ;
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' ]]);
}
2025-12-23 09:00:57 +09:00
$stats = $stmt -> fetch ( PDO :: FETCH_ASSOC );
echo json_encode ([ 'success' => true , 'data' => $stats ]);
2025-12-24 09:46:07 +09:00
} elseif ( $action === 'get_scenario' ) {
$tenant_id = $_GET [ 'tenant_id' ] ? ? null ;
$scenario_type = $_GET [ 'scenario_type' ] ? ? 'manager' ;
2025-12-30 21:34:17 +09:00
if ( ! checkTenantPermission ( $pdo , $tenant_id , $currentUser )) throw new Exception ( " 권한이 없습니다. " );
2025-12-24 09:46:07 +09:00
$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 ;
2025-12-30 21:34:17 +09:00
if ( ! checkTenantPermission ( $pdo , $tenant_id , $currentUser )) throw new Exception ( " 권한이 없습니다. " );
2025-12-24 09:46:07 +09:00
$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' ) {
// 매니저로 매칭 가능한 사람 목록 (영업관리 또는 매니저 직급)
2025-12-30 21:34:17 +09:00
$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 " );
2025-12-24 09:46:07 +09:00
$stmt -> execute ();
$managers = $stmt -> fetchAll ( PDO :: FETCH_ASSOC );
echo json_encode ([ 'success' => true , 'data' => $managers ]);
2025-12-23 09:00:57 +09:00
}
break ;
case 'POST' :
2025-12-24 09:46:07 +09:00
// multipart/form-data인 경우 $_POST 사용, 아니면 JSON 입력 사용
if ( empty ( $_POST )) {
$data = json_decode ( file_get_contents ( 'php://input' ), true );
} else {
$data = $_POST ;
}
2025-12-23 09:00:57 +09:00
if ( $action === 'create_tenant' ) {
2025-12-30 21:34:17 +09:00
if ( $currentUser [ 'role' ] === 'manager' ) {
throw new Exception ( " 매니저는 테넌트를 등록할 권한이 없습니다. " );
}
2025-12-23 09:00:57 +09:00
$tenant_name = $data [ 'tenant_name' ] ? ? '' ;
$representative = $data [ 'representative' ] ? ? '' ;
$business_no = $data [ 'business_no' ] ? ? '' ;
$contact_phone = $data [ 'contact_phone' ] ? ? '' ;
$email = $data [ 'email' ] ? ? '' ;
$address = $data [ 'address' ] ? ? '' ;
2025-12-24 09:46:07 +09:00
$sales_manager_id = $data [ 'sales_manager_id' ] ? ? $currentUser [ 'id' ]; // 지정 안하면 본인
2025-12-23 09:00:57 +09:00
if ( ! $tenant_name ) throw new Exception ( " 업체명은 필수입니다. " );
2025-12-24 09:46:07 +09:00
$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 ]);
2025-12-23 09:00:57 +09:00
echo json_encode ([ 'success' => true , 'id' => $pdo -> lastInsertId (), 'message' => '테넌트가 등록되었습니다.' ]);
} elseif ( $action === 'add_product' ) {
$tenant_id = $data [ 'tenant_id' ] ? ? null ;
2025-12-30 21:34:17 +09:00
if ( ! checkTenantPermission ( $pdo , $tenant_id , $currentUser )) throw new Exception ( " 권한이 없습니다. " );
2025-12-23 09:00:57 +09:00
$product_name = $data [ 'product_name' ] ? ? '' ;
$contract_amount = $data [ 'contract_amount' ] ? ? 0 ;
2026-01-05 06:02:14 +09:00
$subscription_fee = $data [ 'subscription_fee' ] ? ? 0 ;
2025-12-23 09:00:57 +09:00
$contract_date = $data [ 'contract_date' ] ? ? date ( 'Y-m-d' );
2025-12-24 09:46:07 +09:00
$sub_models = isset ( $data [ 'sub_models' ]) ? json_encode ( $data [ 'sub_models' ]) : null ;
2025-12-23 09:00:57 +09:00
if ( ! $tenant_id || ! $product_name ) throw new Exception ( " 필수 정보가 누락되었습니다. " );
2026-01-05 06:02:14 +09:00
$commission_amount = $contract_amount * 0.20 ; // 가입비의 20% 수당
2025-12-24 09:46:07 +09:00
2026-01-05 06:02:14 +09:00
$stmt = $pdo -> prepare ( " INSERT INTO sales_tenant_products (tenant_id, product_name, contract_amount, subscription_fee, commission_rate, commission_amount, contract_date, sub_models) VALUES (?, ?, ?, ?, ?, ?, ?, ?) " );
$stmt -> execute ([ $tenant_id , $product_name , $contract_amount , $subscription_fee , 20 , $commission_amount , $contract_date , $sub_models ]);
2025-12-23 09:00:57 +09:00
echo json_encode ([ 'success' => true , 'message' => '상품 계약 정보가 등록되었습니다.' ]);
} elseif ( $action === 'confirm_product' ) {
if ( $currentUser [ 'role' ] !== 'operator' ) throw new Exception ( " 권한이 없습니다. " );
$product_id = $data [ 'id' ] ? ? null ;
2026-01-05 04:25:12 +09:00
$field = $data [ 'field' ] ? ? 'operator_confirmed' ; // 'join_approved' or 'payment_approved'
$value = $data [ 'value' ] ? 1 : 0 ;
2025-12-23 09:00:57 +09:00
if ( ! $product_id ) throw new Exception ( " ID가 누락되었습니다. " );
2026-01-05 04:25:12 +09:00
if ( ! in_array ( $field , [ 'operator_confirmed' , 'join_approved' , 'payment_approved' ])) {
throw new Exception ( " 유효하지 않은 필드입니다. " );
}
// 지급 승인(payment_approved) 시 수수료 계산 로직 적용
if ( $field === 'payment_approved' && $value === 1 ) {
$stmt = $pdo -> prepare ( "
SELECT p . contract_amount , t . manager_id
FROM sales_tenant_products p
JOIN sales_tenants t ON p . tenant_id = t . id
WHERE p . id = ?
" );
$stmt -> execute ([ $product_id ]);
$row = $stmt -> fetch ( PDO :: FETCH_ASSOC );
if ( $row ) {
$manager_id = $row [ 'manager_id' ];
$amount = $row [ 'contract_amount' ];
2026-01-06 14:06:32 +09:00
// 영업파트너 계층 확인
2026-01-05 04:25:12 +09:00
// 1. 등록자 본인이 sales_admin인지 확인
// 2. 상위(parent)가 sales_admin인지 확인
$sales_admin_count = 0 ;
$curr_id = $manager_id ;
$visited = [];
while ( $curr_id && ! in_array ( $curr_id , $visited )) {
$visited [] = $curr_id ;
$stmtM = $pdo -> prepare ( " SELECT role, parent_id FROM sales_member WHERE id = ? " );
$stmtM -> execute ([ $curr_id ]);
$m = $stmtM -> fetch ( PDO :: FETCH_ASSOC );
if ( ! $m ) break ;
if ( $m [ 'role' ] === 'sales_admin' ) {
$sales_admin_count ++ ;
}
$curr_id = $m [ 'parent_id' ];
if ( ! $curr_id ) break ;
}
$payout_rate = ( $sales_admin_count >= 2 ) ? 25 : 20 ;
$payout_amount = $amount * ( $payout_rate / 100 );
$stmtU = $pdo -> prepare ( " UPDATE sales_tenant_products SET payout_rate = ?, payout_amount = ? WHERE id = ? " );
$stmtU -> execute ([ $payout_rate , $payout_amount , $product_id ]);
}
}
2025-12-23 09:00:57 +09:00
2026-01-05 04:25:12 +09:00
$stmt = $pdo -> prepare ( " UPDATE sales_tenant_products SET $field = ? WHERE id = ? " );
$stmt -> execute ([ $value , $product_id ]);
2025-12-23 09:00:57 +09:00
2026-01-05 04:25:12 +09:00
echo json_encode ([ 'success' => true , 'message' => '처리가 완료되었습니다.' ]);
2025-12-24 09:46:07 +09:00
} elseif ( $action === 'update_checklist' ) {
2025-12-30 21:34:17 +09:00
$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 ;
2025-12-24 09:46:07 +09:00
$scenario_type = $data [ 'scenario_type' ] ? ? 'manager' ;
2025-12-30 21:34:17 +09:00
if ( $tenant_id === null || $step_id === null || $checkpoint_index === null ) {
throw new Exception ( " 필수 파라미터가 누락되었습니다. (T: $tenant_id , S: $step_id , C: $checkpoint_index ) " );
}
2025-12-24 09:46:07 +09:00
2025-12-30 21:34:17 +09:00
if ( ! checkTenantPermission ( $pdo , $tenant_id , $currentUser )) throw new Exception ( " 권한이 없습니다. " );
2025-12-24 09:46:07 +09:00
$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 ;
2025-12-30 21:34:17 +09:00
if ( ! checkTenantPermission ( $pdo , $tenant_id , $currentUser )) throw new Exception ( " 권한이 없습니다. " );
2025-12-24 09:46:07 +09:00
$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' => '기록이 저장되었습니다.' ]);
2026-01-04 19:56:29 +09:00
} 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 ]);
}
2025-12-24 09:46:07 +09:00
} elseif ( $action === 'upload_attachments' ) {
$tenant_id = $data [ 'tenant_id' ] ? ? null ;
2025-12-30 21:34:17 +09:00
if ( ! checkTenantPermission ( $pdo , $tenant_id , $currentUser )) throw new Exception ( " 권한이 없습니다. " );
2025-12-24 09:46:07 +09:00
$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가 누락되었습니다. " );
2025-12-30 21:34:17 +09:00
// 권한 확인을 위해 정보 조회
$stmt = $pdo -> prepare ( " SELECT tenant_id, audio_file_path, attachment_paths FROM sales_tenant_consultations WHERE id = ? " );
2025-12-24 09:46:07 +09:00
$stmt -> execute ([ $id ]);
$c = $stmt -> fetch ( PDO :: FETCH_ASSOC );
2025-12-30 21:34:17 +09:00
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' ]);
2025-12-24 09:46:07 +09:00
}
}
}
}
$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가 누락되었습니다. " );
2025-12-30 21:34:17 +09:00
// 정보 및 권한 조회
2026-01-05 04:25:12 +09:00
$stmt = $pdo -> prepare ( " SELECT tenant_id, join_approved FROM sales_tenant_products WHERE id = ? " );
2025-12-24 09:46:07 +09:00
$stmt -> execute ([ $product_id ]);
$p = $stmt -> fetch ( PDO :: FETCH_ASSOC );
if ( ! $p ) throw new Exception ( " 해당 정보를 찾을 수 없습니다. " );
2025-12-30 21:34:17 +09:00
if ( ! checkTenantPermission ( $pdo , $p [ 'tenant_id' ], $currentUser )) throw new Exception ( " 권한이 없습니다. " );
2026-01-05 04:25:12 +09:00
if ( $p [ 'join_approved' ] == 1 ) throw new Exception ( " 이미 가입 승인된 계약은 삭제할 수 없습니다. " );
2025-12-24 09:46:07 +09:00
$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가 누락되었습니다. " );
2026-01-06 14:06:32 +09:00
// 권한 확인: 배지 지정은 운영자 또는 해당 테넌트를 등록한 영업파트너만 가능
2025-12-30 21:34:17 +09:00
$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 ( " 배정 권한이 없습니다. " );
}
2025-12-24 09:46:07 +09:00
// 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 ? '담당 매니저가 지정되었습니다.' : '담당 매니저 지정이 취소되었습니다.' ]);
2026-01-04 17:39:59 +09:00
2025-12-24 09:46:07 +09:00
} elseif ( $action === 'update_product' ) {
$product_id = $data [ 'id' ] ? ? null ;
2025-12-30 21:34:17 +09:00
if ( ! $product_id ) throw new Exception ( " ID가 누락되었습니다. " );
2025-12-24 09:46:07 +09:00
2025-12-30 21:34:17 +09:00
// 정보 및 권한 조회
2026-01-05 04:25:12 +09:00
$stmt = $pdo -> prepare ( " SELECT tenant_id, join_approved FROM sales_tenant_products WHERE id = ? " );
2025-12-24 09:46:07 +09:00
$stmt -> execute ([ $product_id ]);
$p = $stmt -> fetch ( PDO :: FETCH_ASSOC );
if ( ! $p ) throw new Exception ( " 해당 정보를 찾을 수 없습니다. " );
2025-12-30 21:34:17 +09:00
if ( ! checkTenantPermission ( $pdo , $p [ 'tenant_id' ], $currentUser )) throw new Exception ( " 권한이 없습니다. " );
2026-01-05 04:25:12 +09:00
if ( $p [ 'join_approved' ] == 1 ) throw new Exception ( " 이미 가입 승인된 계약은 수정할 수 없습니다. " );
2025-12-24 09:46:07 +09:00
2025-12-30 21:34:17 +09:00
$product_name = $data [ 'product_name' ] ? ? '' ;
2026-01-04 17:39:59 +09:00
$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 ;
2026-01-05 06:02:14 +09:00
$subscription_fee = $data [ 'subscription_fee' ] ? ? 0 ;
2025-12-30 21:34:17 +09:00
2026-01-05 06:02:14 +09:00
$commission_amount = $contract_amount * 0.20 ; // 가입비의 20% 수당
2025-12-24 09:46:07 +09:00
2026-01-05 06:02:14 +09:00
$stmt = $pdo -> prepare ( " UPDATE sales_tenant_products SET product_name = ?, contract_amount = ?, subscription_fee = ?, commission_rate = ?, commission_amount = ?, contract_date = ?, sub_models = ? WHERE id = ? " );
$stmt -> execute ([ $product_name , $contract_amount , $subscription_fee , 20 , $commission_amount , $contract_date , $sub_models , $product_id ]);
2025-12-24 09:46:07 +09:00
echo json_encode ([ 'success' => true , 'message' => '계약 정보가 수정되었습니다.' ]);
2026-01-04 17:39:59 +09:00
} elseif ( $action === 'update_tenant' ) {
$tenant_id = $data [ 'id' ] ? ? null ;
if ( ! checkTenantPermission ( $pdo , $tenant_id , $currentUser )) throw new Exception ( " 권한이 없습니다. " );
2026-01-04 17:52:14 +09:00
// 운영팀 등록 여부 확인
$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 ( " 운영팀에서 등록한 테넌트는 수정할 수 없습니다. " );
}
2026-01-04 17:39:59 +09:00
$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 ( " 권한이 없습니다. " );
2026-01-04 17:52:14 +09:00
// 운영팀 등록 여부 확인
$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 ( " 운영팀에서 등록한 테넌트는 삭제할 수 없습니다. " );
}
2026-01-04 17:39:59 +09:00
// 관련 데이터 삭제 (계약, 시나리오, 상담기록)
$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' => '테넌트가 삭제되었습니다.' ]);
2025-12-23 09:00:57 +09:00
}
break ;
}
} catch ( Exception $e ) {
echo json_encode ([ 'success' => false , 'error' => $e -> getMessage ()]);
}
2025-12-24 09:46:07 +09:00
?>