<?php
/**
 * 월별 수입/지출 예상 내역서
 *
 * 이 파일은 경동기업 월별 수입/지출 예상 내역서를 생성하고 표시합니다.
 * 사용자 세션을 확인하고 권한에 따라 페이지 접근을 제어합니다.
 * 데이터베이스에서 데이터를 조회하고 계산하여 HTML 테이블 형태로 출력합니다.
 */
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");

// 세션 확인 및 사용자 권한 검사
if (!isset($_SESSION["level"]) || $_SESSION["level"] > 5) {
    sleep(1);
    header("Location:" . $WebSite . "login/login_form.php");
    exit;
}

// 에러 표시 설정
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

// HTML 헤더 로드
include $_SERVER['DOCUMENT_ROOT'] . '/load_header.php';
$title_message = '월별 수입/지출 예상내역서';

// 데이터베이스 연결 설정 파일 로드
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");

// DB명 하드코딩 (mydb.php에서 db_name은 chandj)
if(empty($DB)) {
	$DB = 'chandj';
}

/**
 * 데이터베이스 쿼리를 실행하고 결과를 반환합니다.
 *
 * @param PDO $pdo PDO 객체
 * @param string $sql 실행할 SQL 쿼리
 * @param array $params 쿼리에 바인딩할 파라미터 배열 (선택 사항)
 * @return array|false 쿼리 결과 (연관 배열) 또는 실패 시 false
 * @throws PDOException 쿼리 실행 중 오류가 발생한 경우
 */
function executeQuery(PDO $pdo, string $sql, array $params = [])
{
    try {
        $stmt = $pdo->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    } catch (PDOException $e) {
        error_log("Query execution failed: " . $e->getMessage());
        return false;
    }
}
?>

<link href="css/style.css" rel="stylesheet">
<title><?= $title_message ?></title>
<style>
    /* 테이블에 테두리 추가 */
    #detailTable,
    #detailTable th,
    #detailTable td {
        border: 1px solid black;
        border-collapse: collapse;
    }

    /* 테이블 셀 패딩 조정 */
    #detailTable th,
    #detailTable td {
        padding: 10px;
        text-align: center;
    }

	.custom-modal-body {
		max-height: 600px;
		overflow-y: auto;	
	}
</style>
</head>

<body>

<?php
// 세무사아이디면 다른 메뉴 연결
if($_SESSION["userid"] == '0266771300') {
	include $_SERVER['DOCUMENT_ROOT'] . '/myheader_accountant.php'; 
}
else {
	include $_SERVER['DOCUMENT_ROOT'] . '/myheader.php'; 
}
?>   
<?php
// 동적 대용랴 모달창 가져오기 js, css 파일 가져옴
require_once($_SERVER['DOCUMENT_ROOT'].'/modal/bulkModal.php'); 
// 미수금 데이터 가져오기
require_once($_SERVER['DOCUMENT_ROOT'] . "/account/fetch_balance.php");

// DB명 하드코딩 (mydb.php에서 db_name은 chandj)
$DB = 'chandj';
$tablename = 'account_plan';
$tablename_in = 'account_plan_in';

// 파라미터에서 검색어, 연월 가져오기, 없으면 기본값 설정
$searchKeyword = isset($_REQUEST['search']) ? $_REQUEST['search'] : '';
$selectedYearMonth = isset($_REQUEST['yearMonth']) ? $_REQUEST['yearMonth'] : date("Ym");

// 기준 연월에 따른 fromdate, todate 설정 (검색 기간)
$startDate = $selectedYearMonth . '01'; // Ym01
$endDate = date("Y-m-t", strtotime($startDate)); // Y-m-마지막날
$formattedStartDate = date("Y-m-d", strtotime($startDate)); // Y-m-d
$formattedEndDate = date("Y-m-d", strtotime($endDate)); // Y-m-d

// 거래처별 잔액 계산 (output/output_extra 기반)
$balances = fetch_balances($DB, $startDate, $endDate);

// 거래처 목록
$allVendors = array_keys($balances);

// 미수금 계산 및 거래처명 조회
$receivables = [];
$vendorNames = [];
foreach ($allVendors as $secondordnum) {
    $balance = isset($balances[$secondordnum]) ? $balances[$secondordnum] : 0;
    $receivableAmount = ($balance > 0) ? $balance : 0;
    $receivables[$secondordnum] = $receivableAmount;
    // 거래처 이름 가져오기
    $vendorNameSql = "SELECT vendor_name FROM phonebook WHERE secondordnum = :secondordnum AND (is_deleted IS NULL OR is_deleted = 0)";
    $vendorNameParams = [':secondordnum' => $secondordnum];
    $vendorNameResult = executeQuery($pdo, $vendorNameSql, $vendorNameParams);
    $vendorNames[$secondordnum] = $vendorNameResult[0]['vendor_name'] ?? '';
}

// 수입 내역 (계산서 발행 등은 기존 monthly_sales 테이블 사용, 필요시 output 기반으로 확장)
$incomeData = [];
foreach ($receivables as $secondordnum => $receivableAmount) {
    if ($receivableAmount > 0) {
        $incomeData[] = [
            'customer_name' => $vendorNames[$secondordnum],
            'receivableAmount' => $receivableAmount,
            'totalAmount' => $receivableAmount,
            'secondordnum' => $secondordnum
        ];
    }
}

// 현재 잔액 계산서
$currentDate = date("Y-m-d"); // 현재 날짜

// fromdate 또는 todate가 빈 문자열이거나 null인 경우
if (empty($formattedStartDate) || empty($formattedEndDate)) {
	// 현재 월의 1일을 fromdate로 설정
	$formattedStartDate = date("Y-m-01");
	// 전달의 29일 구하기
	// $formattedStartDate = date("Y-m-29", strtotime("-1 month", strtotime($formattedStartDate)));
	$formattedEndDate = $currentDate;
	$Transtodate = $formattedEndDate;
} else {		
	$Transtodate = $formattedEndDate;
}

/**
 * 문자열이 null이 아니고 빈 문자열이 아닌지 확인합니다.
 *
 * @param string|null $str 확인할 문자열
 * @return bool 문자열이 null이 아니고 비어 있지 않으면 true, 그렇지 않으면 false
 */
function checkNull(?string $str): bool
{
	return $str !== null && trim($str) !== '';
}

// account 테이블 쿼리 조건 및 파라미터 설정
$accountQueryConditions = [];
$accountQueryParams = [];

if (checkNull($searchKeyword)) {
	$accountQueryConditions[] = "searchtag LIKE :searchKeyword";
	$accountQueryParams[':searchKeyword'] = "%$searchKeyword%";
}

$accountQueryConditions[] = "registDate BETWEEN :formattedStartDate AND :formattedEndDate";
$accountQueryParams[':formattedStartDate'] = $formattedStartDate;
$accountQueryParams[':formattedEndDate'] = $formattedEndDate;

$accountQueryConditions[] = "(is_deleted = 0 OR is_deleted IS NULL)";

// 수입/지출 구분
$inoutType = isset($_REQUEST['inoutsep_select']) ? $_REQUEST['inoutsep_select'] : '';
if (checkNull($inoutType)) {
	$accountQueryConditions[] = "inoutsep = :inoutType";
	$accountQueryParams[':inoutType'] = $inoutType;
}

// 내용
$contentType = isset($_REQUEST['content_select']) ? $_REQUEST['content_select'] : '';
if (checkNull($contentType)) {
	$accountQueryConditions[] = "content = :contentType";
	$accountQueryParams[':contentType'] = $contentType;
}

// account 테이블에서 데이터 조회
$accountTable = $DB . '.account';
$accountOrder = " ORDER BY registDate ASC, num ASC ";
$accountSql = "SELECT * FROM {$accountTable} WHERE " . implode(' AND ', $accountQueryConditions) . $accountOrder;

// PDO prepared statement 사용
$stmt = $pdo->prepare($accountSql);
$stmt->execute($accountQueryParams);
$accountData = $stmt->fetchAll(PDO::FETCH_ASSOC);

// 수입, 지출을 기반으로 초기 잔액 계산
$initialBalanceSql = "
	SELECT
		SUM(CASE WHEN inoutsep = '수입' THEN REPLACE(amount, ',', '') ELSE 0 END) +
		SUM(CASE WHEN inoutsep = '최초전월이월' THEN REPLACE(amount, ',', '') ELSE 0 END) -
		SUM(CASE WHEN inoutsep = '지출' THEN REPLACE(amount, ',', '') ELSE 0 END) AS balance 
	FROM {$accountTable}
	WHERE is_deleted = '0' AND registDate < :formattedStartDate
";
$initialBalanceParams = [':formattedStartDate' => $formattedStartDate];
$initialBalanceResult = executeQuery($pdo, $initialBalanceSql, $initialBalanceParams);
$initialBalance = $initialBalanceResult[0]['balance'];

// 총 수입 계산
$totalIncomeSql = "
	SELECT SUM(REPLACE(amount, ',', '')) AS totalIncome
	FROM {$accountTable}
	 WHERE is_deleted = '0' AND (inoutsep = '수입' OR inoutsep = '최초전월이월') 
	AND registDate BETWEEN :formattedStartDate AND :formattedEndDate
";
$totalIncomeParams = [
	':formattedStartDate' => $formattedStartDate,
	':formattedEndDate' => $formattedEndDate
];
$totalIncomeResult = executeQuery($pdo, $totalIncomeSql, $totalIncomeParams);
$totalIncome = $totalIncomeResult[0]['totalIncome'];

