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; } } ?> <?= $title_message ?> 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 '
';
// print_r($paymentData);
// echo '
'; // 수금된 금액을 차감한 나머지 미수금 계산 $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 '
--- 제외된 항목 ($excludedItems) ---';
// print_r($excludedItems);
// echo '
'; // $filteredIncomeData에서 제외된 항목 필터링 $filteredIncomeDataForDebugging = $filteredIncomeData; // 디버깅을 위해 원본 배열 복사 if (!empty($excludedItems)) { $filteredIncomeData = array_filter($filteredIncomeData, function ($item) use ($excludedItems, $selectedYearMonth) { // 디버깅을 위한 코드 추가 // echo '
--- 현재 비교 중인 항목 ($item) ---';
		// print_r($item);
		// echo '
'; $isExcluded = false; // 제외 여부 플래그 foreach ($excludedItems as $excludedItem) { // 디버깅을 위한 코드 추가 // echo '
--- 제외된 항목과 비교 ($excludedItem) ---';
			// print_r($excludedItem);
			// echo '--- 비교 결과 ---';
			// echo '$excludedItem[\'yearMonth\'] === $selectedYearMonth : ' . ($excludedItem['yearMonth'] === $selectedYearMonth ? 'true' : 'false') . '
'; // echo '$excludedItem[\'customerName\'] === $item[\'customer_name\'] : ' . ($excludedItem['customerName'] === $item['customer_name'] ? 'true' : 'false') . '
'; // echo 'intval($excludedItem[\'amount\']) === intval($item[\'totalAmount\']) : ' . (intval($excludedItem['amount']) === intval($item['totalAmount']) ? 'true' : 'false') . '
'; // echo '
'; if ( $excludedItem['yearMonth'] === $selectedYearMonth && $excludedItem['customerName'] === $item['customer_name'] && intval($excludedItem['amount']) === intval($item['totalAmount']) ) { $isExcluded = true; // 제외 플래그 설정 break; } } // 디버깅을 위한 코드 추가 // echo '
--- 최종 제외 여부: ' . ($isExcluded ? '제외됨' : '유지됨') . ' ---
'; return !$isExcluded; // 제외 여부에 따라 반환 }); } // 디버깅을 위한 코드 추가: 필터링 전후 비교 // echo '
--- 필터링 전 ($filteredIncomeDataForDebugging) ---';
// print_r($filteredIncomeDataForDebugging);
// echo '
'; // echo '
--- 필터링 후 ($filteredIncomeData) ---';
// print_r($filteredIncomeData);
// echo '
'; // ... (나머지 코드는 동일) ... // 이번 달로 설정, 계산서는 지난달 $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; }); ?>
계좌 잔액: 0): ?>
:
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 ''; echo ''; echo ''; echo ''; ?> '; // 수입 컬럼 영역 빈칸 echo ''; // 4번째 컬럼: 날짜 소계 라벨 echo ''; // 5번째 컬럼: 소계 금액 echo ''; // 6번째 컬럼: 빈칸 echo ''; echo ''; } // ↑ 소계 로직 끝 ?>
수입 지출
항목 금액
선택
예상지급일 항목 금액 전자결재요청 결재번호 결재상태 비고
' . $incomeContent . '' . ($incomeAmount > 0 ? number_format($incomeAmount) : '') . ' 0 ? number_format((float)$expenseAmount) : '' ?>
' . date('n/j', strtotime($currentDate)) . ' 소계' . number_format($sum) . '
수입 합계   지출 합계  
(계좌 잔액)
최종 차액