Files
sam-kd/account_juil/list_daily.php
kent 0716754bf5 fix(mysql8): MySQL 8.0 Strict Mode DATE 필드 호환성 수정
MySQL 8.0의 Strict Mode에서 DATE 컬럼에 빈 문자열('')을 허용하지 않는
문제를 해결하기 위해 여러 파일 수정

📁 수정된 파일:
- output/_request.php: DATE 필드 빈 문자열을 NULL로 변환
- output/insert_iList.php: ACIaskDate, ACIdoneDate NULL 처리
- output/_row.php: eList_screen, eList_slat 변수 추가
- output/list_document.php: DATE 비교 조건에서 != '' 제거
- output/list_document_except.php: DATE 비교 조건에서 != '' 제거
- output/list_QCsales.php: ACIdoneDate != '' 조건 제거
- account_juil/list_daily.php: dueDate != '' 조건 제거

🐛 해결된 오류:
- SQLSTATE[HY000]: General error: 1525 Incorrect DATE value: ''
- Internal Server Error (undefined variables)

🔧 변경 내용:
- 날짜 필드 입력 시 빈 문자열 → NULL 변환
- SQL WHERE 절에서 DATE != '' 비교 → IS NOT NULL 비교로 변경
- MySQL 8.0 STRICT_TRANS_TABLES, NO_ZERO_DATE 모드 호환

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-13 13:23:41 +09:00

476 lines
23 KiB
PHP