// 총 지출 계산
$totalExpenseSql = "
	SELECT SUM(REPLACE(amount, ',', '')) AS totalExpense
	FROM {$accountTable}
	WHERE is_deleted = '0' AND inoutsep = '지출'
	AND registDate BETWEEN :formattedStartDate AND :formattedEndDate
";
$totalExpenseParams = [
	':formattedStartDate' => $formattedStartDate,
	':formattedEndDate' => $formattedEndDate
];
$totalExpenseResult = executeQuery($pdo, $totalExpenseSql, $totalExpenseParams);
$totalExpense = $totalExpenseResult[0]['totalExpense'];

// 최종 잔액 계산
$finalBalance = $initialBalance + $totalIncome - $totalExpense;




// Bankbook options
$bankbookOptions = [];
$jsonFile = $_SERVER['DOCUMENT_ROOT'] . "/account/accoutlist.json";
$accounts = [];
$selectedAccount = null;
$accountBalances = [];

if (file_exists($jsonFile)) {
    $jsonContent = file_get_contents($jsonFile);
    $accounts = json_decode($jsonContent, true);
    if (is_array($accounts) && !empty($accounts)) {
        // 선택된 계좌 또는 기본 계좌(첫 번째) 설정
        $selectedAccountIndex = isset($_REQUEST['selected_account']) ? intval($_REQUEST['selected_account']) : 0;
        $selectedAccount = $accounts[$selectedAccountIndex] ?? $accounts[0];
        
        // 각 계좌별 잔액 계산
        foreach ($accounts as $index => $account) {
            $accountDisplay = $account['company'] . ' ' . $account['number'];
            if (!empty($account['memo'])) {
                $accountDisplay .= ' (' . $account['memo'] . ')';
            }
            
            // 해당 계좌의 잔액 계산
            $accountBalanceSql = "SELECT 
                SUM(CASE WHEN inoutsep = '수입' AND bankbook = ? THEN REPLACE(amount, ',', '') ELSE 0 END) +
                SUM(CASE WHEN inoutsep = '최초전월이월' AND bankbook = ? THEN REPLACE(amount, ',', '') ELSE 0 END) -
                SUM(CASE WHEN inoutsep = '지출' AND bankbook = ? THEN REPLACE(amount, ',', '') ELSE 0 END) AS balance
                FROM $tablename 
                WHERE is_deleted = '0'";
            $accountBalanceStmh = $pdo->prepare($accountBalanceSql);
            $accountBalanceStmh->bindValue(1, $accountDisplay, PDO::PARAM_STR);
            $accountBalanceStmh->bindValue(2, $accountDisplay, PDO::PARAM_STR);
            $accountBalanceStmh->bindValue(3, $accountDisplay, PDO::PARAM_STR);
            $accountBalanceStmh->execute();
            $accountBalances[$index] = $accountBalanceStmh->fetch(PDO::FETCH_ASSOC)['balance'] ?? 0;
        }
    }
}


// 각 계좌별 요약 정보를 담을 배열 초기화
$accountSummaries = [];
if (is_array($accounts)) {
    foreach ($accounts as $index => $account) {
        $accountDisplay = $account['company'] . ' ' . $account['number'];
        if (!empty($account['memo'])) {
            $accountDisplay .= ' (' . $account['memo'] . ')';
        }

        // 1. 계좌별 기초 잔액 (기간 이전)
        $initialSql = "SELECT 
            (SUM(CASE WHEN inoutsep = '수입' OR inoutsep = '최초전월이월' THEN REPLACE(amount, ',', '') ELSE 0 END) -
             SUM(CASE WHEN inoutsep = '지출' THEN REPLACE(amount, ',', '') ELSE 0 END)) AS balance
            FROM $tablename 
            WHERE is_deleted = '0' AND registDate < :fromdate AND bankbook = :bankbook";
        $initialStmh = $pdo->prepare($initialSql);
        $initialStmh->bindParam(':fromdate', $fromdate);
        $initialStmh->bindParam(':bankbook', $accountDisplay);
        $initialStmh->execute();
        $initialBalanceAccount = $initialStmh->fetch(PDO::FETCH_ASSOC)['balance'] ?? 0;

        // 2. 기간 내 수입
        $incomeSql = "SELECT SUM(REPLACE(amount, ',', '')) AS totalIncome 
            FROM $tablename 
            WHERE is_deleted = '0' AND (inoutsep = '수입' OR inoutsep = '최초전월이월')
            AND registDate BETWEEN :fromdate AND :todate AND bankbook = :bankbook";
        $incomeStmh = $pdo->prepare($incomeSql);
        $incomeStmh->bindParam(':fromdate', $fromdate);
        $incomeStmh->bindParam(':todate', $todate);
        $incomeStmh->bindParam(':bankbook', $accountDisplay);
        $incomeStmh->execute();
        $totalIncomeAccount = $incomeStmh->fetch(PDO::FETCH_ASSOC)['totalIncome'] ?? 0;

        // 3. 기간 내 지출
        $expenseSql = "SELECT SUM(REPLACE(amount, ',', '')) AS totalExpense 
            FROM $tablename 
            WHERE is_deleted = '0' AND inoutsep = '지출' 
            AND registDate BETWEEN :fromdate AND :todate AND bankbook = :bankbook";
        $expenseStmh = $pdo->prepare($expenseSql);
        $expenseStmh->bindParam(':fromdate', $fromdate);
        $expenseStmh->bindParam(':todate', $todate);
        $expenseStmh->bindParam(':bankbook', $accountDisplay);
        $expenseStmh->execute();
        $totalExpenseAccount = $expenseStmh->fetch(PDO::FETCH_ASSOC)['totalExpense'] ?? 0;

        // 4. 최종 잔액
        $finalBalanceAccount = $initialBalanceAccount + $totalIncomeAccount - $totalExpenseAccount;

        // 계산된 정보를 배열에 저장
        $accountSummaries[$index] = [
            'name' => $accountDisplay,
            'income' => $totalIncomeAccount,
            'expense' => $totalExpenseAccount,
            'balance' => $finalBalanceAccount
        ];
    }
}


// 각 계좌별 최종 잔액 정보를 담을 배열 초기화
$accountFinalBalances = [];
if (is_array($accounts)) {
    foreach ($accounts as $index => $account) {
        $accountDisplay = $account['company'] . ' ' . $account['number'];
        if (!empty($account['memo'])) {
            $accountDisplay .= ' (' . $account['memo'] . ')';
        }

        // 계좌별 전체 기간의 최종 잔액 계산
        $balanceSql = "SELECT 
            (SUM(CASE WHEN inoutsep = '수입' OR inoutsep = '최초전월이월' THEN REPLACE(amount, ',', '') ELSE 0 END) -
             SUM(CASE WHEN inoutsep = '지출' THEN REPLACE(amount, ',', '') ELSE 0 END)) AS balance
            FROM {$DB}.account 
            WHERE is_deleted = '0' AND bankbook = :bankbook";
        
        $balanceStmh = $pdo->prepare($balanceSql);
        $balanceStmh->bindParam(':bankbook', $accountDisplay);
        $balanceStmh->execute();
        $balanceResult = $balanceStmh->fetch(PDO::FETCH_ASSOC);

        // 계산된 정보를 배열에 저장
        $accountFinalBalances[$index] = [
            'name' => $accountDisplay,
            'balance' => $balanceResult['balance'] ?? 0
        ];
    }
}



// 수입/지출 내역 조회를 위한 연도 설정
$year = isset($_REQUEST['year']) ? $_REQUEST['year'] : date('Y');

// 조회할 월 설정 (기본값: 현재 월)
$selectedMonth = isset($_REQUEST['startMonth']) ? $_REQUEST['startMonth'] : date('m');

// 계산서 발행 조회할 전달(이전 월) 계산
$prevMonth = $selectedMonth - 1;
if ($prevMonth == 0) {
	$prevMonth = 12;
	$year = $year - 1; // 연도가 바뀌는 경우 처리
}

// 이전달의 시작일과 종료일 설정
$prevStartDate = "$year-$prevMonth-01";
// $prevStartDate = date("Y-m-29", strtotime("-1 month", strtotime($prevStartDate)));
$prevEndDate = date("Y-m-t", strtotime($prevStartDate));

// 수입 내역 조회
$monthlySalesTable = $DB . '.monthly_sales';

$incomeSql = "
	SELECT customer_name, invoice_issued, sales as amount, secondordnum, SUM(sales) as totalAmount
	FROM {$monthlySalesTable}
	WHERE invoice_issued = '발행'
	AND closure_date BETWEEN :prevStartDate AND :prevEndDate
	AND (is_deleted = '0' or is_deleted IS NULL)
	GROUP BY customer_name
";
$incomeParams = [
	':prevStartDate' => $prevStartDate,
	':prevEndDate' => $prevEndDate
];
$incomeData = executeQuery($pdo, $incomeSql, $incomeParams);

// 미수금을 수입 내역에 추가
foreach ($receivables as $secondordnum => $receivableAmount) {
	if ($receivableAmount > 0) {
		$incomeData[] = [
			'customer_name' => $vendorNames[$secondordnum],
			'receivableAmount' => $receivableAmount,
			'totalAmount' => $receivableAmount,
			'secondordnum' => $secondordnum
		];
	}
}

// 미수금 누계 처리
$accumulatedIncomeData = [];
foreach ($incomeData as $item) {
	$secondordnum = $item['secondordnum'];

	// 누적 데이터에 secondordnum이 이미 존재하는지 확인
	if (isset($accumulatedIncomeData[$secondordnum])) {
		// 존재하면 금액을 누계
		$accumulatedIncomeData[$secondordnum]['amount'] += isset($item['amount']) ? $item['amount'] : 0;
		$accumulatedIncomeData[$secondordnum]['receivableAmount'] += isset($item['receivableAmount']) ? $item['receivableAmount'] : 0;
		$accumulatedIncomeData[$secondordnum]['totalAmount'] += isset($item['totalAmount']) ? $item['totalAmount'] : 0;
	} else {
		// 존재하지 않으면 새로운 항목을 추가, 없는 필드 초기화
		$accumulatedIncomeData[$secondordnum] = [
			'customer_name' => $item['customer_name'],
			'amount' => isset($item['amount']) ? $item['amount'] : 0,
			'receivableAmount' => isset($item['receivableAmount']) ? $item['receivableAmount'] : 0,
			'totalAmount' => isset($item['totalAmount']) ? $item['totalAmount'] : 0,
			'secondordnum' => $secondordnum
		];
	}
}

// 배열을 다시 숫자 인덱스로 변환
$incomeData = array_values($accumulatedIncomeData);

// 현재 기준월의 1일부터 현재 날짜까지 수금된 데이터 조회
$fromdate = date("Y-m-01");
// 전전달의 29일 구하기
// $fromdate = date("Y-m-29", strtotime("-1 month", strtotime($fromdate)));
// $todate = date("Y-m-d");
// $lastmonthEnddate = date("Y-m-t", strtotime("first day of last month")); //전달의 **말일(마지막 날)**을 
$lastmonthEnddate = date("Y-m-t");

// account 테이블에서 해당 거래처의 수금된 항목 조회
$paymentSql = "
	SELECT secondordnum, SUM(CAST(REPLACE(amount, ',', '') AS SIGNED)) AS total_payment
	FROM {$accountTable}
	WHERE inoutsep = '수입'
	AND registDate BETWEEN :fromdate AND :lastmonthEnddate
	AND (is_deleted IS NULL OR is_deleted = 0)
	GROUP BY secondordnum
";
$paymentParams = [
	':fromdate' => $fromdate,
	':lastmonthEnddate' => $lastmonthEnddate
];
$paymentData = executeQuery($pdo, $paymentSql, $paymentParams);

// 이미 수금된 secondordnum을 배열로 저장
$receivedPayments = [];
foreach ($paymentData as $row) {
	$secondordnum = $row['secondordnum'];
	$totalPayment = (float)$row['total_payment'];
	// $totalPayment = 0 ; // 이미 수금된것 제외 코드

	// 수금 내역을 기록 (이미 수금된 금액이 있으면 배열에 추가) 수금이 계산서 금액과 일치하면 제외되는 알고리즘 추가한다.
	if (intval($totalPayment) > 0) {
		$receivedPayments[$secondordnum] = $totalPayment;
	}
}

// echo '<pre>';
// print_r($paymentData);
// echo '</pre>';	

// 수금된 금액을 차감한 나머지 미수금 계산
$filteredIncomeData = [];
foreach ($incomeData as $incomeRow) {
	$secondordnum = $incomeRow['secondordnum'] ?? '';

	// 수금된 금액이 있는지 확인
	if (isset($receivedPayments[$secondordnum])) {
		
		// echo ' , ' . $incomeRow['receivableAmount'] . '   미수금 : ' . $receivedPayments[$secondordnum] ;
		
		if( $incomeRow['receivableAmount'] ==  $receivedPayments[$secondordnum]) {
		// 수금된 금액을 차감한 나머지 미수금을 계산		
		$remainingAmount = $incomeRow['receivableAmount'] - $receivedPayments[$secondordnum];  // 현재월의 수금내역 차감공식 수정 250415 찾음
		} 
		else
		{
		   $remainingAmount = $incomeRow['receivableAmount'] ;
		}
		
		// 나머지 미수금이 0보다 크거나 같으면 배열에 추가
		if ($remainingAmount >= 0) {
			$incomeRow['receivableAmount'] = $remainingAmount;
			// totalAmount는 원래의 매출 금액으로 유지되므로 별도 할당 불필요
			$filteredIncomeData[] = $incomeRow;
		}
	} else {
		// 수금된 금액이 없으면 그대로 추가
		$filteredIncomeData[] = $incomeRow;
	}
}

// vendorNames 기준으로 $filteredIncomeData 정렬
usort($filteredIncomeData, function ($a, $b) use ($vendorNames) {
	return strcmp($vendorNames[$a['secondordnum']], $vendorNames[$b['secondordnum']]);
});

// 제외된 항목 파일 경로
$excludedItemsFile = $_SERVER['DOCUMENT_ROOT'] . "/account_plan/excluded_items.json";

// 제외된 항목 로드
$excludedItems = [];
if (file_exists($excludedItemsFile)) {
	$excludedItems = json_decode(file_get_contents($excludedItemsFile), true);
}

// 디버깅을 위한 코드 추가
// echo '<pre>--- 제외된 항목 ($excludedItems) ---';
// print_r($excludedItems);
// echo '</pre>';

// $filteredIncomeData에서 제외된 항목 필터링
$filteredIncomeDataForDebugging = $filteredIncomeData; // 디버깅을 위해 원본 배열 복사
if (!empty($excludedItems)) {
	$filteredIncomeData = array_filter($filteredIncomeData, function ($item) use ($excludedItems, $selectedYearMonth) {
		// 디버깅을 위한 코드 추가
		// echo '<pre>--- 현재 비교 중인 항목 ($item) ---';
		// print_r($item);
		// echo '</pre>';

		$isExcluded = false; // 제외 여부 플래그
		foreach ($excludedItems as $excludedItem) {
			// 디버깅을 위한 코드 추가
			// echo '<pre>--- 제외된 항목과 비교 ($excludedItem) ---';
			// print_r($excludedItem);
			// echo '--- 비교 결과 ---';
			// echo '$excludedItem[\'yearMonth\'] === $selectedYearMonth : ' . ($excludedItem['yearMonth'] === $selectedYearMonth ? 'true' : 'false') . '<br>';
			// echo '$excludedItem[\'customerName\'] === $item[\'customer_name\'] : ' . ($excludedItem['customerName'] === $item['customer_name'] ? 'true' : 'false') . '<br>';
			// echo 'intval($excludedItem[\'amount\']) === intval($item[\'totalAmount\']) : ' . (intval($excludedItem['amount']) === intval($item['totalAmount']) ? 'true' : 'false') . '<br>';
			// echo '</pre>';

			if (
				$excludedItem['yearMonth'] === $selectedYearMonth &&
				$excludedItem['customerName'] === $item['customer_name'] &&
				intval($excludedItem['amount']) === intval($item['totalAmount'])
			) {
				$isExcluded = true; // 제외 플래그 설정
				break;
			}
		}

		// 디버깅을 위한 코드 추가
		// echo '<pre>--- 최종 제외 여부: ' . ($isExcluded ? '제외됨' : '유지됨') . ' ---</pre>';

		return !$isExcluded; // 제외 여부에 따라 반환
	});
}

// 디버깅을 위한 코드 추가: 필터링 전후 비교
// echo '<pre>--- 필터링 전 ($filteredIncomeDataForDebugging) ---';
// print_r($filteredIncomeDataForDebugging);
// echo '</pre>';

// echo '<pre>--- 필터링 후 ($filteredIncomeData) ---';
// print_r($filteredIncomeData);
// echo '</pre>';

// ... (나머지 코드는 동일) ...

// 이번 달로 설정, 계산서는 지난달
$startMonth = isset($_REQUEST['startMonth']) ? $_REQUEST['startMonth'] : date('m');
$endMonth = isset($_REQUEST['endMonth']) ? $_REQUEST['endMonth'] : date('m');

$startDate = "$year-$startMonth-01";
$endDate = date("Y-m-t", strtotime("$year-$endMonth-01"));

// 지출 내역 조회 (월별 누적)
$accountPlanTable = 'account_plan';

$expenseSql = "
	SELECT content, SUM(amount) as totalAmount
	FROM $DB.$accountPlanTable 
	WHERE inoutsep = '지출'
	AND (is_deleted = '0' or is_deleted IS NULL)
	GROUP BY content
";

$expenseData = executeQuery($pdo, $expenseSql);

// 지출 상세 내역 조회
$expenseDetailSql = "
	SELECT num, content, amount, registDate, memo, ForeDate, approvalRequest, eworksNum, workDone 
	FROM $DB.$accountPlanTable 
	WHERE inoutsep = '지출'
	AND (is_deleted = '0' or is_deleted IS NULL)
";

$expenseDetailData = executeQuery($pdo, $expenseDetailSql);

// 수입/지출 합계 및 순이익 계산 (필터링된 데이터 사용)
$filteredTotalIncome = array_sum(array_column($filteredIncomeData, 'totalAmount'));
$filteredTotalExpense = array_sum(array_column($expenseData, 'totalAmount'));
$filteredNetIncome = $filteredTotalIncome - $filteredTotalExpense + $finalBalance;