<?php
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);
include $_SERVER['DOCUMENT_ROOT'] . '/load_header.php';
$title_message = '일일 일보';
?>
<link href="css/style.css" rel="stylesheet">
<title> <?=$title_message?> </title>
<style>
/* 테이블에 테두리 추가 */
.detail-table th, .detail-table td {
border: 1px solid black;
border-collapse: collapse;
}
/* 테이블 셀 패딩 조정 */
.detail-table th, .detail-table td {
padding: 4px;
text-align: center;
font-size: 0.9em;
}
</style>
</head>
<body>
<?php
if($user_id === '0266771300' ) {
require_once($_SERVER['DOCUMENT_ROOT'] . '/myheader_accountant1.php'); // 경리
} else {
require_once($_SERVER['DOCUMENT_ROOT'] . '/myheader1.php');
}
$fromdate = isset($_REQUEST['fromdate']) ? $_REQUEST['fromdate'] : '';
$todate = isset($_REQUEST['todate']) ? $_REQUEST['todate'] : '';
// 날짜 기본값 설정: 당월 1일 ~ 오늘
if (empty($fromdate) || empty($todate)) {
$fromdate = date("2025-06-01");
$todate = date("Y-m-d");
}
$tablename = 'account_juil';
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
// 1. 계좌 목록 로드
$jsonFile = $_SERVER['DOCUMENT_ROOT'] . "/account_juil/accoutlist.json";
$accounts = file_exists($jsonFile) ? json_decode(file_get_contents($jsonFile), true) : [];
$accountNames = [];
if (is_array($accounts)) {
foreach ($accounts as $acc) {
$accountNames[] = $acc['company'] . ' ' . $acc['number'] . ($acc['memo'] ? ' (' . $acc['memo'] . ')' : '');
}
}
// '전자어음' 계좌를 항상 추가
if (!in_array('전자어음', $accountNames)) {
$accountNames[] = '전자어음';
}
// $accountNames[] = '전자어음';
// echo '<pre>';
// print_r($accountNames);
// echo '</pre>';
// 2. 검색 시작일 이전의 계좌별 기초 잔액 계산 (전일이월의 기초값)
$runningBalances = [];
foreach ($accountNames as $bankbookName) {
$initialBalanceSql = "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' OR is_deleted IS NULL) AND registDate < :fromdate AND bankbook = :bankbook ";
//AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')";
$initialStmh = $pdo->prepare($initialBalanceSql);
$initialStmh->execute([':fromdate' => $fromdate, ':bankbook' => $bankbookName]);
$result = $initialStmh->fetch(PDO::FETCH_ASSOC);
$runningBalances[$bankbookName] = $result['balance'] ?? 0;
}
// 3. 기간 내 모든 현금성 거래내역 한번에 조회 후 날짜별로 그룹화
$allTransactionsSql = "SELECT * FROM $tablename WHERE registDate BETWEEN :fromdate AND :todate AND (is_deleted = 0 OR is_deleted IS NULL)
ORDER BY registDate ASC, num ASC";
// AND content != '외상매출채권(전자어음)'
// AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')
$allTransactionsStmh = $pdo->prepare($allTransactionsSql);
$allTransactionsStmh->execute([':fromdate' => $fromdate, ':todate' => $todate]);
$allTransactions = $allTransactionsStmh->fetchAll(PDO::FETCH_ASSOC);
$dataByDate = [];
foreach ($allTransactions as $tx) {
$dataByDate[$tx['registDate']][] = $tx;
}
// 4. 외상매출채권(전자어음) 잔액 계산 - 배서일자 기준으로 수입/지출 구분
$notesReceivableSql = "SELECT
SUBSTRING(
content_detail,
LOCATE('(', content_detail) + 1,
LOCATE(')', content_detail) - LOCATE('(', content_detail) - 1
) AS bill_no,
MIN(content_detail) as content_detail,
MIN(registDate) as issue_date,
MIN(dueDate) as due_date,
SUM(
CASE
WHEN (endorsementDate IS NULL OR endorsementDate = '0000-00-00' OR endorsementDate = '')
THEN REPLACE(amount, ',', '')
ELSE -REPLACE(amount, ',', '')
END
) as outstanding_balance
FROM $tablename
WHERE (dueDate IS NOT NULL)
AND (is_deleted IS NULL OR is_deleted = 0)
AND bankbook = '전자어음'
GROUP BY bill_no
HAVING outstanding_balance > 0
ORDER BY due_date ASC";
$notesStmh = $pdo->query($notesReceivableSql);
$notesReceivable = $notesStmh->fetchAll(PDO::FETCH_ASSOC);
// // 디버그: 전자어음 수입/지출 상세 데이터 확인
// $debugDetailSql = "SELECT
// content_detail,
// registDate,
// dueDate,
// endorsementDate,
// amount,
// inoutsep,
// bankbook,
// CASE
// WHEN (endorsementDate IS NULL OR endorsementDate = '0000-00-00' OR endorsementDate = '') THEN '수입'
// ELSE '지출'
// END as calculated_type,
// CASE
// WHEN (endorsementDate IS NULL OR endorsementDate = '0000-00-00' OR endorsementDate = '') THEN REPLACE(amount, ',', '')
// ELSE -REPLACE(amount, ',', '')
// END as calculated_amount
// FROM $tablename
// WHERE bankbook = '전자어음'
// AND (dueDate != '0000-00-00' AND dueDate IS NOT NULL AND dueDate != '')
// AND (is_deleted IS NULL OR is_deleted = 0)
// ORDER BY content_detail, registDate";
// $debugDetailStmh = $pdo->query($debugDetailSql);
// $debugDetailData = $debugDetailStmh->fetchAll(PDO::FETCH_ASSOC);
// echo '<div style="background: #f0f0f0; padding: 15px; margin: 10px; border: 1px solid #ccc;">';
// echo '<h4>디버그: 전자어음 상세 데이터</h4>';
// echo '<table border="1" style="border-collapse: collapse; width: 100%;">';
// echo '<tr style="background: #e0e0e0;">';
// echo '<th>내용</th><th>등록일</th><th>만기일</th><th>배서일자</th><th>금액</th><th>수입/지출</th><th>계산타입</th><th>계산금액</th>';
// echo '</tr>';
// foreach($debugDetailData as $row) {
// echo '<tr>';
// echo '<td>' . htmlspecialchars($row['content_detail']) . '</td>';
// echo '<td>' . $row['registDate'] . '</td>';
// echo '<td>' . $row['dueDate'] . '</td>';
// echo '<td>' . $row['endorsementDate'] . '</td>';
// echo '<td>' . $row['amount'] . '</td>';
// echo '<td>' . $row['inoutsep'] . '</td>';
// echo '<td>' . $row['calculated_type'] . '</td>';
// echo '<td>' . $row['calculated_amount'] . '</td>';
// echo '</tr>';
// }
// echo '</table>';
// echo '</div>';
// echo '<pre>';
// print_r($notesReceivable);
// echo '</pre>';
// 5. 날짜별로 모든 데이터 계산 후 배열에 저장 (메모리에서 처리)
$reportData = [];
$current = strtotime($fromdate);
$end = strtotime($todate);
while ($current <= $end) {
$currentDateStr = date('Y-m-d', $current);
$dailyTransactions = $dataByDate[$currentDateStr] ?? [];
// 거래가 있는 날만 리포트 데이터 생성
if (!empty($dailyTransactions)) {
$dailySummaries = [];
foreach ($accountNames as $bankbookName) {
$prevBalance = $runningBalances[$bankbookName];
$dailyIncome = 0;
$dailyExpense = 0;
foreach ($dailyTransactions as $tx) {
if ($tx['bankbook'] === $bankbookName) {
$amount = floatval(str_replace(',', '', $tx['amount']));
if ($tx['inoutsep'] === '지출') {
$dailyExpense += $amount;
} else {
$dailyIncome += $amount;
}
}
}
$endOfDayBalance = $prevBalance + $dailyIncome - $dailyExpense;
$dailySummaries[$bankbookName] = [
'prev' => $prevBalance,
'income' => $dailyIncome,
'expense' => $dailyExpense,
'balance' => $endOfDayBalance
];
}
$reportData[$currentDateStr] = [
'summaries' => $dailySummaries,
'transactions' => $dailyTransactions
];
}
// 전일이월액 업데이트는 거래가 없는 날도 매일 수행해야 함
foreach ($accountNames as $bankbookName) {
$dailyIncome = 0; $dailyExpense = 0;
$currentDayTx = $dataByDate[$currentDateStr] ?? [];
foreach ($currentDayTx as $tx) {
if ($tx['bankbook'] === $bankbookName) {
$amount = floatval(str_replace(',', '', $tx['amount']));
if ($tx['inoutsep'] === '지출') $dailyExpense += $amount; else $dailyIncome += $amount;
}
}
$runningBalances[$bankbookName] += ($dailyIncome - $dailyExpense);
}
$current = strtotime('+1 day', $current);
}
// 날짜 역순으로 출력하기 위해 배열 뒤집기
$reportData = array_reverse($reportData, true);
// echo '<pre>';
// print_r($reportData);
// echo '</pre>';
?>
<form id="board_form" name="board_form" method="post">
<div class="container">
<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="d-flex justify-content-center align-items-center mt-2">
<input type="date" id="fromdate" name="fromdate" class="form-control" style="width:130px;" value="<?=$fromdate?>">
<span class="mx-2">~</span>
<input type="date" id="todate" name="todate" class="form-control" style="width:130px;" value="<?=$todate?>">
<button class="btn btn-outline-dark btn-sm ms-2" type="submit"><i class="bi bi-search"></i></button>
</div>
</div>
<div class="mt-2 justify-content-center">
<h4 class="text-center alert alert-warning p-2" >어음 및 외상매출채권 현황</h4>
<div class="d-flex justify-content-center mt-2">
<table class="table table-hover table-bordered table-sm w-75">
<thead class="table-warning">
<tr>
<th style="width:55%;">내용</th>
<th style="width:15%;">현재잔액</th>
<th style="width:15%;">최초발행일</th>
<th style="width:15%;">만기일자</th>
</tr>
</thead>
<tbody>
<?php
$totalOutstandingBalance = 0; // 합계 변수 초기화
if (empty($notesReceivable)): ?>
<tr><td colspan="4">해당 내역이 없습니다.</td></tr>
<?php else: ?>
<?php foreach ($notesReceivable as $note):
$totalOutstandingBalance += $note['outstanding_balance']; // 합계 계산
?>
<tr>
<td class="text-start"><?= htmlspecialchars($note['content_detail']) ?></td>
<td class="text-end fw-bold"><?= number_format($note['outstanding_balance']) ?></td>
<td><?= htmlspecialchars($note['issue_date']) ?></td>
<td class="text-danger fw-bold"><?= htmlspecialchars($note['due_date']) ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
<tfoot class="table-warning">
<tr class="fw-bold">
<td class="text-center">합계</td>
<td class="text-end text-primary"><?= number_format($totalOutstandingBalance) ?></td>
<td></td>
<td></td>
</tr>
</tfoot>
</table>
</div>
</div>
<?php if (empty($reportData)): ?>
<div class="alert alert-warning text-center mt-4" role="alert">
해당 기간에 거래 내역이 없습니다.
</div>
<?php else: ?>
<?php foreach ($reportData as $date => $dayData): ?>
<div class="card mt-4 mb-4">
<div class="card-body">
<div class="row d-flex justify-content-center m-1 mb-2">
<?php
$formatter = new IntlDateFormatter('ko_KR', IntlDateFormatter::FULL, IntlDateFormatter::NONE, null, null, 'Y년 M월 d일 EEEE');
$formattedDate = $formatter->format(strtotime($date));
?>
<div class="alert alert-primary fs-4 text-center">
일자: <?=$formattedDate?> &nbsp; / &nbsp; 작성자 : 우지영
</div>
</div>
<div class="table-responsive d-flex justify-content-center">
<table class="table table-hover table-bordered table-sm w-75">
<thead class="table-secondary">
<tr>
<th class="text-center" style="width:10%;">은행</th>
<th class="text-center" style="width:10%;">별칭</th>
<th class="text-center" style="width:20;">계좌번호</th>
<th class="text-center" style="width:15%;">전일이월</th>
<th class="text-center" style="width:15%;">수입</th>
<th class="text-center" style="width:15%;">지출</th>
<th class="text-center" style="width:15%;">잔액</th>
</tr>
</thead>
<tbody>
<?php
$grandTotal_prev = 0; $grandTotal_income = 0; $grandTotal_expense = 0; $grandTotal_balance = 0;
foreach (array_filter($accountNames, function($name) { return $name !== '전자어음'; }) as $bankbookName):
$summary = $dayData['summaries'][$bankbookName];
$grandTotal_prev += $summary['prev'];
$grandTotal_income += $summary['income'];
$grandTotal_expense += $summary['expense'];
$grandTotal_balance += $summary['balance'];
$bankTitleName = preg_match('/(.+?)은행/', $bankbookName, $matches) ? $matches[0] : $bankbookName;
$bankAliasName = preg_match('/은행\((.*?)\)/', $bankbookName, $matches) ? (!empty($matches[1]) ? $matches[1] : '') : preg_replace('/은행.*?(?=\s*$)/', '', $bankbookName);
// $bankAliasName이 $bankTitleName에 포함되어 있으면 빈 문자열로 설정
$bankAliasName = (strpos($bankTitleName, $bankAliasName) !== false) ? '' : $bankAliasName;
$bankAccountNumber = preg_replace('/[^0-9-]/', '', $bankbookName);
?>
<tr>
<td class="text-start"><?= htmlspecialchars($bankTitleName) ?></td>
<td class="text-start"><?= htmlspecialchars($bankAliasName) ?></td>
<td class="text-start"><?= htmlspecialchars($bankAccountNumber) ?></td>
<td class="text-end"><?= number_format($summary['prev']) ?></td>
<td class="text-end"><?= number_format($summary['income']) ?></td>
<td class="text-end"><?= number_format($summary['expense']) ?></td>
<td class="text-end fw-bold"><?= number_format($summary['balance']) ?></td>
</tr>
<?php endforeach; ?>
<tr class="table-group-divider">
<td class="text-center fw-bold" colspan="3">현금성 자산 합계</td>
<td class="text-end fw-bold"><?= number_format($grandTotal_prev) ?></td>
<td class="text-end fw-bold"><?= number_format($grandTotal_income) ?></td>
<td class="text-end fw-bold"><?= number_format($grandTotal_expense) ?></td>
<td class="text-end fw-bold"><?= number_format($grandTotal_balance) ?></td>
</tr>
</tbody>
</table>
</div>
<div class="mt-4">
<h4 class="text-center alert alert-success p-2"><예금 입출금 내역></h4>
<?php
$transactionsByAccount = [];
foreach ($dayData['transactions'] as $row) {
$isNormalAccount = true;
$isElectronicBill = ($row['bankbook'] === '전자어음' || strpos($row['content'], '전자어음') !== false || strpos($row['content_detail'], '전자어음') !== false);
// 기존 계좌별 분류 + 전자어음 관련 내역도 별도 그룹으로 분류
if ($isElectronicBill) {
$transactionsByAccount['전자어음'][] = $row;
} else {
$transactionsByAccount[$row['bankbook']][] = $row;
}
}
foreach ($transactionsByAccount as $bankbookName => $transactions):
?>
<h5 class="mt-3 text-primary-emphasis"><?= htmlspecialchars($bankbookName) ?></h5>
<div class="table-responsive d-flex justify-content-center">
<table class="table table-bordered detail-table w-75">
<thead class="table-group-divider">
<tr>
<th style="width:35%;">입금내역</th>
<th style="width:15%;">금액</th>
<th style="width:35%;">출금내역</th>
<th style="width:15%;">금액</th>
</tr>
</thead>
<tbody>
<?php
$incomeRows = array_filter($transactions, function($tx) { return $tx['inoutsep'] !== '지출'; });
$expenseRows = array_filter($transactions, function($tx) { return $tx['inoutsep'] === '지출'; });
$maxRows = max(count($incomeRows), count($expenseRows));
$dailyIncomeTotal = 0; $dailyExpenseTotal = 0;
$incomeRows = array_values($incomeRows); $expenseRows = array_values($expenseRows);
for ($i = 0; $i < $maxRows; $i++):
?>
<tr>
<?php if (isset($incomeRows[$i])):
$item = $incomeRows[$i];
$amount = floatval(str_replace(',', '', $item['amount']));
$dailyIncomeTotal += $amount;
?>
<td class="text-start"><?= htmlspecialchars($item['content_detail'] ? $item['content_detail'] : "") ?></td>
<td class="text-end"><?= number_format($amount) ?></td>
<?php else: ?>
<td></td><td></td>
<?php endif; ?>
<?php if (isset($expenseRows[$i])):
$item = $expenseRows[$i];
$amount = floatval(str_replace(',', '', $item['amount']));
$dailyExpenseTotal += $amount;
?>
<td class="text-start"><?= htmlspecialchars($item['content_detail'] ? $item['content_detail'] : "") ?></td>
<td class="text-end"><?= number_format($amount) ?></td>
<?php else: ?>
<td></td><td></td>
<?php endif; ?>
</tr>
<?php endfor; ?>
</tbody>
<tfoot class="table-group-divider">
<tr class="fw-bold">
<td>입금 합계</td>
<td class="text-end text-primary"><?= number_format($dailyIncomeTotal) ?></td>
<td>출금 합계</td>
<td class="text-end text-danger"><?= number_format($dailyExpenseTotal) ?></td>
</tr>
</tfoot>
</table>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
</form>
<script>
document.addEventListener('DOMContentLoaded', function() {
var loader = document.getElementById('loadingOverlay');
if(loader) {
loader.style.display = 'none';
}
if (typeof saveLogData === 'function') {
saveLogData('주일기업 일일 일보');
}
});
</script>
</body>
</html>