// receivableAmount 또는 totalAmount 값이 0보다 큰 항목만 필터링
$filteredIncomeData = array_filter($filteredIncomeData, function ($item) {
	return (isset($item['receivableAmount']) && intval($item['receivableAmount']) > 0) ||
		(isset($item['totalAmount']) && intval($item['totalAmount']) > 0);
});

// vendorNames 기준으로 $filteredIncomeData 정렬
usort($filteredIncomeData, function ($a, $b) {
	return strcmp($a['customer_name'], $b['customer_name']);
});

// 수금을 바로 하는 업체를 처리하기 위한 코드
// 현재 날짜로부터 2개월 전의 1일을 시작일로 설정
$specialStartDate = (new DateTime('first day of -2 months'))->format('Y-m-d');
$specialEndDate = date("Y-m-d");

// account 테이블에서 해당 거래처의 수금된 항목 조회
$specialPaymentSql = "
SELECT secondordnum, SUM(CAST(REPLACE(amount, ',', '') AS SIGNED)) AS total_payment
FROM {$accountTable}
WHERE inoutsep = '수입'
AND registDate BETWEEN :specialStartDate AND :specialEndDate
AND (is_deleted IS NULL OR is_deleted = 0)
GROUP BY secondordnum
";
$specialPaymentParams = [
	':specialStartDate' => $specialStartDate,
	':specialEndDate' => $specialEndDate
];
$specialPaymentData = executeQuery($pdo, $specialPaymentSql, $specialPaymentParams);

// paymentDataSpecial 배열을 secondordnum을 키로 하는 형태로 재구성
$specialPaymentMap = [];
foreach ($specialPaymentData as $payment) {
	$specialPaymentMap[$payment['secondordnum']] = intval($payment['total_payment']);
}

// filteredIncomeData에서 secondordnum과 total_payment가 일치하는 항목 제거
$filteredIncomeData = array_filter($filteredIncomeData, function ($item) use ($specialPaymentMap) {
	// receivableAmount 또는 totalAmount 값이 있으면 intval로 변환
	$item['receivableAmount'] = isset($item['receivableAmount']) ? intval($item['receivableAmount']) : 0;
	$item['totalAmount'] = isset($item['totalAmount']) ? intval($item['totalAmount']) : 0;

	// paymentDataSpecial에 secondordnum이 있고, totalAmount와 total_payment가 일치하면 해당 항목을 제거
	if (isset($specialPaymentMap[$item['secondordnum']]) && $specialPaymentMap[$item['secondordnum']] === $item['totalAmount']) {
		return false; // 제거
	}

	// 제거되지 않은 항목만 반환
	return true;
});

// vendorNames 기준으로 $filteredIncomeData 정렬
usort($filteredIncomeData, function ($a, $b) {
	return strcmp($a['customer_name'], $b['customer_name']);
});


// 예상지급일 오름차순 정렬 코드

// 1) $expenseDetailData 배열이 준비된 직후, 테이블 출력 전에 추가
usort($expenseDetailData, function($a, $b) {
    // '0000-00-00' 혹은 빈 문자열은 매우 미래 날짜로 처리
    $dateA = (!empty($a['ForeDate']) && $a['ForeDate'] !== '0000-00-00')
             ? strtotime($a['ForeDate'])
             : PHP_INT_MAX;
    $dateB = (!empty($b['ForeDate']) && $b['ForeDate'] !== '0000-00-00')
             ? strtotime($b['ForeDate'])
             : PHP_INT_MAX;
    return $dateA <=> $dateB;
});

?>

<form id="board_form" name="board_form" method="post" enctype="multipart/form-data">
	<input type="hidden" id="mode" name="mode" value="<?= isset($mode) ? $mode : '' ?>">
	<input type="hidden" id="num" name="num" value="<?= isset($num) ? $num : '' ?>">
	<input type="hidden" id="tablename" name="tablename" value="<?= isset($tablename) ? $tablename : '' ?>">
	<input type="hidden" id="startMonth" name="startMonth" value="<?= isset($startMonth) ? $startMonth : '' ?>">
	<input type="hidden" id="endMonth" name="endMonth" value="<?= isset($endMonth) ? $endMonth : '' ?>">

	<div class="container-fluid">
		<div id="myModal" class="modal">
			<div class="modal-content" style="width:800px;">
				<div class="modal-header">
					<span class="modal-title"><?= $title_message ?></span>
					<span class="close">&times;</span>
				</div>
				<div class="modal-body">
					<div class="custom-card"></div>
				</div>
			</div>
		</div>
	</div>
	
	<div class="container-fluid mt-5">
		<div class="card justify-content-center text-center mt-5">
			<div class="card-header">
				<span class="text-center fs-5"> <?= $title_message ?>
					<button type="button" class="btn btn-dark btn-sm me-1" onclick='location.reload()'> <i class="bi bi-arrow-clockwise"></i> </button>
				</span>
			</div>
			<div class="card-body">
				<div class="row mb-3">
					<div class="d-flex justify-content-center align-items-center">
						<select id="year" name="year" class="form-select w-auto me-2" style="font-size:0.8rem; height:32px;" disabled  onchange="loadDetails()">
							<?php for ($i = date('Y'); $i >= 2024; $i--) : ?>
								<option value="<?= $i ?>" <?= ($year == $i) ? 'selected' : '' ?>><?= $i ?>년</option>
							<?php endfor; ?>
						</select>

						<button id="newInBtn" type="button" class="btn btn-dark btn-sm mx-1"> <i class="bi bi-pencil-square"></i> 수입등록 </button>
						<button id="expenditureBtn" type="button" class="btn btn-dark btn-sm mx-1"> <i class="bi bi-pencil-square"></i> 지출등록 </button>
						<button id="excludedListBtn" type="button" class="btn btn-primary btn-sm mx-1"> <i class="bi bi-card-checklist"></i> 수입제외목록 </button>
						<button type="button" class="btn btn-dark btn-sm mx-1" id="csvDownload"> <i class="bi bi-floppy-fill"></i>  CSV </button>
						<button id="bulkNewBtn" type="button" class="btn btn-info btn-sm mx-3"> <i class="bi bi-copy"></i> 선택항목 다음달로 복제 </button>
						<button id="approvalRequestBtn" type="button" class="btn btn-success btn-sm mx-3"> <i class="bi bi-file-earmark-arrow-up"></i> 전자결재요청 </button>
						<div class="form-check form-check-inline ms-3">
							<input class="form-check-input" type="checkbox" id="excludeCompleted" checked>
							<label class="form-check-label" for="excludeCompleted" style="font-size: 0.9rem;">
								결재완료 제외
							</label>
						</div>
					</div>
				</div>

				<div class="d-flex flex-wrap justify-content-start align-items-center mt-2 p-2 border rounded" style="gap: 10px;">                
				<strong class="me-2">계좌 잔액:</strong>
				<?php foreach ($accountFinalBalances as $summary): ?>
					<?php if ($summary['balance'] > 0): ?>
						<?php 
						// USD가 포함된 경우 금액 앞에 $ 추가
						$isUSD = stripos($summary['name'], 'USD') !== false;
						$formattedBalance = $isUSD ? '$' . number_format($summary['balance']) : number_format($summary['balance']);
						?>
						<div class="border rounded p-1" style="font-size: 0.8em;">
							<span class="text-secondary"><?= htmlspecialchars($summary['name']) ?>:</span>
							<span class="fw-bold ms-1"><?= $formattedBalance ?></span>
						</div>
					<?php endif; ?>
				<?php endforeach; ?>

            </div>	
				<div class="row mb-4">
					<table class="table table-hover" id="detailTable">
						<thead class="table-info">
							<tr>
								<th colspan="2" class="text-center">수입</th>
								<th colspan="8" class="text-center">지출</th>
							</tr>
							<tr>
								<th class="text-center">항목</th>
								<th class="text-center">금액</th>
								<th class="text-center"><h6><span id="selectAllCheckbox" class="text-primary" style="cursor: pointer; user-select: none;"> ☑ </span> 선택 </h6> </th>
								<th class="text-center">예상지급일</th>
								<th class="text-center">항목</th>
								<th class="text-center">금액</th>
								<th class="text-center">전자결재요청</th>		
								<th class="text-center">결재번호</th>
								<th class="text-center">결재상태</th>
								<th class="text-center">비고</th>
							</tr>
						</thead>
						<tbody>
							<?php
							// 미수금, 계산서 업체를 분할 후 다시 합치는 로직 구현
							$receivablesData = [];
							$invoicesData = [];

							// 이번 달의 시작일과 종료일 계산
							$currentMonthStartDate = date('Y-m-01');
							$currentMonthEndDate = date('Y-m-t');

							// 기존 데이터에서 미수금 및 계산서 발행 금액을 분리
							foreach ($filteredIncomeData as $incomeRow) {
								// 미수금이 있는 경우 receivablesData 배열에 추가
								if ($incomeRow['receivableAmount'] > 0) {
									$receivablesData[] = [
										'customer_name' => $incomeRow['customer_name'],
										'receivableAmount' => $incomeRow['receivableAmount'],
										'secondordnum' => $incomeRow['secondordnum']
									];
								}

								// 계산서 발행 금액이 있는 경우 invoicesData 배열에 추가
								if ($incomeRow['amount'] > 0) {
									$invoicesData[] = [
										'customer_name' => $incomeRow['customer_name'],
										'amount' => $incomeRow['amount'],
										'secondordnum' => $incomeRow['secondordnum']
									];
								}
							}

							// 데이터베이스에서 수동으로 입력된 자료 가져오기
							$manualInputSql = "
								SELECT content AS customer_name, amount, secondordnum, num
								FROM {$DB}.{$accountPlanTable}_in
								WHERE registDate BETWEEN :currentMonthStartDate AND :currentMonthEndDate
								AND (is_deleted = '0' or is_deleted IS NULL)
							";
							$manualInputParams =	[
								':currentMonthStartDate' => $currentMonthStartDate,
								':currentMonthEndDate' => $currentMonthEndDate
							];
							$manualEntries = executeQuery($pdo, $manualInputSql, $manualInputParams);

							// 수동으로 입력된 자료를 기존 데이터에 추가
							foreach ($manualEntries as $entry) {
								// 계산서 발행 금액이 있는 경우 invoicesData 배열에 추가
								if ($entry['amount'] > 0) {
									$invoicesData[] = [
										'customer_name' => '(수기) ' . $entry['customer_name'],
										'amount' => $entry['amount'],
										'secondordnum' => $entry['secondordnum'],
										'num' => $entry['num']
									];
								}
							}

							// 최종적으로 두 배열을 다시 합칩니다.
							$finalIncomeData = array_merge($receivablesData, $invoicesData);

							// 월별 수입/지출 합계 초기화
							$monthlyTotalIncome = 0;
							$monthlyTotalExpense = 0;

							$maxRows = max(count($finalIncomeData), count($expenseDetailData));
							for ($i = 0; $i < $maxRows; $i++) :
								// 수입/미수금
								$incomeContent = isset($finalIncomeData[$i]['customer_name']) ? $finalIncomeData[$i]['customer_name'] . (isset($finalIncomeData[$i]['receivableAmount']) ? ' (미수금)' : ' (계산서발행)') : '';
								$incomeAmount = isset($finalIncomeData[$i]['receivableAmount']) && intval($finalIncomeData[$i]['receivableAmount']) > 0 ? $finalIncomeData[$i]['receivableAmount'] : (isset($finalIncomeData[$i]['amount']) ? $finalIncomeData[$i]['amount'] : 0);

								// Income details
								$incomeNum = isset($finalIncomeData[$i]['num']) ? $finalIncomeData[$i]['num'] : '';

								// Expense details
								$expenseNum = isset($expenseDetailData[$i]['num']) ? $expenseDetailData[$i]['num'] : '';
								$expenseContent = isset($expenseDetailData[$i]['content']) ? $expenseDetailData[$i]['content'] : '';
								$expenseAmount = isset($expenseDetailData[$i]['amount']) ? $expenseDetailData[$i]['amount'] : 0;
								$expenseMemo = isset($expenseDetailData[$i]['memo']) ? $expenseDetailData[$i]['memo'] : '';
								$expenseForeDate = isset($expenseDetailData[$i]['ForeDate']) && $expenseDetailData[$i]['ForeDate'] !== '0000-00-00' ? $expenseDetailData[$i]['ForeDate'] : '';
								$approvalRequest = isset($expenseDetailData[$i]['approvalRequest']) ? (!empty($expenseDetailData[$i]['approvalRequest']) ? '✅' : '') : '';								
								
								// 변경된 코드
								$eworksNum = isset($expenseDetailData[$i]['eworksNum']) ? $expenseDetailData[$i]['eworksNum'] : '';
								if ($eworksNum) {
									// eworks 테이블에서 해당 num의 status 조회
									$statusStmt = $pdo->prepare("SELECT status FROM {$DB}.eworks WHERE num = ? LIMIT 1");
									$statusStmt->execute([ $eworksNum ]);
									$row = $statusStmt->fetch(PDO::FETCH_ASSOC);

									// status 가 'end' 면 완료, 아니면 공백
									$workdone = (isset($row['status']) && $row['status'] === 'end') ? '완료' : '';
								} else {
									$workdone = '';
								}

								// 월별 수입/지출 합계
								$monthlyTotalIncome += floatval($incomeAmount);
								$monthlyTotalExpense += floatval($expenseAmount);

								// 미수금 항목에 'text-danger' 클래스 추가
								$incomeClass = (strpos($incomeContent, '미수금') !== false) ? 'text-danger' : '';

								echo '<tr >';											
									echo '<td class="text-start fw-bold ' . $incomeClass . ' income-row" data-year-month="' . $selectedYearMonth . '" data-customer-name="' . htmlspecialchars($incomeContent) . '" data-amount="' . $incomeAmount . '">' . $incomeContent . '</td>';                                    
									echo '<td class="text-end text-primary fw-bold income-row"'
										. ' data-year-month="' . $selectedYearMonth . '"'
										. ' data-customer-name="' . htmlspecialchars($incomeContent) . '"'
										. ' data-amount="' . $incomeAmount . '">'
										. ($incomeAmount > 0 ? number_format($incomeAmount) : '')
										. '</td>';

									echo '<td><input type="checkbox" class="select-row" data-num="' . $expenseNum . '"></td>';							
									?>									
									<td class="text-center text-secondary fw-bold" onclick="loadForm('update', '<?= $expenseNum ?>', 'account_plan');"><?= $expenseForeDate ?></td>
									<td class="text-start" onclick="loadForm('update', '<?= $expenseNum ?>', 'account_plan');"><?= $expenseContent ?></td>
									<td class="text-end text-danger fw-bold" onclick="loadForm('update', '<?= $expenseNum ?>', 'account_plan');">
										<?= floatval($expenseAmount) > 0 ? number_format((float)$expenseAmount) : '' ?>
									</td>
									<td class="text-center text-secondary fw-bold" onclick="loadForm('update', '<?= $expenseNum ?>', 'account_plan');"><?= $approvalRequest ?></td>
									<td class="text-center text-secondary fw-bold" onclick="loadForm('update', '<?= $expenseNum ?>', 'account_plan');"><?= $eworksNum ?></td>
									<td class="text-center text-secondary fw-bold" onclick="loadForm('update', '<?= $expenseNum ?>', 'account_plan');"><?= $workdone ?></td>
									<td class="text-start text-secondary fw-bold" onclick="loadForm('update', '<?= $expenseNum ?>', 'account_plan');"><?= $expenseMemo ?></td>
								</tr>
								
					<?php
						// ↓ 여기서부터 소계 추가 로직
						// 현재 행의 지출 예상지급일
						$currentDate = $expenseDetailData[$i]['ForeDate'] ?? '';
						// 다음 행의 지출 예상지급일 (존재하지 않으면 빈 문자열)
						$nextDate    = $expenseDetailData[$i+1]['ForeDate'] ?? '';

						// 날짜가 유효하고('0000-00-00'은 빈값으로 처리) 그룹이 바뀌는 시점이라면
						if (
							!empty($currentDate) && $currentDate !== '0000-00-00'
							&& $currentDate !== $nextDate
						) {
							// 해당 날짜의 합계 계산
							$sum = 0;
							foreach ($expenseDetailData as $erow) {
								if ($erow['ForeDate'] === $currentDate) {
									$sum += floatval(str_replace(',', '', $erow['amount']));
								}
							}

							// 소계 행 출력
							echo '<tr>';
							// 수입 컬럼 영역 빈칸
							echo '<td colspan="4"></td>';
							// 4번째 컬럼: 날짜 소계 라벨
							echo '<td class="text-end fw-bold table-secondary">' 
								. date('n/j', strtotime($currentDate)) 
								. ' 소계</td>';
							// 5번째 컬럼: 소계 금액
							echo '<td class="text-end text-danger fw-bold  table-secondary">'
								. number_format($sum)
								. '</td>';
							// 6번째 컬럼: 빈칸
							echo '<td></td>';
							echo '</tr>';
						}
						// ↑ 소계 로직 끝
						?>
						<?php endfor; ?>
					</tbody>
					<tfoot class="">
						<tr>
							<th class="text-end table-secondary"> 수입 합계 &nbsp; </th>
							<th class="text-end text-primary table-secondary"><?= number_format($monthlyTotalIncome) ?></th>
							<th class="text-end table-secondary" colspan="3"> 지출 합계 &nbsp; </th>
							<th class="text-end text-danger table-secondary"><?= number_format($monthlyTotalExpense) ?></th>
							<th class="text-end" colspan="4"></th>
						</tr>
						<tr>
							<th class="text-end table-secondary" colspan="5"> (계좌 잔액) </th>
							<th class="text-end table-secondary"><?= number_format($finalBalance) ?></th>
							<th class="text-end" colspan="4"></th>
						</tr>
						<tr>
							<th class="text-end table-secondary" colspan="5"> 최종 차액 &nbsp; </th>
							<th class="text-end table-secondary"><?= number_format($filteredNetIncome) ?></th>
							<th class="text-end" colspan="4"></th>
						</tr>
					</tfoot>
				</table>
			</div>
		</div>
	</div>
</div>
	
<div class="container-fluid">
	<div id="excludeModal" class="modal">
		<div class="modal-content" style="width:400px;">
			<div class="modal-header">
				<span class="modal-title">항목 제외</span>
				<span class="close">&times;</span>
			</div>
			<div class="modal-body">
				<p><H4> 이 항목을 제외하시겠습니까? </H4></p>
				<button id="excludeConfirmBtn" class="btn btn-danger">제외</button>
			</div>
		</div>
	</div>
</div>

<div id="excludedListModal" class="modal">
<div class="modal-content" style="width: 600px;">
	<div class="modal-header">
		<span class="modal-title">수입제외목록</span>
		<span class="close" onclick="$('#excludedListModal').hide();">&times;</span>
	</div>
	<div class="modal-body custom-modal-body">
		<table class="table table-striped" id="excludedListTable">
			<thead>
				<tr>
					<th>연월</th>
					<th>거래처명</th>
					<th>제외금액</th>
					<th>복구</th>
				</tr>
			</thead>
			<tbody>
			</tbody>
		</table>
	</div>
</div>
</div>
</form>
<script>
	let isSaving = false;
	var ajaxRequest = null;

	// 페이지 로딩
	$(document).ready(function() {
		var loader = document.getElementById('loadingOverlay');
		if(loader) loader.style.display = 'none';

		$("#expenditureBtn").on("click", function() {
			loadForm('insert', null, '<?= $accountPlanTable ?>');
		});
		$("#newInBtn").on("click", function() {
			loadForm('insert', null, '<?= $accountPlanTable ?>_in'); // 수입부분 등록
		});
	});

	/*
	 * 폼을 로드하여 모달 창에 표시합니다.
	 *
	 * @param {string} mode 'insert' 또는 'update' 모드
	 * @param {number|null} num 수정할 레코드의 번호 (mode가 'update'일 때 사용)
	 * @param {string} tablename 데이터베이스 테이블 이름
	 */
	function loadForm(mode, num = null, Selecttablename = '') {
		console.log(num);

		if (mode == 'update' && (num == '' || num == null))
			return // 번호가 없고 수정인 경우는 리턴

		if (num == null) {
			$("#mode").val('insert');
		} else {
			$("#mode").val('update');
			$("#num").val(num);
		}

		if (ajaxRequest !== null) {
			ajaxRequest.abort();
		}

		// 수입, 지출 테이블 구분
		var url = (Selecttablename == '<?= $accountPlanTable ?>') ? "fetch_modal.php" : "fetch_in.php";

		ajaxRequest = $.ajax({
			type: "POST",
			url: url,
			data: {
				mode: mode,
				num: num,
				tablename: Selecttablename // tablename 추가
			},
			dataType: "html",
			success: function(response) {
				document.querySelector(".modal-body .custom-card").innerHTML = response;

				$("#myModal").show();

				$(document).on("click", "#closeBtn", function() {
					$("#myModal").hide();
				});

				$(document).on("click", "#saveBtn", function() {
					if (isSaving) return; // 중복 저장 방지
					isSaving = true;

					if (ajaxRequest !== null) {
						ajaxRequest.abort();
					}
					ajaxRequest = $.ajax({
						url: "/account_plan/insert.php",
						type: "post",
						data: {
							mode: $("#mode").val(),
							num: $("#num").val(),
							update_log: $("#update_log").val(),
							registDate: $("#registDate").val(),
							inoutsep: $("input[name='inoutsep']:checked").val(),
							content: $("#content").val(),
							amount: $("#amount").val(),
							memo: $("#memo").val(),
							first_writer: $("#first_writer").val(),
							content_detail: $("#content_detail").val(),
							ForeDate: $("#ForeDate").val(),
							secondordnum: $("#secondordnum").val(),
							eworksNum: $("#eworksNum").val(),
							workDone: $("#workDone").val(),	
							approvalRequest: $("#approvalRequest").val(),
							tablename: Selecttablename // tablename 추가
						},
						dataType: "json",
						success: function(response) {
							Toastify({
								text: "저장 완료",
								duration: 3000,
								close: true,
								gravity: "top",
								position: "center",
								backgroundColor: "#4fbe87",
							}).showToast();
							setTimeout(function() {
								$("#myModal").hide();
								location.reload();
							}, 1500);
						},
						error: function(jqxhr, status, error) {
							console.log("AJAX Error: ", status, error);
						},
						complete: function() {
							isSaving = false; // 저장 완료 후 중복 방지 해제
						}
					});
				});

				$(document).on("click", "#deleteBtn", function() {
					var level = '<?= $_SESSION["level"] ?>';

					if (level !== '1') {
						Swal.fire({
							title: '삭제불가',
							text: "관리자만 삭제 가능합니다.",
							icon: 'error',
							confirmButtonText: '확인'
						});
						return;
					}

					Swal.fire({
						title: '자료 삭제',
						text: "삭제는 신중! 정말 삭제하시겠습니까?",
						icon: 'warning',
						showCancelButton: true,
						confirmButtonColor: '#3085d6',
						cancelButtonColor: '#d33',
						confirmButtonText: '삭제',
						cancelButtonText: '취소'
					}).then((result) => {
						if (result.isConfirmed) {
							$("#mode").val('delete');
							var formData = $("#board_form").serialize();
							formData += '&tablename=' + Selecttablename; // tablename 추가

							$.ajax({
								url: "/account_plan/insert.php",
								type: "post",
								data: formData,
								success: function(response) {
									Toastify({
										text: "삭제 완료",
										duration: 2000,
										close: true,
										gravity: "top",
										position: "center",
										backgroundColor: "#4fbe87",
									}).showToast();

									$("#myModal").hide();
									location.reload();
								},
								error: function(jqxhr, status, error) {
									console.log(jqxhr, status, error);
								}
							});
						}
					});
				});

				$(".close").on("click", function() {
					$("#myModal").hide();
				});

			},
			error: function(jqxhr, status, error) {
				console.log("AJAX error in loadForm:", status, error);
			}
		});
	}

	/**
	 * 전화번호부 팝업 창을 엽니다.
	 *
	 * @param {string} searchfield 검색 필드 ID
	 */
	function phonebookBtn(searchfield) {
		var search = $("#" + searchfield).val();
		href = '../phonebook/list.php?returnID=수입등록&search=' + search;
		popupCenter(href, '전화번호 검색', 1600, 800);
	}

	// 기존 loadDetails 함수 유지
	function loadDetails() {
		const year = document.getElementById('year').value;
		const startMonth = document.getElementById('startMonth').value;
		const endMonth = document.getElementById('endMonth').value;

		window.location.href = `list.php?year=${year}&startMonth=${startMonth}&endMonth=${endMonth}`;
	}

	/**
	 * 테이블 데이터를 CSV 파일로 다운로드합니다.
	 */
	document.getElementById("csvDownload").addEventListener("click", function() {
		const table = document.getElementById("detailTable");
		const theadRow = table.querySelector("thead tr");
		const rows = table.querySelectorAll("tbody tr");
		const tfootRow = table.querySelectorAll("tfoot tr");

		const csvRows = [];

		// Include the header row
		const headerData = [];
		theadRow.querySelectorAll("th").forEach(function(cell) {
			headerData.push(cell.textContent);
		});
		csvRows.push(headerData.join(","));

		// Include the data rows
		rows.forEach(function(row) {
			const rowData = [];
			row.querySelectorAll("td").forEach(function(cell) {
				// Remove commas from numeric values
				const cleanValue = cell.textContent.replace(/,/g, "");
				rowData.push(cleanValue);
			});
			csvRows.push(rowData.join(","));
		});

		// Include the data rows
		tfootRow.forEach(function(row) {
			const rowData = [];
			row.querySelectorAll("th").forEach(function(cell) {
				// Remove commas from numeric values
				const cleanValue = cell.textContent.replace(/,/g, "");
				rowData.push(cleanValue);
			});
			csvRows.push(rowData.join(","));
		});

		const csvContent = csvRows.join("\n");
		// Add BOM for UTF-8 encoding to fix Korean characters
		const blob = new Blob(['\ufeff' + csvContent], {
			type: "text/csv;charset=utf-8;"
		});
		const link = document.createElement("a");
		link.href = URL.createObjectURL(blob);
		link.setAttribute("download", "월별_수입지출_예상내역서.csv");
		document.body.appendChild(link);
		link.click();
	});
	
	

// tr 클릭 이벤트 핸들러
$(document).on("click", ".income-row", function() {
let yearMonth = $(this).data("year-month");
let customerName = $(this).data("customer-name");
let amount = $(this).data("amount");

// data- 속성에서 값을 가져올 때, 해당 속성이 없으면 undefined가 반환되므로,
// 이 경우를 대비하여 기본값을 설정해주는 것이 좋습니다.
yearMonth = yearMonth || ''; // 빈 문자열 또는 원하는 기본값
customerName = customerName || ''; // 빈 문자열 또는 원하는 기본값
amount = amount || 0; // 0 또는 원하는 기본값

$("#excludeConfirmBtn").data("year-month", yearMonth);
$("#excludeConfirmBtn").data("customer-name", customerName);
$("#excludeConfirmBtn").data("amount", amount);

$("#excludeModal").show();
});

// 제외 버튼 클릭 이벤트 핸들러
$(document).on("click", "#excludeConfirmBtn", function() {
let yearMonth = $(this).data("year-month");
let customerName = $(this).data("customer-name");
let amount = $(this).data("amount");

$.ajax({
	url: "/account_plan/exclude_item.php",
	type: "post",
	data: {
		yearMonth: yearMonth,
		customerName: customerName,
		amount: amount
	},
	dataType: "json",
	success: function(response) {
		if (response.success) {
			Toastify({
				text: "항목이 제외되었습니다.",
				duration: 3000,
				close: true,
				gravity: "top",
				position: "center",
				backgroundColor: "#4fbe87",
			}).showToast();

			// 화면에서 해당 tr 요소 제거
			// $(`.income-row[data-year-month='${yearMonth}'][data-customer-name='${customerName}'][data-amount='${amount}']`).remove();
			
			location.reload();

			$("#excludeModal").hide();
		} else {
			Toastify({
				text: "오류가 발생했습니다.",
				duration: 3000,
				close: true,
				gravity: "top",
				position: "center",
				backgroundColor: "#ff0000",
			}).showToast();
		}
	},
	error: function(jqxhr, status, error) {
		console.log("AJAX Error: ", status, error);
		Toastify({
			text: "서버와의 통신 중 오류가 발생했습니다.",
			duration: 3000,
			close: true,
			gravity: "top",
			position: "center",
			backgroundColor: "#ff0000",
		}).showToast();
	}
});
});

// 모달 닫기 버튼 이벤트
$(".close").on("click", function() {
$("#excludeModal").hide();
});
	

// "수입제외목록" 버튼 클릭 이벤트 핸들러
$(document).on("click", "#excludedListBtn", function() {
	loadExcludedItems();
	$("#excludedListModal").show();
});


function loadExcludedItems() {
$.ajax({
	url: "/account_plan/load_excluded_items.php",
	type: "get",
	dataType: "html",
	success: function(response) {
		$("#excludedListTable tbody").html(response);

		// 복구 버튼 이벤트 핸들러 추가 (loadExcludedItems 함수 내부)
		$(".restore-btn").on("click", function() {
			let yearMonth = $(this).data("year-month");
			let customerName = $(this).data("customer-name");
			let amount = $(this).data("amount");

			if (confirm("이 항목을 복구하시겠습니까?")) {
				$.ajax({
					url: "/account_plan/restore_item.php",
					type: "post",
					data: {
						yearMonth: yearMonth,
						customerName: customerName,
						amount: amount
					},
					dataType: "json",
					success: function(response) {
						if (response.success) {
							Toastify({
								text: "항목이 복구되었습니다.",
								duration: 3000,
								close: true,
								gravity: "top",
								position: "center",
								backgroundColor: "#4fbe87",
							}).showToast();

							// 복구 후 목록 다시 로드
							loadExcludedItems();
							// 복구 후에 페이지 새로 고침
							location.reload();
						} else {
							Toastify({
								text: "오류가 발생했습니다.",
								duration: 3000,
								close: true,
								gravity: "top",
								position: "center",
								backgroundColor: "#ff0000",
							}).showToast();
						}
					},
					error: function(jqxhr, status, error) {
						console.log("AJAX Error: ", status, error);
						Toastify({
							text: "서버와의 통신 중 오류가 발생했습니다.",
							duration: 3000,
							close: true,
							gravity: "top",
							position: "center",
							backgroundColor: "#ff0000",
						}).showToast();
					}
				});
			}
		});
	},
	error: function(jqxhr, status, error) {
		console.log("AJAX Error: ", status, error);
		$("#excludedListTable tbody").html("<tr><td colspan='4'>목록을 불러오는 데 실패했습니다.</td></tr>");
	}
});
}

$(document).ready(function(){
	saveLogData('월별 수입지출 내역서'); 
	
	// 전체 선택/해제 기능
	$("#selectAllCheckbox").on("click", function() {
		var isChecked = $(this).hasClass("selected");
		
		if (isChecked) {
			// 전체 해제 (보이는 행만)
			$(".select-row:visible").prop("checked", false);
			$(this).removeClass("selected").text(" ☑ ");
		} else {
			// 전체 선택 (보이는 행만)
			$(".select-row:visible").prop("checked", true);
			$(this).addClass("selected").text(" ☒ ");
		}
	});
	
	// 개별 체크박스 변경 시 전체 선택 상태 업데이트
	$(document).on("change", ".select-row", function() {
		updateSelectAllCheckbox();
	});
	
	// 결재완료 제외 체크박스 이벤트
	$("#excludeCompleted").on("change", function() {
		filterCompletedRows();
	});
	
	// 페이지 로드 시 초기 필터링 적용
	filterCompletedRows();
});

// 결재완료 제외 필터링 함수
function filterCompletedRows() {
	var excludeCompleted = $("#excludeCompleted").is(":checked");
	
	// 원본 데이터 저장 (처음 한 번만)
	if (!window.originalTableData) {
		window.originalTableData = [];
		$("#detailTable tbody tr").each(function() {
			var $row = $(this);
			var $firstTd = $row.find('td').first();
			
			window.originalTableData.push({
				html: $row.prop('outerHTML'),
				isSubtotal: $firstTd.attr('colspan') === '4', // 소계 행은 첫 번째 td에 colspan="4"가 있음
				hasStatus: $row.find('td').eq(8).length > 0 && $row.find('td').eq(8).text().trim() !== '', // 결재상태 컬럼이 있고 내용이 있는지 확인
				date: $row.find('td').eq(3).text().trim(), // 예상지급일 (소계 계산용)
				amount: $row.find('td').eq(5).text().trim() // 금액 (소계 계산용)
			});
		});
	}
	
	// 테이블 내용 초기화
	var $tbody = $("#detailTable tbody");
	$tbody.empty();
	
	// 필터링된 데이터 수집
	var filteredRows = [];
	
	window.originalTableData.forEach(function(rowData) {
		if (rowData.isSubtotal) {
			// 소계 행은 건너뛰고 나중에 새로 계산
			return;
		} else if (rowData.hasStatus) {
			// 결재상태가 있는 행만 필터링 적용
			var $tempRow = $(rowData.html);
			var statusText = $tempRow.find("td").eq(8).text().trim();
			
			if (!excludeCompleted || statusText !== "완료") {
				filteredRows.push(rowData);
			}
		} else {
			// 결재상태가 없는 행은 항상 표시
			filteredRows.push(rowData);
		}
	});
	
	// 필터링된 데이터를 날짜별로 정렬하여 처리
	var processedRows = [];
	
	// 날짜가 있는 행들과 없는 행들을 분리
	var rowsWithDate = [];
	var rowsWithoutDate = [];
	
	filteredRows.forEach(function(rowData) {
		if (rowData.date && rowData.date !== '' && rowData.date !== '0000-00-00') {
			rowsWithDate.push(rowData);
		} else {
			rowsWithoutDate.push(rowData);
		}
	});
	
	// 날짜가 있는 행들을 날짜순으로 정렬
	rowsWithDate.sort(function(a, b) {
		return new Date(a.date) - new Date(b.date);
	});
	
	// 날짜별로 그룹화하여 처리
	var currentDate = '';
	var currentDateRows = [];
	
	rowsWithDate.forEach(function(rowData) {
		if (currentDate !== rowData.date) {
			// 이전 날짜의 행들과 소계 처리
			if (currentDateRows.length > 0) {
				// 이전 날짜의 행들 추가
				currentDateRows.forEach(function(prevRowData) {
					var $tempRow = $(prevRowData.html);
					processedRows.push($tempRow);
				});
				
				// 이전 날짜의 소계 추가
				var subtotalAmount = calculateSubtotalForDate(currentDate, currentDateRows);
				if (subtotalAmount > 0) {
					var subtotalRow = createSubtotalRow(currentDate, subtotalAmount);
					processedRows.push(subtotalRow);
				}
			}
			
			// 새로운 날짜 시작
			currentDate = rowData.date;
			currentDateRows = [rowData];
		} else {
			// 같은 날짜의 행 추가
			currentDateRows.push(rowData);
		}
	});
	
	// 마지막 날짜의 행들과 소계 처리
	if (currentDateRows.length > 0) {
		currentDateRows.forEach(function(rowData) {
			var $tempRow = $(rowData.html);
			processedRows.push($tempRow);
		});
		
		var subtotalAmount = calculateSubtotalForDate(currentDate, currentDateRows);
		if (subtotalAmount > 0) {
			var subtotalRow = createSubtotalRow(currentDate, subtotalAmount);
			processedRows.push(subtotalRow);
		}
	}
	
	// 날짜가 없는 행들 추가 (수입 행들)
	rowsWithoutDate.forEach(function(rowData) {
		var $tempRow = $(rowData.html);
		processedRows.push($tempRow);
	});
	
	// 최종 테이블에 추가
	processedRows.forEach(function($row) {
		$tbody.append($row);
	});
	
	// 전체 선택 체크박스 상태 업데이트
	updateSelectAllCheckbox();
}

// 특정 날짜의 소계 계산 함수
function calculateSubtotalForDate(date, rows) {
	var total = 0;
	rows.forEach(function(rowData) {
		var amountText = rowData.amount.replace(/,/g, '');
		var amount = parseFloat(amountText) || 0;
		total += amount;
	});
	return total;
}

// 소계 행 생성 함수
function createSubtotalRow(date, amount) {
	// 날짜 형식 파싱 개선 (YYYY-MM-DD 형식)
	var dateParts = date.split('-');
	var year = parseInt(dateParts[0]);
	var month = parseInt(dateParts[1]);
	var day = parseInt(dateParts[2]);
	
	// 날짜 유효성 검사
	if (isNaN(year) || isNaN(month) || isNaN(day)) {
		console.warn('Invalid date format:', date);
		return $('<tr></tr>'); // 빈 행 반환
	}
	
	var subtotalHtml = '<tr>' +
		'<td colspan="4"></td>' +
		'<td class="text-end fw-bold table-secondary">' + month + '/' + day + ' 소계</td>' +
		'<td class="text-end text-danger fw-bold table-secondary">' + amount.toLocaleString() + '</td>' +
		'<td></td>' +
		'</tr>';
	
	return $(subtotalHtml);
}

// 전체 선택 체크박스 상태 업데이트 함수
function updateSelectAllCheckbox() {
	var visibleCheckboxes = $(".select-row:visible").length;
	var checkedVisibleCheckboxes = $(".select-row:visible:checked").length;
	
	if (checkedVisibleCheckboxes === 0) {
		$("#selectAllCheckbox").removeClass("selected").text(" ☑ ");
	} else if (checkedVisibleCheckboxes === visibleCheckboxes) {
		$("#selectAllCheckbox").addClass("selected").text(" ☒ ");
	} else {
		$("#selectAllCheckbox").removeClass("selected").text(" ☑ ");
	}
}
</script>

<script>
$(function(){

// 1) 컬럼 정의
const columns = [
  { id: 'registDate_bulk', label: '등록일자',   type: 'date',  width: 130, align: 'center' },
  { id: 'inoutsep_bulk',   label: '구분',       type: 'text',  width: 80,  align: 'center', value: '지출' },
  { id: 'content_bulk',    label: '내역',       type: 'text',  width: 220, align: 'left' },
  { id: 'amount_bulk',     label: '금액',       type: 'text',  width: 150, align: 'right', function: inputNumberFormat },
  { id: 'ForeDate_bulk',   label: '예상지급일', type: 'date',  width: 130, align: 'center' },
  { id: 'memo_bulk',       label: '비고',       type: 'text',  width: 220, align: 'left' }
];


// 1) 저장 콜백 함수 정의
function saveBulk(entries) {
  if (!entries.length) {
    return Swal.fire('입력 없음', '저장할 데이터가 없습니다.', 'info');
  }
  console.log(entries);
  Swal.fire({
    title: '전체 저장',
    text: `총 ${entries.length}건을 저장하시겠습니까?`,
    icon: 'question',
    showCancelButton: true,
    confirmButtonText: '저장',
    cancelButtonText: '취소'
  }).then(result => {
    if (!result.isConfirmed) return;

    // AJAX 요청
    $.ajax({
	  url: '/account_plan/copy_to_next_month.php', 
      type: 'POST',
      data: JSON.stringify({ entries }),     // { entries: [ {registDate, ...}, ... ] }
      contentType: 'application/json; charset=utf-8',
      dataType: 'json'
    })
    .done(res => {
      if (res.status === 'success') {
        const count = res.insertedCount ?? entries.length;
        Swal.fire({
          icon: 'success',
          title: `${count}건 저장 완료`,
          showConfirmButton: false,
          timer: 1500
        }).then(() => location.reload());
      } else {
        Swal.fire('저장 실패', res.message || '오류가 발생했습니다.', 'error');
      }
    })
    .fail((xhr, status, err) => {
      console.error('Bulk insert AJAX Error:', status, err);
      Swal.fire('서버 오류', '서버와의 통신 중 오류가 발생했습니다.', 'error');
    });
  });
}

// 3) 버튼 클릭 시 모달 열기
// 대량등록 모달 열기 + 선택된 행 데이터 전달
$('#bulkNewBtn').on('click', function() {
  const items = [];

  // 체크된 각 행에서 데이터 추출
  $('.select-row:checked').each(function() {
    const $tr = $(this).closest('tr');
    // 1) 현재 예상지급일
    const currentDate = $tr.find('td').eq(3).text().trim();

    // 2) 다음달 날짜 계산
    let nextMonthDate = '';
    if (currentDate) {
      const parts = currentDate.split('-');
      if (parts.length === 3) {
        let [year, month, day] = parts.map(Number);
        month++;
        if (month > 12) {
          month = 1;
          year++;
        }
        nextMonthDate =
          year + '-' +
          String(month).padStart(2, '0') + '-' +
          String(day).padStart(2, '0');
      }
    }

    // 3) 객체에 담기 (컬럼 정의에 맞춰 키 이름 _bulk 포함)
    items.push({
      registDate_bulk: currentDate,
      inoutsep_bulk:   '지출',            // 구분
      content_bulk:    $tr.find('td').eq(4).text().trim(),   // 내역
      amount_bulk:     $tr.find('td').eq(5).text().trim(),   // 금액
      ForeDate_bulk:   nextMonthDate,
      memo_bulk:       $tr.find('td').eq(9).text().replace(/,/g, '')  // 비고
    });
  });

  // 선택 없으면 경고
  if (!items.length) {
    return Swal.fire('선택 없음', '하나 이상 선택해 주세요.', 'warning');
  }

  // 모달 띄우기 (폭·여백 옵션과 초기 데이터 전달)
  BulkModal.open(
    columns,
    saveBulk,
    { width: 1400, maxWidth: '90vw', margin: '30px auto' },
    items
  );
});


  $('#approvalRequestBtn').on('click', function(){
    var items = [];

    // 체크된 각 행에서 필요한 값 수집
    $('.select-row:checked').each(function(){
      var $tr = $(this).closest('tr');
      items.push({
        num: $(this).data('num'),                                  // 고유번호
        payDate: $tr.find('td').eq(3).text().trim(),                // 예상지급일 (4번째 td)
        content: $tr.find('td').eq(4).text().trim(),                // 항목 (5번째 td)
        amount: parseFloat(                                        // 금액 (6번째 td)
          $tr.find('td').eq(5).text().replace(/,/g, '')
        ) || 0
      });
    });

    if (items.length === 0) {
      alert('하나 이상 선택해 주세요.');
      return;
    }

	console.log(JSON.stringify(items)	);
    // JSON 형태로 AJAX 요청
    $.ajax({
      url: '/account_plan/eworks_process.php', 
      type: 'POST',
      data: JSON.stringify({ items: items }),
      contentType: 'application/json; charset=utf-8',
      dataType: 'json'
    })
    .done(function(res){
      if (res.success) {
        Swal.fire({
            icon: 'success',
            title: '결재 요청이 전송되었습니다.',
            showConfirmButton: false,
            timer: 1000
        }).then(() => {
            location.reload();
        });
      } else {
        alert('결재 요청 실패: ' + res.message);
      }
    })
    .fail(function(xhr, status, err){
      console.error('AJAX Error:', status, err);
      alert('서버 오류가 발생했습니다.');
    });
  });

  // 선택항목 다음달로 복제 기능
  function copyNextMonth(){

    var items = [];

    // 체크된 각 행에서 필요한 값 수집
    $('.select-row:checked').each(function(){
      var $tr = $(this).closest('tr');
      var currentDate = $tr.find('td').eq(3).text().trim(); // 현재 예상지급일
      
      // 다음달 날짜 계산
      var nextMonthDate = '';
      if (currentDate && currentDate !== '') {
        var dateParts = currentDate.split('-');
        if (dateParts.length === 3) {
          var year = parseInt(dateParts[0]);
          var month = parseInt(dateParts[1]);
          var day = parseInt(dateParts[2]);
          
          // 다음달 계산
          month++;
          if (month > 12) {
            month = 1;
            year++;
          }
          
          // 날짜 형식 맞추기 (YYYY-MM-DD)
          nextMonthDate = year + '-' + 
                         (month < 10 ? '0' + month : month) + '-' + 
                         (day < 10 ? '0' + day : day);
        }
      }

      items.push({
        num: $(this).data('num'),                                  // 고유번호
        payDate: currentDate,                                      // 현재 예상지급일
        nextMonthDate: nextMonthDate,                              // 다음달 예상지급일
        content: $tr.find('td').eq(4).text().trim(),                // 항목 (5번째 td)
        amount: parseFloat(                                        // 금액 (6번째 td)
          $tr.find('td').eq(5).text().replace(/,/g, '')
        ) || 0
      });
    });

    if (items.length === 0) {
      alert('하나 이상 선택해 주세요.');
      return;
    }
    // 확인 다이얼로그
    Swal.fire({
      title: '다음달로 복제',
      text: `선택된 ${items.length}개 항목을 다음달로 복제하시겠습니까?`,
      icon: 'question',
      showCancelButton: true,
      confirmButtonColor: '#3085d6',
      cancelButtonColor: '#d33',
      confirmButtonText: '복제',
      cancelButtonText: '취소'
    }).then((result) => {
      if (result.isConfirmed) {
        // JSON 형태로 AJAX 요청
        $.ajax({
          url: '/account_plan/copy_to_next_month.php', 
          type: 'POST',
          data: JSON.stringify({ items: items }),
          contentType: 'application/json; charset=utf-8',
          dataType: 'json'
        })
        .done(function(res){
          console.log('Response received:', res); // 디버깅용 로그 추가
          
          if (res.success) {
            var copiedCount = res.copiedCount || 0; // 기본값 설정
            Swal.fire({
                icon: 'success',
                title: '복제가 완료되었습니다.',
                text: `${copiedCount}개 항목이 다음달로 복제되었습니다.`,
                showConfirmButton: false,
                timer: 2000
            }).then(() => {
                location.reload();
            });
          } else {
            Swal.fire({
                icon: 'error',
                title: '복제 실패',
                text: res.message || '복제 중 오류가 발생했습니다.'
            });
          }
        })
        .fail(function(xhr, status, err){
          console.error('AJAX Error:', status, err);
          Swal.fire({
              icon: 'error',
              title: '서버 오류',
              text: '서버와의 통신 중 오류가 발생했습니다.'
          });
        });
      }
    });
  }


});
</script>

</body>
</html>