초기 커밋: 5130 레거시 시스템

- URL 하드코딩 → .env APP_URL 기반 동적 URL로 변경
- DB 연결 하드코딩 → .env 기반으로 변경
- MySQL strict mode DATE 오류 수정
This commit is contained in:
2025-12-10 20:14:31 +09:00
commit aca1767eb9
6728 changed files with 1863265 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
// HTML 헤더 로드
include $_SERVER['DOCUMENT_ROOT'] . '/load_header.php';
?>
<script>
var loader = document.getElementById('loadingOverlay');
if(loader) loader.style.display = 'none';
$(document).ready(function () {
// showShiningText('프로그램 개발 중입니다...', '80px');
showShiningText();
});
</script>
</body>
</html>

View File

@@ -0,0 +1,744 @@
<?php
// 거래명세표 보여주는 코드 s_transaction.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;
}
include $_SERVER['DOCUMENT_ROOT'] . '/load_header.php';
// 첫 화면 표시 문구
$title_message = '거래처 원장(VAT 포함)';
?>
<link href="css/style.css" rel="stylesheet">
<title> <?=$title_message?> </title>
<style>
/* 테이블에 테두리 추가 */
#myTable, #myTable th, #myTable td {
border: 1px solid black;
border-collapse: collapse;
}
/* 테이블 셀 패딩 조정 */
#myTable th, #myTable td {
padding: 8px;
text-align: center;
}
</style>
</head>
<body>
<?php require_once($_SERVER['DOCUMENT_ROOT'] . '/myheader1.php'); ?>
<?php
$search = isset($_REQUEST['search']) ? $_REQUEST['search'] : '';
$fromdate = isset($_REQUEST['fromdate']) ? $_REQUEST['fromdate'] : '';
$todate = isset($_REQUEST['todate']) ? $_REQUEST['todate'] : '';
$mode = isset($_REQUEST['mode']) ? $_REQUEST['mode'] : '';
// 현재 날짜
$currentDate = date("Y-m-d");
// fromdate 또는 todate가 빈 문자열이거나 null인 경우
if ($fromdate === "" || $fromdate === null || $todate === "" || $todate === null) {
// 현재 월의 1일을 fromdate로 설정
$fromdate = date("Y-m-01");
// // fromdate를 이전 달의 1일로 설정
// $fromdate = date("Y-m-01", strtotime("first day of -1 month"));
$todate = $currentDate;
$Transtodate = $todate;
} else {
$Transtodate = $todate;
}
// 시작일과 종료일을 "8월1일~9월1일" 형태로 포맷팅
$formatted_date_range = date("n월j일", strtotime($fromdate)) . '~' . date("n월j일", strtotime($todate));
function checkNull($strtmp) {
return $strtmp !== null && trim($strtmp) !== '';
}
$tablenamephonebook = 'phonebook';
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
// 이월잔액 계산을 위한 로직 (매출 - 수금)
$initialBalances = [];
// 이월 잔액을 계산할 기준 날짜
$lastMonthEnd = date("Y-m-d", strtotime($fromdate . " -1 day"));
// echo '<pre>';
// echo '이월잔액 기간 lastMonthEnd: ';
// print_r($lastMonthEnd);
// echo '</pre>';
$searchsecondordnum = '';
if(!empty($search))
{
$sql = "SELECT secondordnum FROM ".$DB.".".$tablenamephonebook."
WHERE (is_deleted IS NULL OR is_deleted = 0 or is_deleted ='' )
AND represent='대표코드' AND (vendor_name LIKE '%$search%')";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$searchsecondordnum = $row['secondordnum'];
}
// 거래처별 매출 및 수금 데이터 계산 (이월잔액)
// 주일 work 테이블의 컬럼을 추가해야 함.
$salesBeforeSql = "
SELECT o.secondordnum, SUM(COALESCE(e.ET_total, 0)) AS total_sales
FROM {$DB}.work o
LEFT JOIN {$DB}.output_extra e ON o.num = e.parent_num
WHERE o.outdate <= :lastMonthEnd AND (o.is_deleted IS NULL or o.is_deleted=0 or o.is_deleted ='')
GROUP BY o.secondordnum
";
$paymentBeforeSql = "
SELECT secondordnum, SUM(CAST(REPLACE(amount, ',', '') AS SIGNED)) AS total_payment
FROM {$DB}.account_juil
WHERE registDate <= :lastMonthEnd AND (is_deleted IS NULL or is_deleted=0 or is_deleted ='' ) AND content = '거래처 수금'
AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')
GROUP BY secondordnum
";
$salesBeforeStmt = $pdo->prepare($salesBeforeSql);
$salesBeforeStmt->execute([':lastMonthEnd' => $lastMonthEnd]);
$salesBeforeData = $salesBeforeStmt->fetchAll(PDO::FETCH_ASSOC);
$paymentBeforeStmt = $pdo->prepare($paymentBeforeSql);
$paymentBeforeStmt->execute([':lastMonthEnd' => $lastMonthEnd]);
$paymentBeforeData = $paymentBeforeStmt->fetchAll(PDO::FETCH_ASSOC);
// 거래처별로 매출과 수금을 비교해 이월 잔액을 계산
foreach ($salesBeforeData as $row) {
$secondordnum = $row['secondordnum'];
$total_sales = (float)$row['total_sales'];
if (!isset($initialBalances[$secondordnum])) {
$initialBalances[$secondordnum] = 0;
}
$initialBalances[$secondordnum] += $total_sales;
}
// echo '<pre>';
// print_r($initialBalances);
// echo '</pre>';
// 수금 데이터를 이용해 이월 잔액에서 수금을 차감
foreach ($paymentBeforeData as $row) {
$secondordnum = $row['secondordnum'];
$total_payment = (float)$row['total_payment'];
if (!isset($initialBalances[$secondordnum])) {
$initialBalances[$secondordnum] = 0;
}
$initialBalances[$secondordnum] -= $total_payment;
}
// echo '<pre>';
// print_r($initialBalances);
// echo '</pre>';
// 매출이 발생한 거래처 필터링 및 매출액 계산
$salesSql = "
SELECT o.secondordnum, COALESCE(e.ET_total, 0) as ET_total
FROM {$DB}.work o
LEFT JOIN {$DB}.output_extra e ON o.num = e.parent_num
WHERE (o.outdate BETWEEN date('$fromdate') AND date('$Transtodate'))
AND (o.is_deleted IS NULL OR o.is_deleted = 0 or o.is_deleted ='')
";
$salesStmt = $pdo->prepare($salesSql);
$salesStmt->execute();
$salesData = $salesStmt->fetchAll(PDO::FETCH_ASSOC);
$salesResults = [];
foreach ($salesData as $row) {
$secondordnum = $row['secondordnum'];
$total_sales = (float)$row['ET_total'];
if (!isset($salesResults[$secondordnum])) {
$salesResults[$secondordnum] = 0;
}
$salesResults[$secondordnum] += $total_sales;
}
// echo '<pre>';
// echo '매출발생 시작 fromdate: ';
// print_r($fromdate);
// echo '</pre>';
// echo '<pre>';
// echo '매출발생 종료 Transtodate: ';
// print_r($Transtodate);
// echo '</pre>';
// echo '<pre>';
// echo '이월잔액배열 디오이엔시 추적 initialBalances: ';
// print_r($initialBalances['56']);
// echo '</pre>';
// 모든 거래처 목록을 처리하기 전에 거래처 이름을 저장하는 배열 초기화
$vendorNames = [];
// 모든 거래처 목록을 생성 (매출, 기초채권)
$allResults = array_unique(array_merge(array_keys($salesResults), array_keys($initialBalances)));
// 매출 금액 기준으로 역순으로 정렬
usort($allResults, function($a, $b) use ($salesResults) {
$salesA = isset($salesResults[$a]) ? $salesResults[$a] : 0;
$salesB = isset($salesResults[$b]) ? $salesResults[$b] : 0;
return round($salesA - $salesB);
});
// 합계를 저장할 변수들
$totalInitialReceivable = 0;
$totalSalesAmount = 0;
$totalPaymentAmount = 0;
$totalBalanceDue = 0;
try {
$start_num = 1;
foreach ($allResults as $ordnum) {
// 이월 잔액 설정
$initialReceivable = isset($initialBalances[$ordnum]) ? $initialBalances[$ordnum] : 0;
// 수금 내역 가져오기
$paymentSql = "SELECT SUM(CAST(REPLACE(amount, ',', '') AS SIGNED)) as total_payment
FROM ".$DB.".account_juil
WHERE secondordnum = '$ordnum'
AND registDate BETWEEN '1970-01-01' AND date('$Transtodate')
AND (is_deleted IS NULL OR is_deleted = 0 or is_deleted ='' )
AND content = '거래처 수금'
AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')";
$paymentStmt = $pdo->prepare($paymentSql);
$paymentStmt->execute();
$paymentData = $paymentStmt->fetch(PDO::FETCH_ASSOC);
$total_payment = isset($paymentData['total_payment']) ? (int)str_replace(',', '', $paymentData['total_payment']) : 0;
$total_sales = isset($salesResults[$ordnum]) ? $salesResults[$ordnum] : 0;
// 조건: 기초채권이 있거나 매출이 있는 경우만 표시
if ($initialReceivable != 0 || $total_sales != 0 ) { // 매출이 있는 것을 추출
$sql = "SELECT * FROM $DB.$tablenamephonebook
WHERE secondordnum = '$ordnum'
AND (is_deleted IS NULL OR is_deleted = 0 or is_deleted ='' )
AND represent='대표코드'";
$stmh = $pdo->query($sql);
while ($row = $stmh->fetch(PDO::FETCH_ASSOC)) {
include $_SERVER['DOCUMENT_ROOT'] . '/phonebook/_row.php';
if (intval($ordnum) > 0)
{
$savenum = $ordnum;
// 거래처 이름 저장
$vendorNames[$ordnum] =$vendor_name ;
}
else
$savenum = $num;
$total_amount = round($total_sales ) ;
// 잔액 계산
$balance_due = round($initialReceivable) + $total_amount - round($total_payment);
$totalInitialReceivable += $initialReceivable;
$totalSalesAmount += $total_amount;
$totalPaymentAmount += $total_payment;
$totalBalanceDue += $balance_due;
}
}
}
} catch (PDOException $Exception) {
print "오류: ".$Exception->getMessage();
}
// echo '<pre>';
// print_r($vendorNames);
// echo '</pre>';
// 거래처 이름으로 정렬
usort($allResults, function($a, $b) use ($vendorNames) {
// 거래처 이름이 없는 경우 빈 문자열로 처리
$nameA = $vendorNames[$a] ?? '';
$nameB = $vendorNames[$b] ?? '';
return strcmp($nameA, $nameB);
});
// echo $sql;
// echo '<pre>';
// print_r($allResults);
// echo '</pre>';
// $search값이 있다면 // 특정 숫자 67만 남기고 필터링
// echo 'searchsecondordnum : ' . $searchsecondordnum;
if (!empty($search)) {
$allResults = array_filter($allResults, function ($value) use ($searchsecondordnum) {
return $value === intval($searchsecondordnum);
});
// array_values로 인덱스 재정렬
$allResults = array_values($allResults);
}
// 중복 제거
$allResults = array_unique($allResults);
// 중복 제거
$allResults = array_unique($allResults);
// 빈 값 제거
$allResults = array_filter($allResults, function ($value) {
return $value !== null && $value !== '';
});
// 배열 키 재정렬
$allResults = array_values($allResults);
// echo '<pre>';
// print_r($allResults);
// echo '</pre>';
?>
<form id="board_form" name="board_form" method="post" enctype="multipart/form-data">
<div class="container mb-5">
<input type="hidden" id="mode" name="mode" value="<?=$mode?>">
<input type="hidden" id="num" name="num">
<input type="hidden" id="tablename" name="tablename" value="<?=$tablenamephonebook?>">
<input type="hidden" id="header" name="header" value="<?=$header?>">
<input type="hidden" id="secondordnum" name="secondordnum" value="<?=$secondordnum?>">
<div class="card justify-content-center text-center mt-5">
<div class="card-header">
<div class="d-flex p-1 m-1 mt-1 mb-1 justify-content-center align-items-center">
<span class="text-center fs-5 me-4"><?=$title_message?></span>
<span class="text-center ">* 출고완료일 기준 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>
<button type="button" class="btn btn-dark btn-sm mx-3" onclick='location.reload();' title="새로고침"> <i class="bi bi-arrow-clockwise"></i> </button>
<!-- <span class="badge bg-primary"> (한빛에스티) 매월25일 마감 </span> -->
</div>
</div>
<div class="card-body">
<div class="d-flex p-1 m-1 mt-1 mb-1 justify-content-center align-items-center">
▷ <span id="total"> </span> &nbsp;
<!-- 기간부터 검색까지 연결 묶음 start -->
<button type="button" class="btn btn-outline-dark btn-sm me-1 change_dateRange" onclick='alldatesearch()'>전체</button>
<span id="showdate" class="btn btn-dark btn-sm">기간</span> &nbsp;
<div id="showframe" class="card" style="width:300px;">
<div class="card-header" style="padding:2px;">
<div class="d-flex justify-content-center align-items-center">
기간 설정
</div>
</div>
<div class="card-body">
<div class="d-flex justify-content-center align-items-center">
<button type="button" class="btn btn-dark btn-sm me-1 change_dateRange" onclick='prepre_month()'>전전월</button>
<button type="button" class="btn btn-dark btn-sm me-1 change_dateRange" onclick='pre_month()'>전월</button>
<button type="button" class="btn btn-dark btn-sm me-1 change_dateRange" onclick='this_month()'>당월</button>
<button type="button" class="btn btn-dark btn-sm me-1 change_dateRange" onclick='this_year()'>당해년도</button>
</div>
</div>
</div>
<input type="date" id="fromdate" name="fromdate" class="form-control" style="width:100px;" value="<?=$fromdate?>"> &nbsp; ~ &nbsp;
<input type="date" id="todate" name="todate" class="form-control me-1" style="width:100px;" value="<?=$todate?>"> &nbsp; </span>
<div class="inputWrap">
<input type="text" id="search" name="search" value="<?=$search?>" onkeydown="if(event.key === 'Enter') submitForm();" autocomplete="off" class="form-control" style="width:150px;"> &nbsp;
<button class="btnClear"></button>
</div>
<div id="autocomplete-list">
</div>
&nbsp;
<button id="searchBtn" type="button" class="btn btn-dark btn-sm me-2" onclick="submitForm()"> <i class="bi bi-search"></i> </button>
<button type="button" class="btn btn-dark btn-sm me-2" onclick="location.href='../getmoney/list.php?header=header'"><i class="bi bi-journal-x"></i> 수금 </button>
<button type="button" class="btn btn-dark btn-sm me-1" onclick="location.href='../account_juil/month_sales.php?header=header'"> <i class="bi bi-file-earmark-ruled"></i> 판매일괄회계</button>
<button type="button" class="btn btn-primary btn-sm me-1" onclick="saveBalance();"> <i class="bi bi-floppy"></i> 차기월 이월금확정</button>
<button type="button" class="btn btn-danger btn-sm me-2" onclick="location.href='../account_juil/receivable.php?header=header'"> <i class="bi bi-journal-x"></i> 미수금 </button>
<button type="button" class="btn btn-dark btn-sm me-2" onclick="generateExcel();" > <i class="bi bi-file-earmark-spreadsheet"></i> </button>
</div>
</div>
</div>
<div class="card justify-content-center text-center mt-5">
<div class="card-body">
<div class="d-flex p-1 m-1 mb-1 justify-content-center align-items-center">
<table class="table table-hover" id="myTable">
<thead class="table-info">
<th class="text-center w80px">번호</th>
<th class="text-center w200px">거래처명</th>
<th class="text-center w140px">이월잔액</th>
<th class="text-center w140px"> 매출</th>
<th class="text-center w140px">수금</th>
<th class="text-center w140px">잔액</th>
<th class="text-center w60px">결제일</th>
<th class="text-center w140px">적요</th>
<?php if($user_id == 'pro')
print '<th class="text-center w50px">거래처 Code</th>';
?>
<th style="display:none;" ></th>
</thead>
<tbody>
<?php
try {
$start_num = 1;
foreach ($allResults as $initnum) {
// echo 'second ord num '. $initnum . '<br>';
// 이월잔액 설정
$initialReceivable = isset($initialBalances[$initnum]) ? intval($initialBalances[$initnum]) : 0;
// 마지막 자릿수가 1인지 확인
if (floatval($initialReceivable) % 10 === 1) {
// 마지막 자릿수를 제거 (정수로 처리)
$initialReceivable = floor($initialReceivable / 10);
}
// echo '거래처 $initnum' . $initnum . ' : ', $initialReceivable . ' <br> ' ;
// 수금 내역 가져오기
$paymentSql = "SELECT SUM(CAST(REPLACE(amount, ',', '') AS SIGNED)) as total_payment
FROM $DB.account_juil
WHERE secondordnum = '$initnum'
AND registDate BETWEEN date('$fromdate') AND date('$Transtodate')
AND (is_deleted IS NULL OR is_deleted = 0 or is_deleted ='' )
AND content = '거래처 수금'
AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')";
$paymentStmt = $pdo->prepare($paymentSql);
$paymentStmt->execute();
$paymentData = $paymentStmt->fetch(PDO::FETCH_ASSOC);
$total_payment = isset($paymentData['total_payment']) ? (int)str_replace(',', '', $paymentData['total_payment']) : 0;
$total_sales = isset($salesResults[$initnum]) ? $salesResults[$initnum] : 0;
// print $total_sales;
// 조건: 이월잔액이 있거나 매출이 있는 경우만 표시
// 검색어가 있는 경우 검색어 있는 것만 나오게 함
// echo 'searchsecondordnum : ' . $searchsecondordnum;
if ( ($initialReceivable != 0 or $total_sales != 0) and intval($initnum) > 1 ) {
$sql = "SELECT * FROM $DB.$tablenamephonebook
WHERE secondordnum = '$initnum'
AND (is_deleted IS NULL OR is_deleted = 0 or is_deleted ='' )
AND represent='대표코드'";
$total_amount = round($total_sales,2);
// 잔액 계산
$balance_due = $initialReceivable + $total_amount - $total_payment;
$memo = '';
// if($balance_due>0 && $initialReceivable>0 )
// (주)한빛에스티는 25일 마감 예외처리해야함.
// if($vendor_name === '㈜ 한빛에스티')
// $vendor_name = '㈜ 한빛에스티(월마감25일)';
// 마지막 단위 원단위 중 1은 제거하는 로직
// 당월매출 마지막 1원 삭제
// 마지막 자리가 1로 끝나는 경우, 0으로 변경
// print_r($total_payment);
// $totalSalesAmount -= 5;
if (round($total_amount,2) % 10 === 1) {
$total_amount -= 1; // 1을 빼서 마지막 자리를 0으로 만듭니다.
}
if ($balance_due % 10 === 1) {
$balance_due -= 1; // 1을 빼서 마지막 자리를 0으로 만듭니다.
}
// print_r($balance_due);
if (intval($balance_due) !== 0 || $total_sales > 0 ) {
?>
<tr onclick="redirectToView('<?= $initnum ?>')">
<td class="text-center"><?= $start_num ?></td>
<td class="text-start text-primary"><?= $vendorNames[$initnum] ?></td>
<td class="text-end text-primary fw-bold"><?= number_format($initialReceivable) ?></td>
<td class="text-end text-secondary fw-bold"><?= number_format($total_amount) ?></td>
<td class="text-end fw-bold"><?= number_format($total_payment) ?></td>
<td class="text-end fw-bold"><?= number_format($balance_due) ?></td>
<td class="text-end text-primary fw-bold">
<?php if (!empty($paydate)) : ?>
<?= htmlspecialchars($paydate) ?>
<?php endif; ?>
</td>
<td class="text-end"><?= $memo ?></td>
<?php if($user_id == 'pro')
echo '<td class="text-center w50px"> ' . $initnum . ' </td>';
?>
<td style="display:none;"><?= $initnum ?></td>
</tr>
<?php
$start_num++;
}
}
}
?>
</tbody>
<tfoot class="table-secondary">
<tr>
<th class="text-end w80px" colspan="2"> 합계 &nbsp; </th>
<th class="text-end"><?= number_format($totalInitialReceivable) ?></th>
<th class="text-end"><?= number_format($totalSalesAmount) ?></th>
<th class="text-end"><?= number_format($totalPaymentAmount) ?></th>
<th class="text-end"><?= number_format($totalBalanceDue) ?></th>
<th class="text-end">&nbsp; </th>
<th class="text-end w150px">&nbsp; </th>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
</form>
<?php
} catch (PDOException $Exception) {
print "오류: ".$Exception->getMessage();
}
?>
<!-- 페이지로딩 -->
<script>
$(document).ready(function(){
var loader = document.getElementById('loadingOverlay');
loader.style.display = 'none';
});
function submitForm() {
$('#board_form').submit();
}
</script>
<script>
var dataTable; // DataTables 인스턴스 전역 변수
var bookpageNumber; // 현재 페이지 번호 저장을 위한 전역 변수
$(document).ready(function() {
// DataTables 초기 설정
dataTable = $('#myTable').DataTable({
"paging": true,
"ordering": true,
"searching": true,
"pageLength": 100,
"lengthMenu": [100, 200, 500, 1000],
"language": {
"lengthMenu": "Show _MENU_ entries",
"search": "Live Search:"
},
// "order": [[8, 'desc']], // 잔액기준 내림차순 정렬
"dom": 't<"bottom"ip>', // search 창과 lengthMenu 숨기기
"footerCallback": function ( row, data, start, end, display ) {
var api = this.api(), data;
// 합계를 계산하는 함수
var intVal = function (i) {
return typeof i === 'string' ?
i.replace(/[\$,]/g, '')*1 :
typeof i === 'number' ?
i : 0;
};
// 합계 계산
totalInitialReceivable = api.column(2).data().reduce(function (a, b) { return intVal(a) + intVal(b); }, 0);
totalSalesAmount = api.column(3).data().reduce(function (a, b) { return intVal(a) + intVal(b); }, 0);
totalPaymentAmount = api.column(4).data().reduce(function (a, b) { return intVal(a) + intVal(b); }, 0);
totalBalanceDue = api.column(5).data().reduce(function (a, b) { return intVal(a) + intVal(b); }, 0);
// 합계 출력
$(api.column(2).footer()).html(numberWithCommas(totalInitialReceivable));
$(api.column(3).footer()).html(numberWithCommas(totalSalesAmount));
$(api.column(4).footer()).html(numberWithCommas(totalPaymentAmount));
$(api.column(5).footer()).html(numberWithCommas(totalBalanceDue));
}
});
// 페이지 번호 복원 (초기 로드 시)
var savedPageNumber = getCookie('bookpageNumber');
if (savedPageNumber) {
dataTable.page(parseInt(savedPageNumber) - 1).draw(false);
}
// 페이지 변경 이벤트 리스너
dataTable.on('page.dt', function() {
var bookpageNumber = dataTable.page.info().page + 1;
setCookie('bookpageNumber', bookpageNumber, 10); // 쿠키에 페이지 번호 저장
});
// 페이지 길이 셀렉트 박스 변경 이벤트 처리
$('#myTable_length select').on('change', function() {
var selectedValue = $(this).val();
dataTable.page.len(selectedValue).draw(); // 페이지 길이 변경 (DataTable 파괴 및 재초기화 없이)
// 변경 후 현재 페이지 번호 복원
savedPageNumber = getCookie('bookpageNumber');
if (savedPageNumber) {
dataTable.page(parseInt(savedPageNumber) - 1).draw(false);
}
});
var total = '<?php echo $start_num; ?>';
$("#total").text(Number(total)-1);
});
function redirectToView(num) {
var fromdate = document.getElementById('fromdate').value;
var todate = document.getElementById('todate').value;
var url = "../account_juil/S_transaction_sheet.php?num=" + num + "&fromdate=" + fromdate + "&todate=" + todate;
customPopup(url, '거래원장', 1000, 850);
}
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
function saveBalance() {
// 테이블 데이터를 수집
let data = [];
let closure_date = $('#todate').val();
let year = closure_date.split('-')[0];
let month = closure_date.split('-')[1];
let dayOfMonth = parseInt(closure_date.split('-')[2]);
// 해당 월의 마지막 날 계산
let lastDayOfMonth = new Date(year, month, 0).getDate();
// 날짜가 말일 또는 25일이 아닌 경우 경고 메시지 출력
if (dayOfMonth !== lastDayOfMonth && dayOfMonth !== 25) {
alert('해당일자로 이월 마감할 수 없습니다.');
return; // 함수 종료
}
$('#myTable tbody tr').each(function() {
let row = $(this);
let balance = parseFloat(row.find('td:nth-child(6)').text().replace(/,/g, ''));
let secondordnum = row.find('td:nth-child(9)').text().trim();
// 매월 말일인 경우
if (dayOfMonth === lastDayOfMonth) {
// '66'이 아닌 데이터만 처리
if (secondordnum !== '66' && balance !== 0) {
data.push({
mode: row.attr('data-mode') || 'insert', // insert or update mode
num: row.attr('data-num'),
secondordnum: secondordnum,
customer_name: row.find('td:nth-child(2)').text().trim(),
balance: balance,
closure_date: closure_date,
memo: row.find('td:nth-child(8)').text().trim()
});
}
}
// 25일인 경우
else if (dayOfMonth === 25) {
// '66' 데이터만 처리
if (secondordnum === '66' && balance !== 0) {
data.push({
mode: row.attr('data-mode') || 'insert', // insert or update mode
num: row.attr('data-num'),
secondordnum: secondordnum,
customer_name: row.find('td:nth-child(2)').text().trim(),
balance: balance,
closure_date: closure_date,
memo: row.find('td:nth-child(8)').text().trim()
});
}
}
});
// Ajax로 데이터 전송
if (data.length > 0) {
$.ajax({
url: 'insert_monthly_balance.php',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(data),
success: function(response) {
let result = JSON.parse(response);
if (result.status === 'success') {
alert('이월금액이 성공적으로 저장되었습니다.');
} else {
alert('오류 발생: ' + result.message);
}
},
error: function(xhr, status, error) {
alert('오류 발생: ' + error);
}
});
} else {
alert('저장할 데이터가 없습니다.');
}
}
function detail() {
// 년도, 시작 월, 종료 월 값을 가져옴
const year = document.getElementById('year').value;
const startMonth = document.getElementById('startMonth').value;
const endMonth = document.getElementById('endMonth').value;
// detail.php로 이동할 URL 생성
const url = `detail.php?year=${year}&startMonth=${startMonth}&endMonth=${endMonth}`;
// customPopup을 사용하여 detail.php를 팝업으로 열기
customPopup(url, '상세 내역', 900, 700);
}
function generateExcel() {
var table = document.getElementById('myTable');
var rows = table.getElementsByTagName('tr');
var data = [];
// 각 행을 반복하여 데이터 수집
for (var i = 1; i < rows.length; i++) { // 헤더 행을 건너뜀
var cells = rows[i].getElementsByTagName('td');
var rowData = {};
rowData['number'] = cells[0]?.innerText || '';
rowData['secondord'] = cells[1]?.innerText || '';
rowData['lastbalance'] = cells[2]?.innerText || '';
rowData['monthsales'] = cells[3]?.innerText || '';
rowData['income'] = cells[4]?.innerText || '';
rowData['balances'] = cells[5]?.innerText || '';
rowData['payday'] = cells[6]?.innerText || '';
rowData['memo'] = cells[7]?.innerText || '';
rowData['secondordnum'] = cells[8]?.innerText || '';
data.push(rowData);
}
// saveExcel.php에 데이터 전송
var xhr = new XMLHttpRequest();
xhr.open("POST", "customer_saveExcel.php", true);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
try {
var response = JSON.parse(xhr.responseText);
if (response.success) {
console.log('Excel file generated successfully.');
// 다운로드 스크립트로 리디렉션
window.location.href = 'downloadExcel.php?filename=' + encodeURIComponent(response.filename.split('/').pop());
} else {
console.log('Failed to generate Excel file: ' + response.message);
}
} catch (e) {
console.log('Error parsing response: ' + e.message + '\nResponse text: ' + xhr.responseText);
}
} else {
console.log('Failed to generate Excel file: Server returned status ' + xhr.status);
}
}
};
xhr.send(JSON.stringify(data));
}
$(document).ready(function(){
saveLogData('거래처 원장');
});
</script>
</body>
</html>

View File

@@ -0,0 +1,598 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
// 첫 화면 표시 문구
$title_message = '거래처 원장';
$tablename = 'motor';
// 견적서, 거래명세서, 총거래원장등 설정 $item으로 설정하면 됨.
$item_title ='거래처 원장';
include $_SERVER['DOCUMENT_ROOT'] . '/load_header.php';
?>
<title> <?= $title_message ?> </title>
<style>
table, th, td {
border: 1px solid black !important; /* Bold border */
font-size: 12px !important;
white-space: nowrap;
}
/* Add background color for date rows */
.date-row {
background-color: #f0f0f0!important; /* Light gray background */
}
.date-row-date {
background-color: #f0f0f0!important; /* Light gray background */
color: blue !important;
}
@media print {
body {
width: 210mm; /* A4 width */
height: 297mm; /* A4 height */
margin: 0; /* Remove default margin */
font-size: 10pt; /* Font size for printing */
}
.table {
width: 100%; /* Full width tables */
table-layout: fixed; /* Uniform column sizing */
border-collapse: collapse; /* Ensure borders collapse */
}
.table th, .table td {
padding: 1px; /* Reduce padding */
border: 1px solid #ddd; /* Ensure borders are visible */
}
.text-center {
text-align: center; /* Maintain center alignment */
}
/* Prevent table row splitting */
.table tr {
page-break-inside: avoid; /* Prevent breaking inside rows */
page-break-after: avoid; /* Allow breaking after rows */
}
.table thead {
display: table-header-group; /* Ensure table headers are repeated */
}
.table tbody {
display: table-row-group; /* Ensure table rows are grouped */
}
.table tfoot {
display: table-footer-group; /* Ensure table footers are repeated */
}
/* Add top and bottom margins to each page */
.table tbody:before,
.table tbody:after {
content: "";
display: table-row;
height: 5mm; /* Adjust as needed for top and bottom margins */
}
/* Remove border from the before and after elements */
.table tbody:before td,
.table tbody:after td {
border: none; /* Remove borders */
}
/* Adjust the border of the last row on the page */
.table tbody tr:last-child td {
border-bottom: none; /* Remove the bottom border */
border-left: none; /* Remove the bottom border */
border-right: none; /* Remove the bottom border */
border-top: none; /* Remove the bottom border */
}
/* Prevent border at the connection of two pages */
.table tbody tr:last-child td:first-child {
border-bottom: none; /* Remove the bottom border */
border-left: none; /* Remove the bottom border */
border-right: none; /* Remove the bottom border */
border-top: none; /* Remove the bottom border */
}
.table tbody tr:last-child td:last-child {
border-bottom: none; /* Remove the bottom border */
border-left: none; /* Remove the bottom border */
border-right: none; /* Remove the bottom border */
border-top: none; /* Remove the bottom border */
}
}
</style>
</head>
<body>
<?php
$num = isset($_REQUEST['num']) ? $_REQUEST['num'] : '';
$fromdate = isset($_REQUEST['fromdate']) ? $_REQUEST['fromdate'] : '';
$todate = isset($_REQUEST['todate']) ? $_REQUEST['todate'] : '';
$secondordnum = $num;
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
try {
// Fetch customer details from phonebook
$sql = "SELECT * FROM " . $DB . ".phonebook WHERE secondordnum = ?";
$stmh = $pdo->prepare($sql);
$stmh->bindValue(1, $num, PDO::PARAM_STR);
$stmh->execute();
$customer = $stmh->fetch(PDO::FETCH_ASSOC);
if (!$customer) {
throw new Exception("거래처 정보를 찾을 수 없습니다.");
}
// Fetch sales details from output + output_extra
$sql = "SELECT o.*, e.ET_total, e.estimateList, e.estimateSlatList, e.etcList, e.screen_unapprovedList, e.slat_unapprovedList, e.motorList, e.bendList, e.controllerList, e.accountList, e.ET_unapproved
FROM " . $DB . ".output o
LEFT JOIN " . $DB . ".output_extra e ON o.num = e.parent_num
WHERE o.secondordnum = ? AND o.outdate BETWEEN ? AND ? AND (o.is_deleted IS NULL OR o.is_deleted = 0)
ORDER BY o.outdate ASC";
$stmh = $pdo->prepare($sql);
$stmh->bindValue(1, $num, PDO::PARAM_STR);
$stmh->bindValue(2, $fromdate, PDO::PARAM_STR);
$stmh->bindValue(3, $todate, PDO::PARAM_STR);
$stmh->execute();
$rows = $stmh->fetchAll(PDO::FETCH_ASSOC);
// Fetch payments from account table
$sql = "SELECT registDate, amount FROM " . $DB . ".account
WHERE secondordnum = ?
AND registDate BETWEEN ? AND ?
AND (is_deleted IS NULL OR is_deleted = 0)
AND content = '거래처 수금'
ORDER BY registDate ASC";
$stmh = $pdo->prepare($sql);
$stmh->bindValue(1, $num, PDO::PARAM_STR);
$stmh->bindValue(2, $fromdate, PDO::PARAM_STR);
$stmh->bindValue(3, $todate, PDO::PARAM_STR);
$stmh->execute();
$payments = $stmh->fetchAll(PDO::FETCH_ASSOC);
// 다른 거래처는 기본적으로 마감 기준일 -1일
$lastMonthEnd = date("Y-m-t", strtotime($fromdate . " -1 days"));
// echo '<pre>';
// print_r($lastMonthEnd);
// echo '</pre>';
// 이월잔액 계산
$salesBeforeSql = "
SELECT SUM(COALESCE(e.ET_total, 0)) AS total_sales
FROM " . $DB . ".output o
LEFT JOIN " . $DB . ".output_extra e ON o.num = e.parent_num
WHERE o.secondordnum = :secondordnum AND o.outdate <= :lastMonthEnd AND (o.is_deleted IS NULL OR o.is_deleted = 0)
";
$paymentBeforeSql = "
SELECT SUM(CAST(REPLACE(amount, ',', '') AS SIGNED)) AS total_payment
FROM " . $DB . ".account
WHERE secondordnum = :secondordnum AND registDate <= :lastMonthEnd AND (is_deleted IS NULL OR is_deleted = 0) AND content = '거래처 수금'
";
$salesBeforeStmt = $pdo->prepare($salesBeforeSql);
$salesBeforeStmt->execute([':secondordnum' => $secondordnum, ':lastMonthEnd' => $lastMonthEnd]);
$salesBeforeData = $salesBeforeStmt->fetch(PDO::FETCH_ASSOC);
$paymentBeforeStmt = $pdo->prepare($paymentBeforeSql);
$paymentBeforeStmt->execute([':secondordnum' => $secondordnum, ':lastMonthEnd' => $lastMonthEnd]);
$paymentBeforeData = $paymentBeforeStmt->fetch(PDO::FETCH_ASSOC);
$initialSales = isset($salesBeforeData['total_sales']) ? (float)$salesBeforeData['total_sales'] : 0;
$initialPayments = isset($paymentBeforeData['total_payment']) ? (float)$paymentBeforeData['total_payment'] : 0;
// Calculate the initial balance
$initialBalance = intval(round($initialSales, 2) - round($initialPayments));
// 마지막 자릿수가 1인지 확인
if (floatval($initialBalance) % 10 === 1) {
// 마지막 자릿수를 제거 (정수로 처리)
$initialBalance = floor($initialBalance / 10);
}
} catch (Exception $e) {
echo "오류: " . $e->getMessage();
}
?>
<div class="container mt-2">
<div class="d-flex align-items-center justify-content-end mt-1 m-2">
<i class="bi bi-info-circle-fill"></i> <?=$secondordnum?> &nbsp;
<button type="button" class="btn btn-dark btn-sm me-1" onclick="location.reload();"> <i class="bi bi-arrow-clockwise"></i> </button>
<button class="btn btn-dark btn-sm me-1" onclick="generatePDF()"> PDF 저장 </button>
<button class="btn btn-dark btn-sm me-1" onclick="sendmail();"> <i class="bi bi-envelope-arrow-up"></i> 전송 </button>
<button class="btn btn-secondary btn-sm" onclick="self.close();"> <i class="bi bi-x-lg"></i> 닫기 </button>&nbsp;
</div>
</div>
<div id="content-to-print">
<div class="container" >
<div class="d-flex align-items-center justify-content-center mb-3">
<h2><?= $customer['vendor_name'] ?> 관리대장</h2>
<h5>(거래명세서별)</h5>
</div>
<div class="row align-items-center justify-content-center mb-1 mt-2">
<div class="col-sm-6 text-start">
회사명 : (주) 경동기업 / 담당 : 정미영 차장
</div>
<div class="col-sm-6 text-end">
<?= $fromdate ?> ~ <?= $todate ?>
</div>
</div>
<div class="d-flex align-items-center justify-content-center ">
<table class="table" style="border-collapse: collapse;">
<thead>
<tr>
<th class="text-start fw-bold" style="width:20%;">사업자등록번호</th>
<th class="text-start fw-bold text-primary" style="width:30%;"><?= $customer['vendor_code'] ?></th>
<th class="text-start fw-bold">대표자</th>
<th class="text-start"><?= $customer['representative_name'] ?></th>
</tr>
<tr>
<th class="text-start fw-bold">여신한도</th>
<th class="text-start">0</th>
<th class="text-start fw-bold">전화</th>
<th class="text-start"><?= $customer['phone'] ?> (모바일: <?= $customer['mobile'] ?>)</th>
</tr>
<tr>
<th class="text-start fw-bold">Email</th>
<th class="text-start"><?= $customer['email'] ?></th>
<th class="text-start fw-bold">Fax</th>
<th class="text-start"><?= $customer['fax'] ?></th>
</tr>
<tr>
<th class="text-start fw-bold">주소</th>
<th colspan="3" class="text-start"><?= $customer['address'] ?></th>
</tr>
<tr>
<th class="text-start fw-bold">적요</th>
<th colspan="3" class="text-start"></th>
</tr>
</thead>
</table>
</div>
<div class="d-flex align-items-center justify-content-center ">
<table class="table" style="border-collapse: collapse;">
<thead>
<tr>
<th colspan="5" class="text-center">판매/수금내역</th>
</tr>
<tr>
<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>
<tr>
<td colspan="2" class="text-center fw-bold text-primary">이월잔액</td>
<td class="text-center"></td>
<td class="text-center"></td>
<td class="text-end fw-bold text-primary"><?= number_format($initialBalance) ?></td>
</tr>
<?php
$total_balance = $initialBalance; // 초기 잔액 설정
$monthly_sales = [];
$current_month = '';
$grand_total = 0;
$sale_count = 0;
$total_payment_sum = 0; // 수금 합계 초기화
// Merge sales and payments into one array
$events = [];
foreach ($rows as $row) {
$events[] = [
'date' => $row['outdate'],
'type' => 'sale',
'data' => $row
];
}
// 수금부분
foreach ($payments as $payment) {
$events[] = [
'date' => $payment['registDate'], // 올바른 키 이름 사용
'type' => 'payment',
'data' => [
'amount' => $payment['amount'] // 올바른 키 이름 사용
]
];
}
// Sort events by date
usort($events, function($a, $b) {
return strcmp($a['date'], $b['date']);
});
// 출고예정일 첫번째 요소 저장변수
$Last_deadline = '';
foreach ($events as $event) {
$event_date = $event['date'];
$event_type = $event['type'];
$month = date('Y/m', strtotime($event_date));
if ($event_type == 'payment') {
$payment = $event['data'];
$payment_date = $event_date; // 날짜는 이벤트의 날짜를 사용
$payment_amount = (float)str_replace(',', '', $payment['amount']); // payment 대신 amount 키 사용
$total_balance -= $payment_amount;
$total_payment_sum += $payment_amount; // 수금 합계에 추가
if (!isset($monthly_sales[$month])) {
$monthly_sales[$month] = 0;
}
echo "<tr class='date-row'>
<td class='date-row-date text-start'>{$payment_date}</td>
<td class='date-row text-start'>입금</td>
<td class='date-row text-end'></td>
<td class='date-row text-end'>" . number_format($payment_amount) . "</td>
<td class='date-row text-end'>" . number_format($total_balance) . "</td>
</tr>";
}
if ($current_month !== $month) {
if ($current_month !== '') {
echo "<tr>
<td colspan='2' class='text-center fw-bold'>{$current_month} 계</td>
<td class='text-end'>" . number_format($monthly_sales[$current_month]) . "</td>
<td class='text-start'></td>
<td class='text-start'></td>
</tr>";
}
$current_month = $month;
}
if ($event_type == 'sale') {
$row = $event['data'];
$outdate = $row['outdate'];
$workplacename = isset($row['workplacename']) ? $row['workplacename'] : '';
$amount = (float)$row['ET_total'];
$total_balance += round($amount);
$sale_count++;
if (!isset($monthly_sales[$month])) {
$monthly_sales[$month] = 0;
}
$monthly_sales[$month] += $amount;
$grand_total += $amount;
echo "<tr class='date-row' onclick=\"redirectToView('{$row['num']}', '{$tablename}')\">
<td class='date-row-date text-start'>{$outdate}</td>
<td class='date-row text-start'>{$workplacename}</td>
<td class='date-row text-end'>" . number_format($amount) . "</td>
<td class='date-row text-start'></td>
<td class='date-row text-end'>" . number_format($total_balance) . "</td>
</tr>";
// 상세내역: estimateList, estimateSlatList, etcList, screen_unapprovedList, slat_unapprovedList, motorList, bendList, controllerList, accountList
$detailColumns = [
'estimateList', 'estimateSlatList', 'etcList', 'screen_unapprovedList', 'slat_unapprovedList', 'motorList', 'bendList', 'controllerList', 'accountList'
];
foreach ($detailColumns as $col) {
$list = isset($row[$col]) ? json_decode($row[$col], true) : [];
if (is_array($list)) {
foreach ($list as $item) {
// 품목명, 수량, 단가, 금액 등 컬럼명은 데이터 구조에 따라 다를 수 있음
$itemName = isset($item['col1']) ? $item['col1'] : '';
$spec = isset($item['col2']) ? $item['col2'] : '';
$qty = isset($item['col4']) ? $item['col4'] : (isset($item['col2']) ? $item['col2'] : 1);
$unit = isset($item['col5']) ? str_replace(',', '', $item['col5']) : 0;
$amountDetail = floatval($qty) * floatval($unit);
if ($itemName && $amountDetail > 0) {
echo "<tr>
<td class='text-start'></td>
<td class='text-start'>{$itemName} {$spec}</td>
<td class='text-end'>" . number_format($amountDetail) . "</td>
<td class='text-start'></td>
<td class='text-start'></td>
</tr>";
}
}
}
}
// 비인정 금액(ET_unapproved) 표시
if (isset($row['ET_unapproved']) && floatval($row['ET_unapproved']) > 0) {
echo "<tr>
<td class='text-start'></td>
<td class='text-start text-danger'>비인정 금액</td>
<td class='text-end text-danger'>-" . number_format($row['ET_unapproved']) . "</td>
<td class='text-start'></td>
<td class='text-start'></td>
</tr>";
}
}
}
if ($current_month !== '') {
// 마지막 1원 정리
if (round($monthly_sales[$current_month]) % 10 === 1) {
$monthly_sales[$current_month] -= 1; // 1을 빼서 마지막 자리를 0으로 만듭니다.
}
echo "<tr>
<td colspan='2' class='text-center fw-bold date-row'>{$current_month} 계 <span style='font-size:9px;'> (VAT 포함) </span></td>
<td class='text-end date-row fw-bold'>" . number_format($monthly_sales[$current_month]) . "</td>
<td class='text-start date-row'></td>
<td class='text-start date-row'></td>
</tr>";
}
if (round($grand_total) % 10 === 1) {
$grand_total -= 1; // 1을 빼서 마지막 자리를 0으로 만듭니다.
}
if (round($total_balance) % 10 === 1) {
$total_balance -= 1; // 1을 빼서 마지막 자리를 0으로 만듭니다.
}
?>
<tr class="date-row" >
<td colspan="2" class="text-center fw-bold date-row" >총 <?= $sale_count ?>건 누계 <span style='font-size:11px;'> (VAT 포함) </span></td>
<td class="text-end date-row fw-bold"><?= number_format($grand_total) ?></td>
<td class="text-end date-row fw-bold"><?= number_format($total_payment_sum) ?></td> <!-- 수금 합계 표시 -->
<td class="text-end date-row fw-bold"><?= number_format($total_balance) ?></td> <!-- 잔액 합계 표시 -->
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- 페이지로딩 -->
<script>
$(document).ready(function(){
var loader = document.getElementById('loadingOverlay');
loader.style.display = 'none';
});
function generatePDF() {
var workplace = '<?= $customer['vendor_name'] ?>';
var deadline = '<?php echo $Last_deadline; ?>';
var deadlineDate = new Date(deadline);
var formattedDate = "(" + String(deadlineDate.getFullYear()).slice(-2) + "." + ("0" + (deadlineDate.getMonth() + 1)).slice(-2) + "." + ("0" + deadlineDate.getDate()).slice(-2) + ")";
var result = '경동기업_거래원장(' + workplace + ')' + formattedDate + '.pdf';
var element = document.getElementById('content-to-print');
var opt = {
margin: [15, 8, 17, 8], // Top, right, bottom, left margins
filename: result,
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 2 },
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' },
pagebreak: { mode: [''] }
};
html2pdf().from(element).set(opt).save();
}
function redirectToView(num, tablename) {
var url = "/output/write_form.php?mode=view&num=" + num + "&tablename=" + tablename;
customPopup(url, '수주내역', 1850, 900);
}
ajaxRequest = null;
function generatePDF_server(callback) {
var workplace = '<?= $customer['vendor_name'] ?>';
var item = '<?php echo $item_title; ?>';
var deadline = '<?php echo $Last_deadline; ?>';
var deadlineDate = new Date(deadline);
var formattedDate = "(" + String(deadlineDate.getFullYear()).slice(-2) + "." + ("0" + (deadlineDate.getMonth() + 1)).slice(-2) + "." + ("0" + deadlineDate.getDate()).slice(-2) + ")";
var result = 'DH ' + item +'(' + workplace + ')' + formattedDate + '.pdf';
var element = document.getElementById('content-to-print');
var opt = {
margin: [15, 8, 17, 8], // Top, right, bottom, left margins
filename: result,
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 2 },
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' },
pagebreak: { mode: [''] }
};
html2pdf().from(element).set(opt).output('datauristring').then(function (pdfDataUri) {
var pdfBase64 = pdfDataUri.split(',')[1]; // Base64 인코딩된 PDF 데이터 추출
var formData = new FormData();
formData.append('pdf', pdfBase64);
formData.append('filename', result);
$.ajax({
type: 'POST',
url: 'save_pdf.php', // PDF 파일을 저장하는 PHP 파일
data: formData,
processData: false,
contentType: false,
success: function (response) {
var res = JSON.parse(response);
if (callback) {
callback(res.filename); // 서버에 저장된 파일 경로를 콜백으로 전달
}
},
error: function (xhr, status, error) {
Swal.fire('Error', 'PDF 저장에 실패했습니다.', 'error');
}
});
});
}
function sendmail() {
var secondordnum = '<?php echo $secondordnum; ?>'; // 서버에서 가져온 값
var item = '<?php echo $item_title; ?>';
console.log('secondordnum', secondordnum);
if (typeof ajaxRequest !== 'undefined' && ajaxRequest !== null) {
ajaxRequest.abort();
}
ajaxRequest = $.ajax({
type: 'POST',
url: 'get_companyCode.php', // 파일 이름 수정
data: { secondordnum: secondordnum },
dataType: 'json',
success: function(response) {
console.log('response : ', response);
if (response.error) {
Swal.fire('Error', response.error, 'error');
} else {
var email = response.email;
var vendorName = response.vendor_name;
Swal.fire({
title: '이메일 보내기',
text: '거래처(' + vendorName + ') Email : (' + email + ') 이메일 전송 하시겠습니까?',
icon: 'warning',
showCancelButton: true,
confirmButtonText: '보내기',
cancelButtonText: '취소',
reverseButtons: true
}).then((result) => {
if (result.isConfirmed) {
generatePDF_server(function(filename) {
sendEmail(email, vendorName, item, filename);
});
}
});
}
},
error: function(xhr, status, error) {
Swal.fire('Error', '전송중 오류가 발생했습니다.', 'error');
}
});
}
function sendEmail(recipientEmail,vendorName, item, filename) {
// 이메일 전송 코드 작성 (예: PHP를 호출하여 이메일 전송)
if (typeof ajaxRequest !== 'undefined' && ajaxRequest !== null) {
ajaxRequest.abort();
}
var deadline = '<?php echo $Last_deadline; ?>';
var deadlineDate = new Date(deadline);
var formattedDate = "(" + String(deadlineDate.getFullYear()).slice(-2) + "." + ("0" + (deadlineDate.getMonth() + 1)).slice(-2) + "." + ("0" + deadlineDate.getDate()).slice(-2) + ")";
ajaxRequest = $.ajax({
type: 'POST',
url: 'send_email.php', // 이메일 전송을 처리하는 PHP 파일
data: { email: recipientEmail, vendorName : vendorName, filename: filename, item : item, formattedDate :formattedDate },
success: function(response) {
console.log(response);
Swal.fire('Success', '정상적으로 전송되었습니다.', 'success');
},
error: function(xhr, status, error) {
Swal.fire('Error', '전송에 실패했습니다. 확인바랍니다.', 'error');
}
});
}
</script>
</body>
</html>

18
account_juil/_request.php Normal file
View File

@@ -0,0 +1,18 @@
<?php
$num = isset($_REQUEST['num']) ? $_REQUEST['num'] : '';
$is_deleted = isset($_REQUEST['is_deleted']) ? $_REQUEST['is_deleted'] : 0;
$searchtag = isset($_REQUEST['searchtag']) ? $_REQUEST['searchtag'] : '';
$registDate = isset($_REQUEST['registDate']) ? $_REQUEST['registDate'] : '';
$inoutsep = isset($_REQUEST['inoutsep']) ? $_REQUEST['inoutsep'] : '';
$content = isset($_REQUEST['content']) ? $_REQUEST['content'] : '';
$contentSub = isset($_REQUEST['contentSub']) ? $_REQUEST['contentSub'] : '';
$amount = isset($_REQUEST['amount']) ? $_REQUEST['amount'] : '';
$dueDate = isset($_REQUEST['dueDate']) ? $_REQUEST['dueDate'] : '';
$first_writer = isset($_REQUEST['first_writer']) ? $_REQUEST['first_writer'] : '';
$update_log = isset($_REQUEST['update_log']) ? $_REQUEST['update_log'] : '';
$content_detail = isset($_REQUEST['content_detail']) ? $_REQUEST['content_detail'] : '';
$bankbook = isset($_REQUEST['bankbook']) ? $_REQUEST['bankbook'] : '';
$secondordnum = isset($_REQUEST['secondordnum']) ? $_REQUEST['secondordnum'] : '';
$endorsementDate = isset($_REQUEST['endorsementDate']) ? $_REQUEST['endorsementDate'] : date('Y-m-d');
$parentEBNum = isset($_REQUEST['parentEBNum']) ? $_REQUEST['parentEBNum'] : '';
?>

18
account_juil/_row.php Normal file
View File

@@ -0,0 +1,18 @@
<?php
$num = isset($row['num']) ? $row['num'] : '';
$is_deleted = isset($row['is_deleted']) ? $row['is_deleted'] : 0;
$searchtag = isset($row['searchtag']) ? $row['searchtag'] : '';
$registDate = isset($row['registDate']) ? $row['registDate'] : '';
$inoutsep = isset($row['inoutsep']) ? $row['inoutsep'] : '';
$content = isset($row['content']) ? $row['content'] : '';
$contentSub = isset($row['contentSub']) ? $row['contentSub'] : '';
$amount = isset($row['amount']) ? $row['amount'] : '';
$dueDate = isset($row['dueDate']) ? $row['dueDate'] : '';
$first_writer = isset($row['first_writer']) ? $row['first_writer'] : '';
$update_log = isset($row['update_log']) ? $row['update_log'] : '';
$content_detail = isset($row['content_detail']) ? $row['content_detail'] : '';
$bankbook = isset($row['bankbook']) ? $row['bankbook'] : '';
$secondordnum = isset($row['secondordnum']) ? $row['secondordnum'] : '';
$endorsementDate = isset($row['endorsementDate']) ? $row['endorsementDate'] : '';
$parentEBNum = isset($row['parentEBNum']) ? $row['parentEBNum'] : '';
?>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,32 @@
[
{
"company": "국민",
"number": "796801-00-039630",
"memo": "주거래통장"
},
{
"company": "국민",
"number": "006090-18-199685",
"memo": "미래에셋주식계좌"
},
{
"company": "국민",
"number": "796868-00-003858",
"memo": "외국환거래통장"
},
{
"company": "기업",
"number": "339-086768-01-011",
"memo": ""
},
{
"company": "기업",
"number": "339-086768-01-028",
"memo": "보증부대출전용"
},
{
"company": "국민",
"number": "796816-00-062898",
"memo": "산재예방시설자금(대출)"
}
]

View File

@@ -0,0 +1,92 @@
[
{
"company": "국민은행★",
"number": "231401-04-180862",
"memo": ""
},
{
"company": "국민은행",
"number": "796801-00-006119",
"memo": ""
},
{
"company": "국민은행(롯데건설)",
"number": "796837-00-001193",
"memo": ""
},
{
"company": "국민은행(영신)",
"number": "433437-01-005318",
"memo": ""
},
{
"company": "국민은행(현대건설)",
"number": "433437-01-005363",
"memo": ""
},
{
"company": "기업은행",
"number": "149-074461-01-018",
"memo": ""
},
{
"company": "기업은행(동성빌딩)",
"number": "461-044317-04-021",
"memo": ""
},
{
"company": "하나은행",
"number": "337-890050-08504",
"memo": ""
},
{
"company": "하나은행(요진건설)",
"number": "176-910045-85504",
"memo": ""
},
{
"company": "하나은행(이수건설)",
"number": "176-910043-21004",
"memo": ""
},
{
"company": "하나은행(현대엔지니어링)",
"number": "176-910039-25104",
"memo": ""
},
{
"company": "하나은행(한화)",
"number": "176-910038-64504",
"memo": ""
},
{
"company": "신한은행(GS건설)",
"number": "100-033-404566",
"memo": ""
},
{
"company": "신한은행(신세계건설)",
"number": "100-033-032265",
"memo": ""
},
{
"company": "신한은행(케이알산업)",
"number": "100-037-328297",
"memo": ""
},
{
"company": "우리은행(대림건설)",
"number": "1005-203-967961",
"memo": ""
},
{
"company": "하나은행(하도급지킴이3)",
"number": "176-910042-260004",
"memo": ""
},
{
"company": "기업은행(기보대출통장)",
"number": "170-175366-01-011",
"memo": ""
}
]

168
account_juil/accoutlist.php Normal file
View File

@@ -0,0 +1,168 @@
<?php
// accoutlist.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;
}
include $_SERVER['DOCUMENT_ROOT'] . '/load_header.php';
$title_message = '법인계좌 목록 관리';
?>
<title><?= $title_message ?></title>
<?php if($chkMobile==true) { ?>
<style>
@media (max-width: 1000px) {
body { font-size: 25px; }
.form-control, .fw-bold, .table td, .table th { font-size: 25px; }
button { font-size: 30px; }
.modal-body, .modal-title { font-size: 30px; }
}
</style>
<?php } ?>
</head>
<body>
<?php
// 메뉴를 표현할지 판단하는 header
$header = $_REQUEST['header'] ?? '';
if($user_id === '0266771300' ) {
require_once($_SERVER['DOCUMENT_ROOT'] . '/myheader_accountant1.php'); // 경리
} else {
require_once($_SERVER['DOCUMENT_ROOT'] . '/myheader1.php');
}
$jsonFile = $_SERVER['DOCUMENT_ROOT'] . '/account_juil/accoutlist.json';
$cards = [];
if (file_exists($jsonFile)) {
$jsonContent = file_get_contents($jsonFile);
$cards = json_decode($jsonContent, true);
if (!is_array($cards)) {
$cards = [];
}
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
$index = isset($_POST['index']) ? intval($_POST['index']) : -1;
$company = trim($_POST['company'] ?? '');
$number = trim($_POST['number'] ?? '');
$memo = trim($_POST['memo'] ?? '');
if ($action === 'insert' && $company !== '' && $number !== '') {
$cards[] = [
"company" => $company,
"number" => $number,
"memo" => $memo
];
} elseif ($action === 'update' && $index >= 0 && $index < count($cards)) {
$cards[$index]["company"] = $company;
$cards[$index]["number"] = $number;
$cards[$index]["memo"] = $memo;
} elseif ($action === 'delete' && $index >= 0 && $index < count($cards)) {
array_splice($cards, $index, 1);
}
file_put_contents($jsonFile, json_encode($cards, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
}
?>
<div class="container mt-3">
<div class="card">
<div class="card-header d-flex justify-content-center align-items-center text-center">
<h3 class="mb-0"><?= $title_message ?></h3>
</div>
<div class="card-body">
<form id="addCardForm" method="post" action="accoutlist.php" class="row g-3 mb-3">
<input type="hidden" name="action" id="action" value="insert">
<input type="hidden" name="index" id="index" value="-1">
<div class="d-flex justify-content-center align-items-center text-center">
<input type="text" name="company" id="company" class="form-control mx-1" placeholder="은행명" autocomplete="off" style="width:150px;">
<input type="text" name="number" id="number" class="form-control mx-1" placeholder="계좌 번호" autocomplete="off" style="width:200px;">
<input type="text" name="memo" id="memo" class="form-control mx-1" placeholder="비고" autocomplete="off" style="width:120px;">
<button type="submit" class="btn btn-primary btn-sm mx-1" id="submitBtn">등록</button>
</div>
</form>
<div class="table-responsive">
<table class="table table-bordered table-hover text-center">
<thead class="table-secondary">
<tr>
<th>순번</th>
<th>은행명</th>
<th>계좌 번호</th>
<th>비고</th>
<th>수정/삭제</th>
</tr>
</thead>
<tbody>
<?php if (!empty($cards)): ?>
<?php foreach ($cards as $i => $card): ?>
<tr>
<td><?= $i + 1 ?></td>
<td><?= htmlspecialchars($card["company"], ENT_QUOTES, 'UTF-8') ?></td>
<td><?= htmlspecialchars($card["number"], ENT_QUOTES, 'UTF-8') ?></td>
<td><?= htmlspecialchars($card["memo"], ENT_QUOTES, 'UTF-8') ?></td>
<td>
<button type="button" class="btn btn-sm btn-outline-primary editBtn" data-index="<?= $i ?>">수정</button>
<button type="button" class="btn btn-sm btn-outline-danger deleteBtn" data-index="<?= $i ?>">삭제</button>
</td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr><td colspan="5">등록된 계좌가 없습니다.</td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function(){
// 로딩 오버레이 제거
var loader = document.getElementById('loadingOverlay');
if(loader) loader.style.display = 'none';
$('.editBtn').on('click', function(){
var row = $(this).closest('tr');
var index = $(this).data('index');
var company = row.find('td:eq(1)').text().trim();
var number = row.find('td:eq(2)').text().trim();
var memo = row.find('td:eq(3)').text().trim();
$('#company').val(company);
$('#number').val(number);
$('#memo').val(memo);
$('#index').val(index);
$('#action').val('update');
$('#submitBtn').text('수정');
});
$('.deleteBtn').on('click', function(){
var index = $(this).data('index');
Swal.fire({
title: '계좌 삭제',
text: "정말 삭제하시겠습니까?",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: '삭제',
cancelButtonText: '취소'
}).then((result) => {
if (result.isConfirmed) {
$('#index').val(index);
$('#action').val('delete');
$('#addCardForm').submit();
}
});
});
});
</script>
<?php include $_SERVER['DOCUMENT_ROOT'] . '/common/modal.php'; ?>
</body>
</html>

737
account_juil/baddebt.php Normal file
View File

@@ -0,0 +1,737 @@
<?php
// 거래명세표 보여주는 코드 s_transaction.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;
}
include $_SERVER['DOCUMENT_ROOT'] . '/load_header.php';
// 첫 화면 표시 문구
$title_message = '악성 채권추심';
?>
<link href="css/style.css" rel="stylesheet">
<title> <?=$title_message?> </title>
<style>
/* 테이블에 테두리 추가 */
#myTable, #myTable th, #myTable td {
border: 1px solid black;
border-collapse: collapse;
}
/* 테이블 셀 패딩 조정 */
#myTable th, #myTable td {
padding: 8px;
text-align: center;
}
</style>
</head>
<body>
<?php require_once($_SERVER['DOCUMENT_ROOT'] . '/myheader1.php'); ?>
<?php
$search = isset($_REQUEST['search']) ? $_REQUEST['search'] : '';
$fromdate = isset($_REQUEST['fromdate']) ? $_REQUEST['fromdate'] : '';
$todate = isset($_REQUEST['todate']) ? $_REQUEST['todate'] : '';
$mode = isset($_REQUEST['mode']) ? $_REQUEST['mode'] : '';
// 현재 날짜
$currentDate = date("Y-m-d");
// fromdate 또는 todate가 빈 문자열이거나 null인 경우
if ($fromdate === "" || $fromdate === null || $todate === "" || $todate === null) {
// 현재 월의 1일을 fromdate로 설정
$fromdate = date("Y-m-01");
// // fromdate를 이전 달의 1일로 설정
// $fromdate = date("Y-m-01", strtotime("first day of -1 month"));
$todate = $currentDate;
$Transtodate = $todate;
} else {
$Transtodate = $todate;
}
// 시작일과 종료일을 "8월1일~9월1일" 형태로 포맷팅
$formatted_date_range = date("n월j일", strtotime($fromdate)) . '~' . date("n월j일", strtotime($todate));
function checkNull($strtmp) {
return $strtmp !== null && trim($strtmp) !== '';
}
$tablenamephonebook = 'phonebook';
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
// 이월잔액 계산을 위한 로직 (매출 - 수금)
$initialBalances = [];
// 이월 잔액을 계산할 기준 날짜
$lastMonthEnd = date("Y-m-d", strtotime($fromdate . " -1 day"));
// echo '<pre>';
// echo '이월잔액 기간 lastMonthEnd: ';
// print_r($lastMonthEnd);
// echo '</pre>';
$searchsecondordnum = '';
if(!empty($search))
{
$sql = "SELECT secondordnum FROM ".$DB.".".$tablenamephonebook."
WHERE (is_deleted IS NULL OR is_deleted = 0 or is_deleted ='' )
AND represent='대표코드' AND (vendor_name LIKE '%$search%')";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$searchsecondordnum = $row['secondordnum'];
}
// 거래처별 매출 및 수금 데이터 계산 (이월잔액)
$salesBeforeSql = "
SELECT o.secondordnum, SUM(COALESCE(e.ET_total, 0)) AS total_sales
FROM {$DB}.output o
LEFT JOIN {$DB}.output_extra e ON o.num = e.parent_num
WHERE o.outdate <= :lastMonthEnd AND (o.is_deleted IS NULL or o.is_deleted=0 or o.is_deleted ='')
GROUP BY o.secondordnum
";
$paymentBeforeSql = "
SELECT secondordnum, SUM(CAST(REPLACE(amount, ',', '') AS SIGNED)) AS total_payment
FROM {$DB}.account_juil
WHERE registDate <= :lastMonthEnd AND (is_deleted IS NULL or is_deleted=0 or is_deleted ='' ) AND content = '거래처 수금'
AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')
GROUP BY secondordnum
";
$salesBeforeStmt = $pdo->prepare($salesBeforeSql);
$salesBeforeStmt->execute([':lastMonthEnd' => $lastMonthEnd]);
$salesBeforeData = $salesBeforeStmt->fetchAll(PDO::FETCH_ASSOC);
$paymentBeforeStmt = $pdo->prepare($paymentBeforeSql);
$paymentBeforeStmt->execute([':lastMonthEnd' => $lastMonthEnd]);
$paymentBeforeData = $paymentBeforeStmt->fetchAll(PDO::FETCH_ASSOC);
// 거래처별로 매출과 수금을 비교해 이월 잔액을 계산
foreach ($salesBeforeData as $row) {
$secondordnum = $row['secondordnum'];
$total_sales = (float)$row['total_sales'];
if (!isset($initialBalances[$secondordnum])) {
$initialBalances[$secondordnum] = 0;
}
$initialBalances[$secondordnum] += $total_sales;
}
// echo '<pre>';
// print_r($initialBalances);
// echo '</pre>';
// 수금 데이터를 이용해 이월 잔액에서 수금을 차감
foreach ($paymentBeforeData as $row) {
$secondordnum = $row['secondordnum'];
$total_payment = (float)$row['total_payment'];
if (!isset($initialBalances[$secondordnum])) {
$initialBalances[$secondordnum] = 0;
}
$initialBalances[$secondordnum] -= $total_payment;
}
// echo '<pre>';
// print_r($initialBalances);
// echo '</pre>';
// 매출이 발생한 거래처 필터링 및 매출액 계산
$salesSql = "
SELECT o.secondordnum, COALESCE(e.ET_total, 0) as ET_total
FROM {$DB}.output o
LEFT JOIN {$DB}.output_extra e ON o.num = e.parent_num
WHERE (o.outdate BETWEEN date('$fromdate') AND date('$Transtodate'))
AND (o.is_deleted IS NULL OR o.is_deleted = 0 or o.is_deleted ='')
";
$salesStmt = $pdo->prepare($salesSql);
$salesStmt->execute();
$salesData = $salesStmt->fetchAll(PDO::FETCH_ASSOC);
$salesResults = [];
foreach ($salesData as $row) {
$secondordnum = $row['secondordnum'];
$total_sales = (float)$row['ET_total'];
if (!isset($salesResults[$secondordnum])) {
$salesResults[$secondordnum] = 0;
}
$salesResults[$secondordnum] += $total_sales;
}
// echo '<pre>';
// echo '매출발생 시작 fromdate: ';
// print_r($fromdate);
// echo '</pre>';
// echo '<pre>';
// echo '매출발생 종료 Transtodate: ';
// print_r($Transtodate);
// echo '</pre>';
// echo '<pre>';
// echo '이월잔액배열 디오이엔시 추적 initialBalances: ';
// print_r($initialBalances['56']);
// echo '</pre>';
// 모든 거래처 목록을 처리하기 전에 거래처 이름을 저장하는 배열 초기화
$vendorNames = [];
// 모든 거래처 목록을 생성 (매출, 기초채권)
$allResults = array_unique(array_merge(array_keys($salesResults), array_keys($initialBalances)));
// 매출 금액 기준으로 역순으로 정렬
usort($allResults, function($a, $b) use ($salesResults) {
$salesA = isset($salesResults[$a]) ? $salesResults[$a] : 0;
$salesB = isset($salesResults[$b]) ? $salesResults[$b] : 0;
return round($salesA - $salesB);
});
// 합계를 저장할 변수들
$totalInitialReceivable = 0;
$totalSalesAmount = 0;
$totalPaymentAmount = 0;
$totalBalanceDue = 0;
try {
$start_num = 1;
foreach ($allResults as $ordnum) {
// 이월 잔액 설정
$initialReceivable = isset($initialBalances[$ordnum]) ? $initialBalances[$ordnum] : 0;
// 수금 내역 가져오기
$paymentSql = "SELECT SUM(CAST(REPLACE(amount, ',', '') AS SIGNED)) as total_payment
FROM ".$DB.".account_juil
WHERE secondordnum = '$ordnum'
AND registDate BETWEEN '1970-01-01' AND date('$Transtodate')
AND (is_deleted IS NULL OR is_deleted = 0 or is_deleted ='' )
AND content = '거래처 수금'
AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')";
$paymentStmt = $pdo->prepare($paymentSql);
$paymentStmt->execute();
$paymentData = $paymentStmt->fetch(PDO::FETCH_ASSOC);
$total_payment = isset($paymentData['total_payment']) ? (int)str_replace(',', '', $paymentData['total_payment']) : 0;
$total_sales = isset($salesResults[$ordnum]) ? $salesResults[$ordnum] : 0;
// 조건: 기초채권이 있거나 매출이 있는 경우만 표시
if ($initialReceivable != 0 || $total_sales != 0 ) { // 매출이 있는 것을 추출
$sql = "SELECT * FROM $DB.$tablenamephonebook
WHERE secondordnum = '$ordnum'
AND (is_deleted IS NULL OR is_deleted = 0 or is_deleted ='' )
AND represent='대표코드'";
$stmh = $pdo->query($sql);
while ($row = $stmh->fetch(PDO::FETCH_ASSOC)) {
include $_SERVER['DOCUMENT_ROOT'] . '/phonebook/_row.php';
if (intval($ordnum) > 0)
{
$savenum = $ordnum;
// 거래처 이름 저장
$vendorNames[$ordnum] =$vendor_name ;
}
else
$savenum = $num;
$total_amount = round($total_sales ) ;
// 잔액 계산
$balance_due = round($initialReceivable) + $total_amount - round($total_payment);
$totalInitialReceivable += $initialReceivable;
$totalSalesAmount += $total_amount;
$totalPaymentAmount += $total_payment;
$totalBalanceDue += $balance_due;
}
}
}
} catch (PDOException $Exception) {
print "오류: ".$Exception->getMessage();
}
// echo '<pre>';
// print_r($vendorNames);
// echo '</pre>';
// 거래처 이름으로 정렬
usort($allResults, function($a, $b) use ($vendorNames) {
// 거래처 이름이 없는 경우 빈 문자열로 처리
$nameA = $vendorNames[$a] ?? '';
$nameB = $vendorNames[$b] ?? '';
return strcmp($nameA, $nameB);
});
// echo $sql;
// echo '<pre>';
// print_r($allResults);
// echo '</pre>';
// $search값이 있다면 // 특정 숫자 67만 남기고 필터링
// echo 'searchsecondordnum : ' . $searchsecondordnum;
if (!empty($search)) {
$allResults = array_filter($allResults, function ($value) use ($searchsecondordnum) {
return $value === intval($searchsecondordnum);
});
// array_values로 인덱스 재정렬
$allResults = array_values($allResults);
}
// 중복 제거
$allResults = array_unique($allResults);
// 중복 제거
$allResults = array_unique($allResults);
// 빈 값 제거
$allResults = array_filter($allResults, function ($value) {
return $value !== null && $value !== '';
});
// 배열 키 재정렬
$allResults = array_values($allResults);
// echo '<pre>';
// print_r($allResults);
// echo '</pre>';
?>
<form id="board_form" name="board_form" method="post" enctype="multipart/form-data">
<div class="container mb-5">
<input type="hidden" id="mode" name="mode" value="<?=$mode?>">
<input type="hidden" id="num" name="num">
<input type="hidden" id="tablename" name="tablename" value="<?=$tablenamephonebook?>">
<input type="hidden" id="header" name="header" value="<?=$header?>">
<input type="hidden" id="secondordnum" name="secondordnum" value="<?=$secondordnum?>">
<div class="card justify-content-center text-center mt-5">
<div class="card-header">
<div class="d-flex p-1 m-1 mt-1 mb-1 justify-content-center align-items-center">
<span class="text-center text-danger fs-5 me-4"> <i class="bi bi-exclamation-octagon-fill text-danger"></i> <?=$title_message?></span>
<button type="button" class="btn btn-dark btn-sm mx-3" onclick='location.reload();' title="새로고침"> <i class="bi bi-arrow-clockwise"></i> </button>
<!-- <span class="badge bg-primary"> (한빛에스티) 매월25일 마감 </span> -->
</div>
</div>
<div class="card-body">
<div class="d-flex p-1 m-1 mt-1 mb-1 justify-content-center align-items-center">
▷ <span id="total"> </span> &nbsp;
<!-- 기간부터 검색까지 연결 묶음 start -->
<button type="button" class="btn btn-outline-dark btn-sm me-1 change_dateRange" onclick='alldatesearch()'>전체</button>
<span id="showdate" class="btn btn-dark btn-sm">기간</span> &nbsp;
<div id="showframe" class="card" style="width:300px;">
<div class="card-header" style="padding:2px;">
<div class="d-flex justify-content-center align-items-center">
기간 설정
</div>
</div>
<div class="card-body">
<div class="d-flex justify-content-center align-items-center">
<button type="button" class="btn btn-dark btn-sm me-1 change_dateRange" onclick='prepre_month()'>전전월</button>
<button type="button" class="btn btn-dark btn-sm me-1 change_dateRange" onclick='pre_month()'>전월</button>
<button type="button" class="btn btn-dark btn-sm me-1 change_dateRange" onclick='this_month()'>당월</button>
<button type="button" class="btn btn-dark btn-sm me-1 change_dateRange" onclick='this_year()'>당해년도</button>
</div>
</div>
</div>
<input type="date" id="fromdate" name="fromdate" class="form-control" style="width:100px;" value="<?=$fromdate?>"> &nbsp; ~ &nbsp;
<input type="date" id="todate" name="todate" class="form-control me-1" style="width:100px;" value="<?=$todate?>"> &nbsp; </span>
<div class="inputWrap">
<input type="text" id="search" name="search" value="<?=$search?>" onkeydown="if(event.key === 'Enter') submitForm();" autocomplete="off" class="form-control" style="width:150px;"> &nbsp;
<button class="btnClear"></button>
</div>
<div id="autocomplete-list">
</div>
&nbsp;
<button id="searchBtn" type="button" class="btn btn-dark btn-sm me-2" onclick="submitForm()"> <i class="bi bi-search"></i> </button>
</div>
</div>
</div>
<div class="card justify-content-center text-center mt-5">
<div class="card-body">
<div class="d-flex p-1 m-1 mb-1 justify-content-center align-items-center">
<table class="table table-hover" id="myTable">
<thead class="table-info">
<th class="text-center w80px">번호</th>
<th class="text-center w200px">거래처명</th>
<th class="text-center w140px">이월잔액</th>
<th class="text-center w140px"> 매출</th>
<th class="text-center w140px">수금</th>
<th class="text-center w140px">잔액</th>
<th class="text-center w60px">결제일</th>
<th class="text-center w140px">적요</th>
<?php if($user_id == 'pro')
print '<th class="text-center w50px">거래처 Code</th>';
?>
<th style="display:none;" ></th>
</thead>
<tbody>
<?php
try {
$start_num = 1;
foreach ($allResults as $initnum) {
// echo 'second ord num '. $initnum . '<br>';
// 이월잔액 설정
$initialReceivable = isset($initialBalances[$initnum]) ? intval($initialBalances[$initnum]) : 0;
// 마지막 자릿수가 1인지 확인
if (floatval($initialReceivable) % 10 === 1) {
// 마지막 자릿수를 제거 (정수로 처리)
$initialReceivable = floor($initialReceivable / 10);
}
// echo '거래처 $initnum' . $initnum . ' : ', $initialReceivable . ' <br> ' ;
// 수금 내역 가져오기
$paymentSql = "SELECT SUM(CAST(REPLACE(amount, ',', '') AS SIGNED)) as total_payment
FROM $DB.account_juil
WHERE secondordnum = '$initnum'
AND registDate BETWEEN date('$fromdate') AND date('$Transtodate')
AND (is_deleted IS NULL OR is_deleted = 0 or is_deleted ='' )
AND content = '거래처 수금'
AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')";
$paymentStmt = $pdo->prepare($paymentSql);
$paymentStmt->execute();
$paymentData = $paymentStmt->fetch(PDO::FETCH_ASSOC);
$total_payment = isset($paymentData['total_payment']) ? (int)str_replace(',', '', $paymentData['total_payment']) : 0;
$total_sales = isset($salesResults[$initnum]) ? $salesResults[$initnum] : 0;
// print $total_sales;
// 조건: 이월잔액이 있거나 매출이 있는 경우만 표시
// 검색어가 있는 경우 검색어 있는 것만 나오게 함
// echo 'searchsecondordnum : ' . $searchsecondordnum;
if ( ($initialReceivable != 0 or $total_sales != 0) and intval($initnum) > 1 ) {
$sql = "SELECT * FROM $DB.$tablenamephonebook
WHERE secondordnum = '$initnum'
AND (is_deleted IS NULL OR is_deleted = 0 or is_deleted ='' )
AND represent='대표코드'";
$total_amount = round($total_sales,2);
// 잔액 계산
$balance_due = $initialReceivable + $total_amount - $total_payment;
$memo = '';
// if($balance_due>0 && $initialReceivable>0 )
// (주)한빛에스티는 25일 마감 예외처리해야함.
// if($vendor_name === '㈜ 한빛에스티')
// $vendor_name = '㈜ 한빛에스티(월마감25일)';
// 마지막 단위 원단위 중 1은 제거하는 로직
// 당월매출 마지막 1원 삭제
// 마지막 자리가 1로 끝나는 경우, 0으로 변경
// print_r($total_payment);
// $totalSalesAmount -= 5;
if (round($total_amount,2) % 10 === 1) {
$total_amount -= 1; // 1을 빼서 마지막 자리를 0으로 만듭니다.
}
if ($balance_due % 10 === 1) {
$balance_due -= 1; // 1을 빼서 마지막 자리를 0으로 만듭니다.
}
// print_r($balance_due);
if (intval($balance_due) !== 0 || $total_sales > 0 ) {
?>
<tr onclick="redirectToView('<?= $initnum ?>')">
<td class="text-center"><?= $start_num ?></td>
<td class="text-start text-primary"><?= $vendorNames[$initnum] ?></td>
<td class="text-end text-primary fw-bold"><?= number_format($initialReceivable) ?></td>
<td class="text-end text-secondary fw-bold"><?= number_format($total_amount) ?></td>
<td class="text-end fw-bold"><?= number_format($total_payment) ?></td>
<td class="text-end fw-bold"><?= number_format($balance_due) ?></td>
<td class="text-end text-primary fw-bold">
<?php if (!empty($paydate)) : ?>
<?= htmlspecialchars($paydate) ?>
<?php endif; ?>
</td>
<td class="text-end"><?= $memo ?></td>
<?php if($user_id == 'pro')
echo '<td class="text-center w50px"> ' . $initnum . ' </td>';
?>
<td style="display:none;"><?= $initnum ?></td>
</tr>
<?php
$start_num++;
}
}
}
?>
</tbody>
<tfoot class="table-secondary">
<tr>
<th class="text-end w80px" colspan="2"> 합계 &nbsp; </th>
<th class="text-end"><?= number_format($totalInitialReceivable) ?></th>
<th class="text-end"><?= number_format($totalSalesAmount) ?></th>
<th class="text-end"><?= number_format($totalPaymentAmount) ?></th>
<th class="text-end"><?= number_format($totalBalanceDue) ?></th>
<th class="text-end">&nbsp; </th>
<th class="text-end w150px">&nbsp; </th>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
</form>
<?php
} catch (PDOException $Exception) {
print "오류: ".$Exception->getMessage();
}
?>
<!-- 페이지로딩 -->
<script>
$(document).ready(function(){
var loader = document.getElementById('loadingOverlay');
loader.style.display = 'none';
});
function submitForm() {
$('#board_form').submit();
}
</script>
<script>
var dataTable; // DataTables 인스턴스 전역 변수
var bookpageNumber; // 현재 페이지 번호 저장을 위한 전역 변수
$(document).ready(function() {
// DataTables 초기 설정
dataTable = $('#myTable').DataTable({
"paging": true,
"ordering": true,
"searching": true,
"pageLength": 100,
"lengthMenu": [100, 200, 500, 1000],
"language": {
"lengthMenu": "Show _MENU_ entries",
"search": "Live Search:"
},
// "order": [[8, 'desc']], // 잔액기준 내림차순 정렬
"dom": 't<"bottom"ip>', // search 창과 lengthMenu 숨기기
"footerCallback": function ( row, data, start, end, display ) {
var api = this.api(), data;
// 합계를 계산하는 함수
var intVal = function (i) {
return typeof i === 'string' ?
i.replace(/[\$,]/g, '')*1 :
typeof i === 'number' ?
i : 0;
};
// 합계 계산
totalInitialReceivable = api.column(2).data().reduce(function (a, b) { return intVal(a) + intVal(b); }, 0);
totalSalesAmount = api.column(3).data().reduce(function (a, b) { return intVal(a) + intVal(b); }, 0);
totalPaymentAmount = api.column(4).data().reduce(function (a, b) { return intVal(a) + intVal(b); }, 0);
totalBalanceDue = api.column(5).data().reduce(function (a, b) { return intVal(a) + intVal(b); }, 0);
// 합계 출력
$(api.column(2).footer()).html(numberWithCommas(totalInitialReceivable));
$(api.column(3).footer()).html(numberWithCommas(totalSalesAmount));
$(api.column(4).footer()).html(numberWithCommas(totalPaymentAmount));
$(api.column(5).footer()).html(numberWithCommas(totalBalanceDue));
}
});
// 페이지 번호 복원 (초기 로드 시)
var savedPageNumber = getCookie('bookpageNumber');
if (savedPageNumber) {
dataTable.page(parseInt(savedPageNumber) - 1).draw(false);
}
// 페이지 변경 이벤트 리스너
dataTable.on('page.dt', function() {
var bookpageNumber = dataTable.page.info().page + 1;
setCookie('bookpageNumber', bookpageNumber, 10); // 쿠키에 페이지 번호 저장
});
// 페이지 길이 셀렉트 박스 변경 이벤트 처리
$('#myTable_length select').on('change', function() {
var selectedValue = $(this).val();
dataTable.page.len(selectedValue).draw(); // 페이지 길이 변경 (DataTable 파괴 및 재초기화 없이)
// 변경 후 현재 페이지 번호 복원
savedPageNumber = getCookie('bookpageNumber');
if (savedPageNumber) {
dataTable.page(parseInt(savedPageNumber) - 1).draw(false);
}
});
var total = '<?php echo $start_num; ?>';
$("#total").text(Number(total)-1);
});
function redirectToView(num) {
var fromdate = document.getElementById('fromdate').value;
var todate = document.getElementById('todate').value;
var url = "../account_juil/S_transaction_sheet.php?num=" + num + "&fromdate=" + fromdate + "&todate=" + todate;
customPopup(url, '거래원장', 1000, 850);
}
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
function saveBalance() {
// 테이블 데이터를 수집
let data = [];
let closure_date = $('#todate').val();
let year = closure_date.split('-')[0];
let month = closure_date.split('-')[1];
let dayOfMonth = parseInt(closure_date.split('-')[2]);
// 해당 월의 마지막 날 계산
let lastDayOfMonth = new Date(year, month, 0).getDate();
// 날짜가 말일 또는 25일이 아닌 경우 경고 메시지 출력
if (dayOfMonth !== lastDayOfMonth && dayOfMonth !== 25) {
alert('해당일자로 이월 마감할 수 없습니다.');
return; // 함수 종료
}
$('#myTable tbody tr').each(function() {
let row = $(this);
let balance = parseFloat(row.find('td:nth-child(6)').text().replace(/,/g, ''));
let secondordnum = row.find('td:nth-child(9)').text().trim();
// 매월 말일인 경우
if (dayOfMonth === lastDayOfMonth) {
// '66'이 아닌 데이터만 처리
if (secondordnum !== '66' && balance !== 0) {
data.push({
mode: row.attr('data-mode') || 'insert', // insert or update mode
num: row.attr('data-num'),
secondordnum: secondordnum,
customer_name: row.find('td:nth-child(2)').text().trim(),
balance: balance,
closure_date: closure_date,
memo: row.find('td:nth-child(8)').text().trim()
});
}
}
// 25일인 경우
else if (dayOfMonth === 25) {
// '66' 데이터만 처리
if (secondordnum === '66' && balance !== 0) {
data.push({
mode: row.attr('data-mode') || 'insert', // insert or update mode
num: row.attr('data-num'),
secondordnum: secondordnum,
customer_name: row.find('td:nth-child(2)').text().trim(),
balance: balance,
closure_date: closure_date,
memo: row.find('td:nth-child(8)').text().trim()
});
}
}
});
// Ajax로 데이터 전송
if (data.length > 0) {
$.ajax({
url: 'insert_monthly_balance.php',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(data),
success: function(response) {
let result = JSON.parse(response);
if (result.status === 'success') {
alert('이월금액이 성공적으로 저장되었습니다.');
} else {
alert('오류 발생: ' + result.message);
}
},
error: function(xhr, status, error) {
alert('오류 발생: ' + error);
}
});
} else {
alert('저장할 데이터가 없습니다.');
}
}
function detail() {
// 년도, 시작 월, 종료 월 값을 가져옴
const year = document.getElementById('year').value;
const startMonth = document.getElementById('startMonth').value;
const endMonth = document.getElementById('endMonth').value;
// detail.php로 이동할 URL 생성
const url = `detail.php?year=${year}&startMonth=${startMonth}&endMonth=${endMonth}`;
// customPopup을 사용하여 detail.php를 팝업으로 열기
customPopup(url, '상세 내역', 900, 700);
}
function generateExcel() {
var table = document.getElementById('myTable');
var rows = table.getElementsByTagName('tr');
var data = [];
// 각 행을 반복하여 데이터 수집
for (var i = 1; i < rows.length; i++) { // 헤더 행을 건너뜀
var cells = rows[i].getElementsByTagName('td');
var rowData = {};
rowData['number'] = cells[0]?.innerText || '';
rowData['secondord'] = cells[1]?.innerText || '';
rowData['lastbalance'] = cells[2]?.innerText || '';
rowData['monthsales'] = cells[3]?.innerText || '';
rowData['income'] = cells[4]?.innerText || '';
rowData['balances'] = cells[5]?.innerText || '';
rowData['payday'] = cells[6]?.innerText || '';
rowData['memo'] = cells[7]?.innerText || '';
rowData['secondordnum'] = cells[8]?.innerText || '';
data.push(rowData);
}
// saveExcel.php에 데이터 전송
var xhr = new XMLHttpRequest();
xhr.open("POST", "customer_saveExcel.php", true);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
try {
var response = JSON.parse(xhr.responseText);
if (response.success) {
console.log('Excel file generated successfully.');
// 다운로드 스크립트로 리디렉션
window.location.href = 'downloadExcel.php?filename=' + encodeURIComponent(response.filename.split('/').pop());
} else {
console.log('Failed to generate Excel file: ' + response.message);
}
} catch (e) {
console.log('Error parsing response: ' + e.message + '\nResponse text: ' + xhr.responseText);
}
} else {
console.log('Failed to generate Excel file: Server returned status ' + xhr.status);
}
}
};
xhr.send(JSON.stringify(data));
}
$(document).ready(function(){
saveLogData('경동기업 악성채권');
});
</script>
</body>
</html>

View File

@@ -0,0 +1,47 @@
[
{
"company": "국민카드",
"number": "5585-2697-8607-8835",
"user": "윤희재"
},
{
"company": "국민카드",
"number": "5585-2694-1183-1830",
"user": "유민수"
},
{
"company": "국민카드",
"number": "5585-2694-6309-9823",
"user": "계도건"
},
{
"company": "국민카드",
"number": "5585-2694-3595-6811",
"user": "신승표"
},
{
"company": "신한카드",
"number": "9410-6441-0601-4244",
"user": "사무실"
},
{
"company": "신한카드",
"number": "4902-9841-1316-7973",
"user": "김영민"
},
{
"company": "신한카드",
"number": "3779-8508-1047-026",
"user": "쿠팡"
},
{
"company": "국민카드",
"number": "5585-2694-1183-1830",
"user": "이성제"
},
{
"company": "국민카드",
"number": "5585-2694-6309-9823",
"user": "이성제"
}
]

170
account_juil/cardlist.php Normal file
View File

@@ -0,0 +1,170 @@
<?php
// cardlist.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;
}
include $_SERVER['DOCUMENT_ROOT'] . '/load_header.php';
$title_message = '법인카드 관리';
?>
<title><?= $title_message ?></title>
<?php if($chkMobile==true) { ?>
<style>
@media (max-width: 1000px) {
body { font-size: 25px; }
.form-control, .fw-bold, .table td, .table th { font-size: 25px; }
button { font-size: 30px; }
.modal-body, .modal-title { font-size: 30px; }
}
</style>
<?php } ?>
</head>
<body>
<?php
// 메뉴를 표현할지 판단하는 header
$header = $_REQUEST['header'] ?? '';
if($user_id === '0266771300' ) {
require_once($_SERVER['DOCUMENT_ROOT'] . '/myheader_accountant1.php'); // 경리
} else {
require_once($_SERVER['DOCUMENT_ROOT'] . '/myheader1.php');
}
$jsonFile = $_SERVER['DOCUMENT_ROOT'] . '/account_juil/cardlist.json';
$cards = [];
if (file_exists($jsonFile)) {
$jsonContent = file_get_contents($jsonFile);
$cards = json_decode($jsonContent, true);
if (!is_array($cards)) {
$cards = [];
}
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
$index = isset($_POST['index']) ? intval($_POST['index']) : -1;
$company = trim($_POST['company'] ?? '');
$number = trim($_POST['number'] ?? '');
$user = trim($_POST['user'] ?? '');
if ($action === 'insert' && $company !== '' && $number !== '') {
$cards[] = [
"company" => $company,
"number" => $number,
"user" => $user
];
} elseif ($action === 'update' && $index >= 0 && $index < count($cards)) {
$cards[$index]["company"] = $company;
$cards[$index]["number"] = $number;
$cards[$index]["user"] = $user;
} elseif ($action === 'delete' && $index >= 0 && $index < count($cards)) {
array_splice($cards, $index, 1);
}
file_put_contents($jsonFile, json_encode($cards, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
}
?>
<div class="container mt-3">
<div class="card">
<div class="card-header d-flex justify-content-center align-items-center text-center">
<h3 class="mb-0"><?= $title_message ?></h3> <br>
<small class="ms-5 text-muted">카드회사, 카드번호, 사용자 정보를 넣고 등록 버튼을 누르시면 등록됩니다.</small>
</div>
<div class="card-body">
<form id="addCardForm" method="post" action="cardlist.php" class="row g-3 mb-3">
<input type="hidden" name="action" id="action" value="insert">
<input type="hidden" name="index" id="index" value="-1">
<div class="d-flex justify-content-center align-items-center text-center">
<input type="text" name="company" id="company" class="form-control mx-1" placeholder="카드 회사" autocomplete="off" style="width:150px;">
<input type="text" name="number" id="number" class="form-control mx-1" placeholder="카드 번호" autocomplete="off" style="width:200px;">
<input type="text" name="user" id="user" class="form-control mx-1" placeholder="사용자" autocomplete="off" style="width:120px;">
<button type="submit" class="btn btn-primary btn-sm mx-1" id="submitBtn">등록</button>
</div>
</form>
<div class="table-responsive">
<table class="table table-bordered table-hover text-center">
<thead class="table-secondary">
<tr>
<th>순번</th>
<th>카드 회사</th>
<th>카드 번호</th>
<th>사용자</th>
<th>수정/삭제</th>
</tr>
</thead>
<tbody>
<?php if (!empty($cards)): ?>
<?php foreach ($cards as $i => $card): ?>
<tr>
<td><?= $i + 1 ?></td>
<td><?= htmlspecialchars($card["company"], ENT_QUOTES, 'UTF-8') ?></td>
<td><?= htmlspecialchars($card["number"], ENT_QUOTES, 'UTF-8') ?></td>
<td><?= htmlspecialchars($card["user"], ENT_QUOTES, 'UTF-8') ?></td>
<td>
<button type="button" class="btn btn-sm btn-outline-primary editBtn" data-index="<?= $i ?>">수정</button>
<button type="button" class="btn btn-sm btn-outline-danger deleteBtn" data-index="<?= $i ?>">삭제</button>
</td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr><td colspan="5">등록된 카드가 없습니다.</td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function(){
// 로딩 오버레이 제거
var loader = document.getElementById('loadingOverlay');
if(loader) loader.style.display = 'none';
$('.editBtn').on('click', function(){
var row = $(this).closest('tr');
var index = $(this).data('index');
var company = row.find('td:eq(1)').text().trim();
var number = row.find('td:eq(2)').text().trim();
var user = row.find('td:eq(3)').text().trim();
$('#company').val(company);
$('#number').val(number);
$('#user').val(user);
$('#index').val(index);
$('#action').val('update');
$('#submitBtn').text('수정');
});
$('.deleteBtn').on('click', function(){
var index = $(this).data('index');
Swal.fire({
title: '카드 삭제',
text: "정말 삭제하시겠습니까?",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: '삭제',
cancelButtonText: '취소'
}).then((result) => {
if (result.isConfirmed) {
$('#index').val(index);
$('#action').val('delete');
$('#addCardForm').submit();
}
});
});
});
</script>
<?php include $_SERVER['DOCUMENT_ROOT'] . '/common/modal.php'; ?>
</body>
</html>

135
account_juil/css/style.css Normal file
View File

@@ -0,0 +1,135 @@
#openModalBtn {
padding: 10px 20px;
font-size: 16px;
}
.modal {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: hidden; /* Changed from 'auto' to 'hidden' to prevent closing on outside click */
background-color: rgba(0, 0, 0, 0.4);
padding-top: 80px;
}
.modal-content {
background-color: #fefefe;
margin: auto;
border-radius: 10px;
width: 95%;
max-width: 1200px;
animation: fadeIn 0.5s;
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.modal-header {
background-color: #1f48d4;
color: white;
padding: 10px;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
display: flex;
justify-content: space-between;
align-items: center;
}
.modal-title {
font-size: 18px;
}
.close {
color: white;
font-size: 18px;
font-weight: bold;
cursor: pointer;
}
.close:hover,
.close:focus {
color: #bbb;
text-decoration: none;
}
.modal-body {
padding: 10px;
}
.custom-card {
background-color: #f9f9f9;
padding: 15px;
border: 1px solid #ddd;
border-radius: 5px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.tooltip-inner {
background-color: black !important; /* 배경색 */
color: white !important; /* 글자색 */
}
.tooltip-arrow {
color: black !important; /* 화살표 색상 */
}
/* 입력창에 대한 설계 */
.ui-autocomplete {
max-height: 500px;
overflow-y: auto;
overflow-x: hidden;
}
.specialinputWrap {
position: relative;
display: inline-block;
width:100%;
}
.specialbtnClear {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
background: transparent;
border: none;
color: black;
cursor: pointer;
}
.specialbtnClear:before {
content: 'X';
font-size: 12px;
}
.specialbtnClear:hover {
color: black;
}
.btnClear_lot {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
background: transparent;
border: none;
color: black;
cursor: pointer;
}
.btnClear_lot:before {
content: 'X';
font-size: 12px;
}
.btnClear_lot:hover {
color: black;
}

View File

@@ -0,0 +1,124 @@
<?php
// 에러 표시 설정
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
header('Content-Type: application/json'); // JSON 응답 설정
$response = ['success' => false, 'message' => 'Unknown error'];
try {
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// 요청에서 JSON 데이터 가져오기
$data = json_decode(file_get_contents('php://input'), true);
// JSON 오류 확인
if (json_last_error() !== JSON_ERROR_NONE) {
throw new Exception('Invalid JSON input: ' . json_last_error_msg());
}
// 데이터가 비어있는지 확인
if (empty($data)) {
throw new Exception('No data received');
}
// PHPExcel 라이브러리 포함
require '../PHPExcel_1.8.0/Classes/PHPExcel.php';
// 새로운 PHPExcel 객체 생성
$objPHPExcel = new PHPExcel();
$objPHPExcel->setActiveSheetIndex(0);
$sheet = $objPHPExcel->getActiveSheet();
// 헤더 설정
$headers = [
'number' => '번호',
'secondord' => '거래처명',
'lastbalance' => '이월잔액',
'monthsales' => '당월매출',
'income' => '수금합계',
'balances' => '잔액',
'payday' => '결제일',
'memo' => '적요',
'secondordnum' => '거래처코드'
];
// 헤더를 엑셀에 추가
$col = 'A';
foreach ($headers as $header) {
$sheet->setCellValue($col . '1', $header);
// 셀의 글씨를 굵게 하고 음영을 추가
$sheet->getStyle($col . '1')->getFont()->setBold(true);
$sheet->getStyle($col . '1')->getFill()->setFillType(PHPExcel_Style_Fill::FILL_SOLID);
$sheet->getStyle($col . '1')->getFill()->getStartColor()->setRGB('D9D9D9');
$col++;
}
// 데이터 채우기
$rowNumber = 2;
foreach ($data as $row) {
$col = 'A';
foreach ($headers as $key => $header) {
$value = isset($row[$key]) ? $row[$key] : ''; // 데이터가 있으면 채우고 없으면 공백
$sheet->setCellValue($col . $rowNumber, $value);
$col++;
}
$rowNumber++;
}
// 특정 열의 기본 폭 설정
$sheet->getColumnDimension('B')->setWidth(40);
// 나머지 열의 폭을 글씨에 맞추기
foreach (range('A', 'I') as $columnID) {
if (!in_array($columnID, ['B'])) {
$sheet->getColumnDimension($columnID)->setWidth(25);
}
}
// 테두리 설정
$styleArray = [
'borders' => [
'allborders' => [
'style' => PHPExcel_Style_Border::BORDER_THIN,
],
],
];
$sheet->getStyle('A1:I' . ($rowNumber - 1))->applyFromArray($styleArray);
// 열별 정렬 설정
$sheet->getStyle('E2:E' . ($rowNumber - 1))
->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_RIGHT);
$sheet->getStyle('F2:F' . ($rowNumber - 1))
->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_RIGHT);
$sheet->getStyle('G2:G' . ($rowNumber - 1))
->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_RIGHT);
$sheet->getStyle('H2:H' . ($rowNumber - 1))
->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
// 파일 저장
$filename = 'DH모터(거래처원장)_' . date('YmdHis') . '.xlsx';
$filePath = '../excelsave/' . $filename; // 파일 경로 확인 필요
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
$objWriter->save($filePath);
// 파일이 생성되었는지 확인
if (file_exists($filePath)) {
$response = ['success' => true, 'filename' => $filePath];
} else {
throw new Exception('Failed to save the Excel file');
}
} else {
throw new Exception('Invalid request method');
}
} catch (Exception $e) {
error_log($e->getMessage()); // 오류 로그 기록
$response = ['success' => false, 'message' => $e->getMessage()];
}
// JSON 응답 반환
echo json_encode($response);
?>

195
account_juil/detail.php Normal file
View File

@@ -0,0 +1,195 @@
<?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;
}
include $_SERVER['DOCUMENT_ROOT'] . '/load_header.php';
$title_message = '상세 내역 조회';
?>
<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: 8px;
text-align: center;
}
</style>
</head>
<body>
<?php
$year = isset($_REQUEST['year']) ? $_REQUEST['year'] : date('Y');
$startMonth = isset($_REQUEST['startMonth']) ? $_REQUEST['startMonth'] : 1;
$endMonth = isset($_REQUEST['endMonth']) ? $_REQUEST['endMonth'] : date('m');
$startDate = "$year-$startMonth-01";
$endDate = date("Y-m-t", strtotime("$year-$endMonth-01"));
$tablename = 'account_juil';
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
// 수입 내역 조회
$incomeSql = "
SELECT content, SUM(amount) as totalAmount
FROM $tablename
WHERE inoutsep = '수입'
AND registDate BETWEEN :startDate AND :endDate
AND is_deleted = '0'
GROUP BY content
";
$incomeStmt = $pdo->prepare($incomeSql);
$incomeStmt->bindParam(':startDate', $startDate);
$incomeStmt->bindParam(':endDate', $endDate);
$incomeStmt->execute();
$incomeData = $incomeStmt->fetchAll(PDO::FETCH_ASSOC);
// 지출 내역 조회
$expenseSql = "
SELECT content, SUM(amount) as totalAmount
FROM $tablename
WHERE inoutsep = '지출'
AND registDate BETWEEN :startDate AND :endDate
AND is_deleted = '0'
GROUP BY content
";
$expenseStmt = $pdo->prepare($expenseSql);
$expenseStmt->bindParam(':startDate', $startDate);
$expenseStmt->bindParam(':endDate', $endDate);
$expenseStmt->execute();
$expenseData = $expenseStmt->fetchAll(PDO::FETCH_ASSOC);
// 월수익 계산
$totalIncome = array_sum(array_column($incomeData, 'totalAmount'));
$totalExpense = array_sum(array_column($expenseData, 'totalAmount'));
$netIncome = $totalIncome - $totalExpense;
?>
<div class="container mt-5">
<div class="card">
<div class="card-header">
<h5 class="text-center"><?=$title_message?></h5>
</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" onchange="loadDetails()">
<?php for ($i = date('Y'); $i >= 2024; $i--): ?>
<option value="<?=$i?>" <?=($year == $i) ? 'selected' : ''?>><?=$i?>년</option>
<?php endfor; ?>
</select>
<select id="startMonth" name="startMonth" class="form-select w-auto me-1" onchange="loadDetails()">
<?php for ($i = 1; $i <= 12; $i++): ?>
<option value="<?=$i?>" <?=($startMonth == $i) ? 'selected' : ''?>><?=$i?>월</option>
<?php endfor; ?>
</select>
~ &nbsp;
<select id="endMonth" name="endMonth" class="form-select w-auto me-5 " onchange="loadDetails()">
<?php for ($i = 1; $i <= 12; $i++): ?>
<option value="<?=$i?>" <?=($endMonth == $i) ? 'selected' : ''?>><?=$i?>월</option>
<?php endfor; ?>
</select>
</div>
</div>
<div class="row mb-3">
<div class="d-flex justify-content-center">
<?php for ($i = 1; $i <= 12; $i++): ?>
<button class="btn btn-outline-primary btn-sm me-1" onclick="loadSpecificMonth('<?=$i?>')">
<?=$i?>월
</button>
<?php endfor; ?>
</div>
</div>
<table class="table table-hover" id="detailTable">
<thead class="table-info">
<tr>
<th colspan="2" class="text-center">수입</th>
<th colspan="2" class="text-center">지출</th>
</tr>
<tr>
<th class="text-center">항목</th>
<th class="text-center">금액</th>
<th class="text-center">항목</th>
<th class="text-center">금액</th>
</tr>
</thead>
<tbody>
<?php
$maxRows = max(count($incomeData), count($expenseData));
for ($i = 0; $i < $maxRows; $i++):
$incomeContent = isset($incomeData[$i]) ? $incomeData[$i]['content'] : '';
$incomeAmount = isset($incomeData[$i]) ? number_format($incomeData[$i]['totalAmount']) : '';
$expenseContent = isset($expenseData[$i]) ? $expenseData[$i]['content'] : '';
$expenseAmount = isset($expenseData[$i]) ? number_format($expenseData[$i]['totalAmount']) : '';
?>
<tr>
<td class="text-center"><?=$incomeContent?></td>
<td class="text-end text-primary"><?=$incomeAmount?></td>
<td class="text-center"><?=$expenseContent?></td>
<td class="text-end text-danger"><?=$expenseAmount?></td>
</tr>
<?php endfor; ?>
</tbody>
<tfoot class="table-secondary">
<tr>
<th class="text-end" > 수입 합계 &nbsp; </th>
<th class="text-end text-primary"><?=number_format($totalIncome)?></th>
<th class="text-end"> 지출 합계 &nbsp; </th>
<th class="text-end text-danger"><?=number_format($totalExpense)?></th>
</tr>
<tr>
<th class="text-end" colspan="3"> 월수익 &nbsp; </th>
<th class="text-end"><?=number_format($netIncome)?></th>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</body>
</html>
<script>
// 페이지 로딩
$(document).ready(function(){
var loader = document.getElementById('loadingOverlay');
loader.style.display = 'none';
});
// 기존 loadDetails 함수 유지
function loadDetails() {
const year = document.getElementById('year').value;
const startMonth = document.getElementById('startMonth').value;
const endMonth = document.getElementById('endMonth').value;
window.location.href = `detail.php?year=${year}&startMonth=${startMonth}&endMonth=${endMonth}`;
}
// 새로운 함수 추가: 특정 월 선택 시 호출
function loadSpecificMonth(month) {
const year = document.getElementById('year').value;
window.location.href = `detail.php?year=${year}&startMonth=${month}&endMonth=${month}`;
}
</script>

View File

@@ -0,0 +1,25 @@
<?php
// 파일 이름이 제공되었는지 확인
if (!isset($_GET['filename']) || empty($_GET['filename'])) {
die('Filename not specified.');
}
$filename = basename($_GET['filename']);
$filePath = '../excelsave/' . $filename;
// 파일이 존재하는지 확인
if (!file_exists($filePath)) {
die('File not found.');
}
// 파일을 다운로드하도록 설정
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $filename);
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filePath));
readfile($filePath);
exit;
?>

View File

@@ -0,0 +1,134 @@
<?php
// fetch_balance.php
function fetch_balances($DB, $fromdate, $todate) {
return [];
// require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
// $pdo = db_connect();
// // 현재 날짜
// $currentDate = date("Y-m-d");
// // fromdate 또는 todate가 빈 문자열이거나 null인 경우 처리
// if ($fromdate === "" || $fromdate === null || $todate === "" || $todate === null) {
// $fromdate = date("Y-m-01");
// $todate = $currentDate;
// }
// $initialBalances = [];
// // 이월 잔액을 직접 계산하는 로직
// $lastMonthEnd = date("Y-m-t", strtotime($fromdate . " -1 month"));
// // 미수금 내역 조회 (work + output_extra, outdate, ET_total)
// $salesBeforeSql = "
// SELECT o.secondordnum, SUM(COALESCE(e.ET_total, 0)) AS total_sales
// FROM {$DB}.work o
// LEFT JOIN {$DB}.output_extra e ON o.num = e.parent_num
// WHERE o.outdate <= :lastMonthEnd AND (o.is_deleted IS NULL or o.is_deleted = 0)
// GROUP BY o.secondordnum
// ";
// $paymentBeforeSql = "
// SELECT secondordnum, SUM(CAST(REPLACE(amount, ',', '') AS SIGNED)) AS total_payment
// FROM {$DB}.account_juil
// WHERE registDate <= :lastMonthEnd AND (is_deleted IS NULL or is_deleted = 0) AND content = '거래처 수금'
// AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')
// GROUP BY secondordnum
// ";
// // 전월까지의 매출과 수금 데이터 가져오기
// $salesBeforeStmt = $pdo->prepare($salesBeforeSql);
// $salesBeforeStmt->execute([':lastMonthEnd' => $lastMonthEnd]);
// $salesBeforeData = $salesBeforeStmt->fetchAll(PDO::FETCH_ASSOC);
// $paymentBeforeStmt = $pdo->prepare($paymentBeforeSql);
// $paymentBeforeStmt->execute([':lastMonthEnd' => $lastMonthEnd]);
// $paymentBeforeData = $paymentBeforeStmt->fetchAll(PDO::FETCH_ASSOC);
// // 이월 잔액 계산
// foreach ($salesBeforeData as $row) {
// $secondordnum = $row['secondordnum'];
// $total_sales_before = round((float)$row['total_sales'],2); // 부가세 포함(이미 ET_total은 부가세 포함)
// if (!isset($initialBalances[$secondordnum])) {
// $initialBalances[$secondordnum] = 0;
// }
// $initialBalances[$secondordnum] += $total_sales_before;
// }
// foreach ($paymentBeforeData as $row) {
// $secondordnum = $row['secondordnum'];
// $total_payment_before = (float)$row['total_payment'];
// if (!isset($initialBalances[$secondordnum])) {
// $initialBalances[$secondordnum] = 0;
// }
// $initialBalances[$secondordnum] -= $total_payment_before;
// }
// // 당월 매출 내역 가져오기 (work + output_extra, outdate, ET_total)
// $salesSql = "
// SELECT o.secondordnum, COALESCE(e.ET_total, 0) AS ET_total
// FROM {$DB}.work o
// LEFT JOIN {$DB}.output_extra e ON o.num = e.parent_num
// WHERE (o.outdate BETWEEN date('$fromdate') AND date('$todate')) AND (o.is_deleted IS NULL or o.is_deleted = 0)
// ";
// $salesStmt = $pdo->prepare($salesSql);
// $salesStmt->execute();
// $salesData = $salesStmt->fetchAll(PDO::FETCH_ASSOC);
// $salesResults = [];
// foreach ($salesData as $row) {
// $secondordnum = $row['secondordnum'];
// $total_sales = (float)$row['ET_total']; // ET_total은 부가세 포함
// if (!isset($salesResults[$secondordnum])) {
// $salesResults[$secondordnum] = 0;
// }
// $salesResults[$secondordnum] += round($total_sales,2);
// }
// // 당월 수금 내역 가져오기 (account_juil 테이블)
// $paymentSql = "
// SELECT secondordnum, SUM(CAST(REPLACE(amount, ',', '') AS SIGNED)) AS total_payment
// FROM {$DB}.account_juil
// WHERE registDate BETWEEN date('$fromdate') AND date('$todate')
// AND (is_deleted IS NULL or is_deleted = 0) AND content = '거래처 수금'
// AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')
// GROUP BY secondordnum
// ";
// $paymentStmt = $pdo->prepare($paymentSql);
// $paymentStmt->execute();
// $paymentData = $paymentStmt->fetchAll(PDO::FETCH_ASSOC);
// $paymentResults = [];
// foreach ($paymentData as $row) {
// $secondordnum = $row['secondordnum'];
// $total_payment = (float)$row['total_payment'];
// if (!isset($paymentResults[$secondordnum])) {
// $paymentResults[$secondordnum] = 0;
// }
// $paymentResults[$secondordnum] += $total_payment;
// }
// // 모든 거래처 목록을 생성 (매출, 기초채권)
// $allResults = array_unique(array_merge(array_keys($salesResults), array_keys($initialBalances)));
// // 최종 잔액 계산
// $balances = [];
// foreach ($allResults as $secondordnum) {
// $initialReceivable = isset($initialBalances[$secondordnum]) ? $initialBalances[$secondordnum] : 0;
// $total_sales = isset($salesResults[$secondordnum]) ? $salesResults[$secondordnum] : 0; // 부가세 포함
// $total_payment = isset($paymentResults[$secondordnum]) ? $paymentResults[$secondordnum] : 0;
// // 최종 잔액
// $balances[$secondordnum] = $initialReceivable + $total_sales - $total_payment;
// }
// return $balances;
}
?>

View File

@@ -0,0 +1,413 @@
<?php
require_once $_SERVER['DOCUMENT_ROOT'] . '/load_GoogleDrive.php'; // 세션 등 여러가지 포함됨 파일 포함
if (!isset($_SESSION["level"]) || $_SESSION["level"] > 5) {
sleep(1);
header("Location:" . $WebSite . "login/login_form.php");
exit;
}
$mode = isset($_POST['mode']) ? $_POST['mode'] : '';
$num = isset($_POST['num']) ? $_POST['num'] : '';
$tablename = 'account_juil';
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
if ($mode === 'update' && $num) {
try {
$sql = "SELECT * FROM " . $tablename . " WHERE num=?";
$stmh = $pdo->prepare($sql);
$stmh->bindValue(1, $num, PDO::PARAM_INT);
$stmh->execute();
$row = $stmh->fetch(PDO::FETCH_ASSOC);
$content = $row['content']; // 저장된 content 값을 가져옴
include '_row.php';
// 콤마 제거 후 숫자로 변환
$amount = floatval(str_replace(',', '', $row['amount']));
} catch (PDOException $Exception) {
echo "오류: " . $Exception->getMessage();
exit;
}
} else if ($mode === 'copy' && $num) {
try {
$sql = "SELECT * FROM " . $tablename . " WHERE num=?";
$stmh = $pdo->prepare($sql);
$stmh->bindValue(1, $num, PDO::PARAM_INT);
$stmh->execute();
$row = $stmh->fetch(PDO::FETCH_ASSOC);
$content = $row['content'];
include '_row.php';
$amount = floatval(str_replace(',', '', $row['amount']));
$mode = 'insert'; // 복사 모드에서는 새로운 항목으로 등록
$registDate = date('Y-m-d'); // 현재 날짜로 설정
} catch (PDOException $Exception) {
echo "오류: " . $Exception->getMessage();
exit;
}
} else {
include '_request.php';
$mode = 'insert';
$registDate = date('Y-m-d');
$inoutsep = '지출';
$amount = 0;
$content = ''; // 기본값 설정
}
$title_message = ($mode === 'update') ? '금전출납부 수정 #' . $num : '금전출납부 신규 등록' ;
// Bankbook options
$bankbookOptions = [];
$jsonFile = $_SERVER['DOCUMENT_ROOT'] . "/account_juil/accoutlist.json";
$accounts = [];
$selectedAccount = null;
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];
// bankbookOptions 배열에 계좌 정보 추가
foreach ($accounts as $account) {
$displayText = $account['company'] . ' ' . $account['number'];
if (!empty($account['memo'])) {
$displayText .= ' (' . $account['memo'] . ')';
}
$bankbookOptions[] = $displayText;
}
}
}
// 전자어음은 별도로 처리하므로 JSON 배열에는 추가하지 않음
// 수입/지출 계정 정보 가져오기
include 'fetch_options.php';
if($inoutsep == '수입')
$options = $incomeOptions;
elseif($inoutsep == '최초전월이월')
$options = $incomeOptions;
else
$options = $expenseOptions;
// 선택된 항목의 세부항목 가져오기
$selectedKey = $content ?? null; // URL의 'key' 매개변수로 전달
$details = null;
if ($selectedKey) {
// 수입에서 검색
if (isset($jsonData['수입'][$selectedKey])) {
$details = $jsonData['수입'][$selectedKey]['하위계정'];
}
// 지출에서 검색
if (isset($jsonData['지출'][$selectedKey])) {
$details = $jsonData['지출'][$selectedKey]['하위계정'];
}
}
// '개인대출'과 '주일기업' 등 키만 추출
$Suboptions = [];
if ($details) {
foreach ($details as $detail) {
foreach ($detail as $key => $value) {
$Suboptions[] = $key;
}
}
}
// 항목의 세부항목 수정시 처리하는 구문
if (isset($_POST['action']) && $_POST['action'] === 'getSubOptions') {
$selectedKey = $_POST['selectedKey'] ?? null;
$subOptions = [];
if ($selectedKey) {
if (isset($incomeOptions[$selectedKey]) && isset($jsonData['수입'][$selectedKey]['하위계정'])) {
$subOptions = $jsonData['수입'][$selectedKey]['하위계정'];
} elseif (isset($expenseOptions[$selectedKey]) && isset($jsonData['지출'][$selectedKey]['하위계정'])) {
$subOptions = $jsonData['지출'][$selectedKey]['하위계정'];
} elseif (isset($incomeOptions[$selectedKey]) && isset($jsonData['최초전월이월'][$selectedKey]['하위계정'])) {
$subOptions = $jsonData['최초전월이월'][$selectedKey]['하위계정'];
}
}
// $Suboptions 배열을 키를 기준으로 오름차순 정렬
ksort($Suboptions);
echo json_encode(['subOptions' => $subOptions], JSON_UNESCAPED_UNICODE);
exit;
}
// echo '<pre>';
// print_r($Suboptions);
// echo '</pre>';
// echo '<pre>';
// print_r($contentSub);
// echo '</pre>';
//print_r($details[);
// $options = array_merge($incomeOptions, $expenseOptions);
// $options 배열을 키를 기준으로 오름차순 정렬
ksort($options);
// $Suboptions 배열을 키를 기준으로 오름차순 정렬
ksort($Suboptions);
require_once $_SERVER['DOCUMENT_ROOT'] . '/load_GoogleDriveSecond.php'; // attached, image에 대한 정보 불러오기
// echo '<pre>';
// print_r($savefilename_arr);
// echo '</pre>';
// echo '<pre>';
// print_r($$bankbookOptions );
// echo '</pre>';
?>
<input type="hidden" id="update_log" name="update_log" value="<?=$update_log?>">
<input type="hidden" id="first_writer" name="first_writer" value="<?=$first_writer?>">
<div class="container-fluid">
<div class="d-flex align-items-center justify-content-center">
<div class="card justify-content-center w-100">
<div class="card-header text-center">
<span class="text-center fs-5"><?=$title_message?></span>
</div>
<div class="card-body">
<div class="row justify-content-center text-center">
<div class="d-flex align-items-center justify-content-center ">
<table class="table table-bordered ">
<tbody>
<tr>
<td class="text-center fw-bold" style="width:13%">등록일자</td>
<td class="text-center" colspan="3" style="width:37%">
<input type="date" class="form-control noborder-input w110px" id="registDate" name="registDate" value="<?=$registDate?>">
</td>
<td class="text-center fw-bold" style="width:13%">구분</td>
<td class="text-center" colspan="3" style="width:37%">
<div class="d-flex align-items-center justify-content-center">
<input type="radio" class="form-check-input mx-2" id="premonthly" name="inoutsep" value="최초전월이월" <?= $inoutsep === '최초전월이월' ? 'checked' : '' ?>>
<label for="premonthly" class="form-check-label ">최초전월이월</label>
&nbsp;&nbsp;
<input type="radio" class="form-check-input mx-2" id="income" name="inoutsep" value="수입" <?= $inoutsep === '수입' ? 'checked' : '' ?>>
<label for="income" class="form-check-label ">수입</label>
&nbsp;&nbsp;
<input type="radio" class="form-check-input mx-2" id="expense" name="inoutsep" value="지출" <?= $inoutsep === '지출' ? 'checked' : '' ?>>
<label for="expense" class="form-check-label ">지출</label>
</div>
</td>
</tr>
<tr>
<td class="text-center fw-bold">계좌</td>
<td class="text-center" colspan="7">
<div class="d-flex align-items-center align-items-center">
<select class="form-select w-auto" style="font-size: 0.8rem;height: 32px;" id="bankbook" name="bankbook">
<?php
// _row.php에서 설정된 $bankbook 변수 사용
$currentBankbook = isset($bankbook) ? $bankbook : '';
// JSON 계좌 옵션들 추가
foreach ($bankbookOptions as $option):
$isSelected = ($currentBankbook === $option);
?>
<option value="<?= htmlspecialchars($option) ?>" <?= $isSelected ? 'selected' : '' ?>><?= htmlspecialchars($option) ?></option>
<?php endforeach; ?>
<!-- 전자어음 옵션 추가 (JSON에 없어도 항상 표시) -->
<option value="전자어음" <?= $currentBankbook === '전자어음' ? 'selected' : '' ?>>전자어음</option>
</select>
<div id="endorsementDateContainer" class="ms-2" style="display: <?= $currentBankbook === '전자어음' ? 'inline-block' : 'none' ?>">
<span class="form-label mx-5 fw-bold text-primary" style="font-size: 0.8rem; margin: 0;">배서일자</span>
<input type="date" class="ms-5 form-control noborder-input" id="endorsementDate" name="endorsementDate" value="<?= $endorsementDate ?>" style="width: 110px; font-size: 0.8rem; height: 32px;">
</div>
<button type="button" id="selectElectronicBillBtn" class="btn btn-outline-primary btn-sm ms-2" style="display: <?= $currentBankbook === '전자어음' ? 'inline-block' : 'none' ?>">
<i class="bi bi-search"></i> 전자어음 선택
</button>
</div>
</td>
</tr>
<tr>
<td class="text-center fw-bold" >항목</td>
<td class="text-center" colspan="3">
<div class="row d-flex align-items-center justify-content-start">
<select class="form-select w200px p-2" style="margin-left:15px; font-size: 0.8rem;height: 35px;" id="content" name="content">
<?php foreach ($options as $key => $value): ?>
<option value="<?= htmlspecialchars($key) ?>" <?= $content === $key ? 'selected' : '' ?>><?= htmlspecialchars($key) ?></option>
<?php endforeach; ?>
</select>
<span class="text-start" style="margin-left:15px; font-size: 0.8rem;" id="content_description">
<?= $options[$content] ?? '' ?>
</span>
</div>
</td>
<td class="text-center fw-bold" >세부항목</td>
<td colspan="3" class="text-center">
<select class="form-select w-auto" style="font-size: 0.8rem;height: 32px;" id="contentSub" name="contentSub">
<?php foreach ($Suboptions as $value): // 키를 사용하지 않고 값만 사용 ?>
<option value="<?= htmlspecialchars($value) ?>" <?= $contentSub === $value ? 'selected' : '' ?>>
<?= htmlspecialchars($value) ?>
</option>
<?php endforeach; ?>
</select>
</td>
</tr>
<tr>
<td class="text-center fw-bold">상세 내역</td>
<td class="text-start" colspan="7">
<input type="text" class="form-control text-start noborder-input" id="content_detail" name="content_detail" value="<?=$content_detail?>" autocomplete="off">
</td>
</tr>
<tr>
<td class="text-center fw-bold" >금액</td>
<td class="text-center w200px">
<input
type="text"
class="form-control text-end fw-bold noborder-input "
id="amount"
name="amount"
value="<?= (isset($amount) && $amount != 0) ? number_format($amount) : '' ?>"
autocomplete="off"
onkeyup="inputNumberFormat(this)"
>
</td>
<td class="text-center text-end text-secondary w60px" >PNum</td>
<td class="text-center w100px">
<input
type="text"
class="form-control text-end noborder-input "
id="parentEBNum"
name="parentEBNum"
value="<?= (isset($parentEBNum)) ?$parentEBNum : '' ?>"
autocomplete="off"
>
</td>
<td class="text-center fw-bold" style="width:100px;">거래처코드</td>
<td class="text-start">
<input type="text" class="form-control text-start noborder-input w120px" id="secondordnum" name="secondordnum" value="<?= isset($secondordnum) ? $secondordnum : '' ?>" autocomplete="off" >
</td>
<td class="text-center fw-bold" style="width:100px;">만기일자</td>
<td class="text-start">
<input type="date" class="form-control text-start noborder-input w120px" id="dueDate" name="dueDate" value="<?= isset($dueDate) ? $dueDate : '' ?>" autocomplete="off" >
</td>
</tr>
</tbody>
</table>
</div>
</div>
<?php
// 삽입 위치: form 하단, </div></div> 직전
// try {
// $imgSt = $pdo->prepare(
// "SELECT picname
// FROM picuploads
// WHERE tablename = ?
// AND parentnum = ?
// AND item = 'image'"
// );
// $imgSt->execute([$tablename, $num]);
// $files = $imgSt->fetchAll(PDO::FETCH_COLUMN);
// if ($files) {
// echo '<div class="mt-3"><strong>첨부 이미지</strong></div>';
// echo '<div id="displayImage" class="d-flex flex-wrap gap-2">';
// echo '</div>';
// }
// } catch (Exception $e) {
// // 이미지 섹션 로드 실패 시 무시
// }
// // 삽입 위치: form 하단, </div></div> 직전
try {
$imgSt = $pdo->prepare(
"SELECT picname
FROM picuploads
WHERE tablename = ?
AND parentnum = ?
AND item = 'image'"
);
$imgSt->execute([$tablename, $num]);
$files = $imgSt->fetchAll(PDO::FETCH_COLUMN);
if ($files) {
echo '<div class="mt-3"><strong>첨부 이미지</strong></div>';
echo '<div class="d-flex flex-wrap gap-2">';
foreach ($files as $fileId) {
$thumb = getThumbnail($fileId, $service)
?: "https://drive.google.com/uc?id={$fileId}";
$imageId = $fileId; // 고유한 이미지 ID 생성
// $link ="https://drive.google.com/uc?id={$fileId}";
$link ="https://drive.google.com/file/d/{$fileId}/view?usp=drivesdk";
echo '<div>';
echo " <a href=\"#\" onclick=\"openTmpImagePopup('{$link}', '{$imageId}'); return false;\">";
echo " <img id=\"{$imageId}\" src=\"{$thumb}\" style=\"width:100px; height:auto;\" class=\"img-thumbnail\" />";
echo ' </a>';
echo '</div>';
}
echo '</div>';
}
} catch (Exception $e) {
// 이미지 섹션 로드 실패 시 무시
}
?>
<div class="d-flex justify-content-center">
<button type="button" id="saveBtn" class="btn btn-dark btn-sm me-3">
<i class="bi bi-floppy-fill"></i> 저장
</button>
<?php if($mode != 'insert') { ?>
<button type="button" id="copyBtn" class="btn btn-primary btn-sm me-3">
<i class="bi bi-files"></i> 복사
</button>
<button type="button" id="deleteBtn" class="btn btn-danger btn-sm me-3">
<i class="bi bi-trash"></i> 삭제
</button>
<?php } ?>
<button type="button" id="closeBtn" class="btn btn-outline-dark btn-sm me-2">
&times; 닫기
</button>
</div>
</div>
</div>
</div>
</div>
<!-- 전자어음 선택 모달 -->
<div id="electronicBillModal" class="modal fade" tabindex="-1" aria-labelledby="electronicBillModalLabel" aria-hidden="true">
<div class="modal-dialog modal-fullscreen">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="electronicBillModalLabel">배서일자가 없는 전자어음 선택</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="table-responsive">
<table class="table table-hover" id="electronicBillTable">
<thead class="table-secondary">
<tr>
<th>번호</th>
<th>등록일자</th>
<th>항목</th>
<th>세부항목</th>
<th>상세내용</th>
<th>금액</th>
<th>만기일자</th>
<th>선택</th>
</tr>
</thead>
<tbody id="electronicBillTableBody">
<!-- 데이터가 여기에 로드됩니다 -->
</tbody>
</table>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">닫기</button>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,36 @@
<?php
// JSON 파일 경로
$jsonFile = $_SERVER['DOCUMENT_ROOT'] . '/account_juil/accountContents.json';
// JSON 파일 읽기
if (file_exists($jsonFile)) {
$jsonData = json_decode(file_get_contents($jsonFile), true);
// 수입 옵션 생성
$incomeOptions = [];
if (isset($jsonData['수입'])) {
foreach ($jsonData['수입'] as $key => $value) {
$incomeOptions[$key] = $value['description'];
}
}
// 지출 옵션 생성
$expenseOptions = [];
if (isset($jsonData['지출'])) {
foreach ($jsonData['지출'] as $key => $value) {
$expenseOptions[$key] = $value['description'];
}
}
// 결과 출력
// echo json_encode([
// 'incomeOptions' => $incomeOptions,
// 'expenseOptions' => $expenseOptions,
// 'selectedDetails' => $details
// ], JSON_UNESCAPED_UNICODE);
} else {
echo json_encode([
'error' => 'JSON 파일을 찾을 수 없습니다.'
], JSON_UNESCAPED_UNICODE);
}
?>

View File

@@ -0,0 +1,174 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
$mode = isset($_POST['mode']) ? $_POST['mode'] : '';
$num = isset($_POST['num']) ? $_POST['num'] : '';
$tablename = 'todos_monthly';
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
try {
if ($mode === 'modify' && $num) {
$sql = "SELECT * FROM " . $tablename . " WHERE num=?";
$stmh = $pdo->prepare($sql);
$stmh->bindValue(1, $num, PDO::PARAM_INT);
$stmh->execute();
$row = $stmh->fetch(PDO::FETCH_ASSOC);
if ($row) {
$title = isset($row['title']) ? $row['title'] : '';
$registdate = isset($row['registdate']) ? $row['registdate'] : '';
$itemsep = isset($row['itemsep']) ? $row['itemsep'] : '';
$specialday = isset($row['specialday']) ? $row['specialday'] : '';
$yearlyspecialday = isset($row['yearlyspecialday']) ? $row['yearlyspecialday'] : '';
// Determine which period type to show based on saved data
$isYearly = !empty($yearlyspecialday); // 매년 값이 있는지 판단
if ($isYearly) {
// Split yearlyspecialday if available
list($month, $day) = explode('/', $yearlyspecialday);
} else {
$month = 1;
$day = 1;
}
$first_writer = isset($row['first_writer']) ? $row['first_writer'] : '';
$update_log = isset($row['update_log']) ? $row['update_log'] : '';
$searchtag = isset($row['searchtag']) ? $row['searchtag'] : '';
} else {
echo "Record not found.";
exit;
}
} else {
$title = '';
$registdate = date('Y-m-d');
$itemsep = '';
$specialday = '';
$month = 1; // Default month for yearlyspecialday
$day = 1; // Default day for yearlyspecialday
$first_writer = $user_name;
$update_log = '';
$searchtag = '';
$isYearly = false; // Default to monthly if no data
}
} catch (PDOException $Exception) {
echo "오류: " . $Exception->getMessage();
exit;
}
?>
<input type="hidden" id="update_log" name="update_log" value="<?= isset($update_log) ? $update_log : '' ?>">
<input type="hidden" id="num" name="num" value="<?= isset($num) ? $num : '' ?>">
<input type="hidden" id="searchtag" name="searchtag" value="<?= isset($searchtag) ? $searchtag : '' ?>">
<input type="hidden" id="user_name" name="user_name" value="<?= isset($user_name) ? $user_name : '' ?>">
<input type="hidden" id="first_writer" name="first_writer" value="<?= isset($first_writer) ? $first_writer : '' ?>">
<div class="container-fluid">
<div class="d-flex align-items-center justify-content-center">
<div class="card justify-content-center">
<div class="card-header text-center">
<span class="text-center fs-5"><?= $mode === 'update' ? '회계 월별 할일 수정' : '회계 월별 할일 신규 등록' ?></span>
</div>
<div class="card-body">
<div class="row justify-content-center text-center">
<div class="d-flex align-items-center justify-content-center m-2">
<table class="table table-bordered">
<tbody>
<tr>
<td class="text-center fs-6 fw-bold" style="width:150px;">등록일자</td>
<td class="text-center" style="width:200px;">
<input type="date" class="form-control fs-6" id="registdate" name="registdate" style="width:130px;" value="<?= htmlspecialchars($registdate) ?>">
</td>
<td class="text-center fs-6 fw-bold" style="width:150px;">작성자</td>
<td class="text-center" colspan="1">
<input type="text" class="form-control fs-6" id="first_writer" name="first_writer" value="<?= htmlspecialchars($first_writer) ?>" readonly>
</td>
</tr>
<tr>
<td class="text-center fs-6 fw-bold" style="width:150px;">주기</td>
<td class="text-center" colspan="3">
<div class="d-flex align-items-center justify-content-center">
<input type="radio" id="yearly" name="period" value="yearly" style="transform: scale(1.5);" <?= $isYearly ? 'checked' : '' ?> onchange="toggleDateFields()"> &nbsp;<span class="fs-6 ms-2 me-2">매년</span>
<input type="radio" id="monthly" name="period" value="monthly" style="transform: scale(1.5);" <?= !$isYearly ? 'checked' : '' ?> onchange="toggleDateFields()"> &nbsp;<span class="fs-6 ms-2 me-2">매월</span>
</div>
</td>
</tr>
<tr id="monthlyRow" style="<?= !$isYearly ? '' : 'display:none;' ?>">
<td class="text-center fs-6 fw-bold" style="width:150px;">매월</td>
<td class="text-center" colspan="3">
<div class="d-flex align-items-center justify-content-center">
<select class="form-control fs-6" style="width:60px;" id="specialday" name="specialday">
<?php for ($day = 1; $day <= 31; $day++): ?>
<option value="<?= $day ?>" <?= $specialday == $day ? 'selected' : '' ?>>
<?= $day ?>
</option>
<?php endfor; ?>
</select>
&nbsp;<span class="fs-6">일</span>
</div>
</td>
</tr>
<tr id="yearlyRow" style="<?= $isYearly ? '' : 'display:none;' ?>">
<td class="text-center fs-6 fw-bold" style="width:150px;">매년</td>
<td class="text-center" colspan="3">
<div class="d-flex align-items-center justify-content-center">
<select class="form-control fs-6" style="width:60px;" id="month" name="month">
<?php for ($m = 1; $m <= 12; $m++): ?>
<option value="<?= $m ?>" <?= $m == $month ? 'selected' : '' ?>><?= $m ?></option>
<?php endfor; ?>
</select>
&nbsp;<span class="fs-6">월</span>
<select class="form-control fs-6 ms-2" style="width:60px;" id="day" name="day">
<?php for ($d = 1; $d <= 31; $d++): ?>
<option value="<?= $d ?>" <?= $d == $day ? 'selected' : '' ?>><?= $d ?></option>
<?php endfor; ?>
</select>
&nbsp;<span class="fs-6">일</span>
</div>
</td>
</tr>
<tr>
<td class="text-center fs-6 fw-bold" style="width:150px;">내용</td>
<td class="text-center" colspan="3" >
<input type="text" class="form-control fs-6" id="title" name="title" value="<?= htmlspecialchars($title) ?>" autocomplete="off">
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="d-flex justify-content-center">
<button type="button" id="saveBtn_month" class="btn btn-dark btn-sm me-3">
<i class="bi bi-floppy-fill"></i> 저장
</button>
<?php if ($mode === 'modify') { ?>
<button type="button" id="deleteBtn_month" class="btn btn-danger btn-sm me-3">
<i class="bi bi-trash"></i> 삭제
</button>
<?php } ?>
<button type="button" id="closeBtn_month" class="btn btn-outline-dark btn-sm me-2">
&times; 닫기
</button>
</div>
</div>
</div>
</div>
</div>
<script>
function toggleDateFields() {
const yearlyRow = document.getElementById('yearlyRow');
const monthlyRow = document.getElementById('monthlyRow');
const yearlyRadio = document.getElementById('yearly').checked;
if (yearlyRadio) {
yearlyRow.style.display = '';
monthlyRow.style.display = 'none';
} else {
yearlyRow.style.display = 'none';
monthlyRow.style.display = '';
}
}
</script>

View File

@@ -0,0 +1,34 @@
<?php
require_once $_SERVER['DOCUMENT_ROOT'] . '/load_GoogleDrive.php';
if (!isset($_SESSION["level"]) || $_SESSION["level"] > 5) {
header("Content-Type: application/json");
echo json_encode(['error' => '권한이 없습니다.']);
exit;
}
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
try {
// 배서일자가 없는 전자어음 데이터 조회
$sql = "SELECT num, registDate, content, contentSub, content_detail, amount, dueDate
FROM account_juil
WHERE bankbook = '전자어음'
AND (endorsementDate IS NULL OR endorsementDate = '' OR endorsementDate = '0000-00-00')
AND (parentEBNum IS NULL OR parentEBNum = '' )
AND (is_deleted = 0 OR is_deleted IS NULL)
ORDER BY registDate DESC, num DESC";
$stmh = $pdo->prepare($sql);
$stmh->execute();
$results = $stmh->fetchAll(PDO::FETCH_ASSOC);
header("Content-Type: application/json; charset=utf-8");
echo json_encode(['success' => true, 'data' => $results], JSON_UNESCAPED_UNICODE);
} catch (PDOException $e) {
header("Content-Type: application/json; charset=utf-8");
echo json_encode(['error' => '데이터 조회 중 오류가 발생했습니다: ' . $e->getMessage()], JSON_UNESCAPED_UNICODE);
}
?>

112
account_juil/insert.php Normal file
View File

@@ -0,0 +1,112 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
$tablename = isset($_REQUEST['tablename']) ? $_REQUEST['tablename'] : 'account_juil';
$mode = isset($_REQUEST['mode']) ? $_REQUEST['mode'] : '';
header("Content-Type: application/json"); // Use JSON content type
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
include "_request.php";
// Construct the searchtag value
$searchtag = $registDate . ' ' . $inoutsep . ' ' . $content . ' ' . $contentSub . ' ' . $amount . $content_detail ;
if ($mode == "update") {
$update_log = date("Y-m-d H:i:s") . " - " . $_SESSION["name"] . " " . $update_log . "&#10";
try {
$pdo->beginTransaction();
// Prepare the SQL query for updating the account_juil information
$sql = "UPDATE " . $tablename . " SET ";
$sql .= "registDate = ?, inoutsep = ?, content = ?, content_detail = ?, amount = ?, dueDate = ?, searchtag = ?, update_log = ?, first_writer = ?, bankbook = ?, secondordnum = ?, contentSub=?, endorsementDate=?, parentEBNum=? ";
$sql .= "WHERE num = ? LIMIT 1"; // Update only one record matching the 'num'
$stmh = $pdo->prepare($sql);
// Bind the variables to the prepared statement as parameters
$stmh->bindValue(1, $registDate, PDO::PARAM_STR);
$stmh->bindValue(2, $inoutsep, PDO::PARAM_STR);
$stmh->bindValue(3, $content, PDO::PARAM_STR);
$stmh->bindValue(4, $content_detail, PDO::PARAM_STR);
$stmh->bindValue(5, str_replace(',', '', $amount), PDO::PARAM_STR); // 숫자안에 콤마제거후 저장
$stmh->bindValue(6, $dueDate, PDO::PARAM_STR);
$stmh->bindValue(7, $searchtag, PDO::PARAM_STR);
$stmh->bindValue(8, $update_log, PDO::PARAM_STR);
$stmh->bindValue(9, $first_writer, PDO::PARAM_STR);
$stmh->bindValue(10, $bankbook, PDO::PARAM_STR);
$stmh->bindValue(11, $secondordnum, PDO::PARAM_STR);
$stmh->bindValue(12, $contentSub, PDO::PARAM_STR);
$stmh->bindValue(13, $endorsementDate, PDO::PARAM_STR);
$stmh->bindValue(14, $parentEBNum, PDO::PARAM_STR);
$stmh->bindValue(15, $num, PDO::PARAM_INT);
// Execute the statement
$stmh->execute();
$pdo->commit();
} catch (PDOException $Exception) {
$pdo->rollBack();
print "오류: " . $Exception->getMessage();
}
}
if ($mode == "insert" || $mode == '' || $mode == null) {
$first_writer = date("Y-m-d H:i:s") . " - " . $_SESSION["name"] ;
$update_log = date("Y-m-d H:i:s") . " - " . $_SESSION["name"] . " " . $update_log . "&#10";
// Data insertion
try {
$pdo->beginTransaction();
// Updated columns and values to be inserted
$sql = "INSERT INTO " . $tablename . " (";
$sql .= "registDate, inoutsep, content, content_detail, amount, dueDate, searchtag, update_log, first_writer, bankbook, secondordnum, contentSub, endorsementDate, parentEBNum ";
$sql .= ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
$stmh = $pdo->prepare($sql);
$stmh->bindValue(1, $registDate, PDO::PARAM_STR);
$stmh->bindValue(2, $inoutsep, PDO::PARAM_STR);
$stmh->bindValue(3, $content, PDO::PARAM_STR);
$stmh->bindValue(4, $content_detail, PDO::PARAM_STR);
$stmh->bindValue(5, str_replace(',', '', $amount), PDO::PARAM_STR);
$stmh->bindValue(6, $dueDate, PDO::PARAM_STR);
$stmh->bindValue(7, $searchtag, PDO::PARAM_STR);
$stmh->bindValue(8, $update_log, PDO::PARAM_STR);
$stmh->bindValue(9, $first_writer, PDO::PARAM_STR);
$stmh->bindValue(10, $bankbook, PDO::PARAM_STR);
$stmh->bindValue(11, $secondordnum, PDO::PARAM_STR);
$stmh->bindValue(12, $contentSub, PDO::PARAM_STR);
$stmh->bindValue(13, $endorsementDate, PDO::PARAM_STR);
$stmh->bindValue(14, $parentEBNum, PDO::PARAM_STR);
// Execute the statement
$stmh->execute();
$pdo->commit();
} catch (PDOException $Exception) {
$pdo->rollBack();
print "오류: " . $Exception->getMessage();
}
}
if ($mode == "delete") { // Data deletion
try {
$pdo->beginTransaction();
$sql = "UPDATE " . $tablename . " SET is_deleted=1 WHERE num = ?";
$stmh = $pdo->prepare($sql);
$stmh->bindValue(1, $num, PDO::PARAM_INT);
$stmh->execute();
$pdo->commit();
} catch (PDOException $ex) {
$pdo->rollBack();
print "오류: " . $ex->getMessage();
}
}
$data = [
'num' => $num,
'mode' => $mode
];
echo json_encode($data, JSON_UNESCAPED_UNICODE);
?>

View File

@@ -0,0 +1,75 @@
<?php
// insert_bulk.php
require_once $_SERVER['DOCUMENT_ROOT'] . '/session.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/lib/mydb.php';
header('Content-Type: application/json; charset=utf-8');
$pdo = db_connect();
// 1) 클라이언트에서 JSON 문자열로 넘어온 entries
$payload = $_POST['entries'] ?? '';
$entries = json_decode($payload, true);
if (!is_array($entries) || count($entries) === 0) {
echo json_encode([
'status' => 'error',
'message' => '저장할 데이터가 없습니다.'
], JSON_UNESCAPED_UNICODE);
exit;
}
$nums = [];
try {
$pdo->beginTransaction();
// 2) account_juil 테이블에 대량 INSERT
$sql = "INSERT INTO account_juil (
registDate,
inoutsep,
bankbook,
content,
contentSub,
content_detail,
amount,
secondordnum,
dueDate,
endorsementDate
) VALUES (
?,?,?,?,?,?,?,?,?,?
)";
$stmt = $pdo->prepare($sql);
foreach ($entries as $row) {
$stmt->execute([
$row['registDate'], // 등록일자
$row['inoutsep'], // 구분
$row['bankbook'], // 계좌
$row['content'], // 항목
$row['contentSub'], // 세부항목
$row['content_detail'], // 상세내용
$row['amount'], // 금액 (콤마 제거된 숫자)
$row['secondordnum'], // 거래처코드
$row['dueDate'], // 만기일자
$row['endorsementDate'], // 배서일자
]);
// 3) 새로 생성된 AUTO_INCREMENT PK (num) 수집
$nums[] = $pdo->lastInsertId();
}
$pdo->commit();
// 4) 성공 응답: nums 배열을 돌며 클라이언트가 이미지 업로드에 사용할 수 있음
echo json_encode([
'status' => 'success',
'nums' => $nums
], JSON_UNESCAPED_UNICODE);
} catch (PDOException $e) {
$pdo->rollBack();
echo json_encode([
'status' => 'error',
'message' => $e->getMessage()
], JSON_UNESCAPED_UNICODE);
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2216
account_juil/list.php Normal file

File diff suppressed because it is too large Load Diff

476
account_juil/list_daily.php Normal file
View File

@@ -0,0 +1,476 @@
<?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 != '0000-00-00' AND dueDate IS NOT NULL AND dueDate != '')
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>

75
account_juil/modal.php Normal file
View File

@@ -0,0 +1,75 @@
<!-- 이월자료 Modal -->
<div class="container-fluid justify-content-center align-items-center">
<div id="monthlyBalanceModal" class="modal fade" tabindex="-1">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title">이월자료 수정</h2>
<span class="close">&times;</span>
</div>
<div class="modal-body">
<table class="table table-hover">
<thead class="table-info">
<tr>
<th class="text-center" style="width:20%;">기준일자</th>
<th class="text-center" style="width:30%;">거래처명</th>
<th class="text-center" style="width:20%;">이월잔액</th>
<th class="text-center" style="width:30%;">적요</th>
<th style="display:none;">고유번호</th>
<th style="display:none;">secondordnum</th>
</tr>
</thead>
<tbody id="monthlyBalanceModalBody">
<!-- 데이터를 여기에 동적으로 추가 -->
</tbody>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-dark btn-sm" onclick="saveMonthlyBalanceData()"> <i class="bi bi-floppy2-fill"></i> 저장</button>
<span class="badge bg-dark close">&times;</span>
</div>
</div>
</div>
</div>
</div>
<!-- 판매일괄회계반영 Modal -->
<div class="container-fluid justify-content-center align-items-center">
<div id="monthlysaleModal" class="modal fade" tabindex="-1">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title"> 판매일괄회계반영(계산서발행) </h2>
<span class="close">&times;</span>
</div>
<div class="modal-body">
<table class="table table-hover">
<thead class="table-info">
<tr>
<th class="text-center" >기준일자</th>
<th class="text-center" >거래처명</th>
<th class="text-center" >당월 발생금액</th>
<th class="text-center" style="width:140px;" >계산서 발행</th>
<th class="text-center" >적요</th>
<th class="text-center" style="width:80px;" >고유번호</th>
</tr>
</thead>
<tbody id="monthlysaleModalBody">
<!-- 데이터를 여기에 동적으로 추가 -->
</tbody>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-dark btn-sm" onclick="saveMonthlyBalanceData()"> <i class="bi bi-floppy2-fill"></i> 저장</button>
<button type="button" class="btn btn-danger btn-sm" onclick="saveMonthlyDelete()"> <i class="bi bi-trash3-fill"></i> 삭제 </button>
<span class="badge bg-dark close">&times;</span>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,676 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
session_start();
if (!isset($_SESSION["level"]) || $_SESSION["level"] > 5) {
sleep(1);
header("Location: /login/login_form.php");
exit;
}
include $_SERVER['DOCUMENT_ROOT'] . '/load_header.php';
// 첫 화면 표시 문구
$title_message = '판매일괄회계반영';
?>
<link href="css/style.css" rel="stylesheet">
<title> <?=$title_message?> </title>
<style>
/* 테이블에 테두리 추가 */
#myTable, #myTable th, #myTable td {
border: 1px solid black;
border-collapse: collapse;
}
/* 테이블 셀 패딩 조정 */
#myTable th, #myTable td {
padding: 8px;
text-align: center;
}
</style>
</head>
<body>
<?php require_once($_SERVER['DOCUMENT_ROOT'] . '/myheader.php'); ?>
<?php
$search = isset($_REQUEST['search']) ? $_REQUEST['search'] : '';
$fromdate = isset($_REQUEST['fromdate']) ? $_REQUEST['fromdate'] : '';
$todate = isset($_REQUEST['todate']) ? $_REQUEST['todate'] : '';
$mode = isset($_REQUEST['mode']) ? $_REQUEST['mode'] : '';
// 현재 날짜
$currentDate = date("Y-m-d");
// fromdate 또는 todate가 빈 문자열이거나 null인 경우
if ($fromdate === "" || $fromdate === null || $todate === "" || $todate === null) {
$fromdate = date("Y-m-01", strtotime($currentDate)); // 월의 첫날 설정
$todate = date("Y-m-t", strtotime($currentDate)); // 현재 달의 마지막 날 설정
} else {
$fromdate = date("Y-m-01", strtotime($fromdate)); // 선택한 달의 첫날 설정
$todate = date("Y-m-t", strtotime($todate)); // 선택한 달의 마지막 날 설정
}
function checkNull($strtmp) {
return $strtmp !== null && trim($strtmp) !== '';
}
$tablename = 'phonebook';
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
// 매출이 발생한 거래처 필터링 및 매출액 계산
$salesSql = "
SELECT o.secondordnum, COALESCE(e.ET_total, 0) AS ET_total
FROM output o
LEFT JOIN output_extra e ON o.num = e.parent_num
WHERE (o.outdate BETWEEN :fromdate AND :todate) AND o.is_deleted IS NULL
";
$salesStmt = $pdo->prepare($salesSql);
$salesStmt->bindParam(':fromdate', $fromdate, PDO::PARAM_STR);
$salesStmt->bindParam(':todate', $todate, PDO::PARAM_STR);
$salesStmt->execute();
$salesData = $salesStmt->fetchAll(PDO::FETCH_ASSOC);
$salesResults = [];
foreach ($salesData as $row) {
$secondordnum = $row['secondordnum'];
$et_total = (float)$row['ET_total'];
if (!isset($salesResults[$secondordnum])) {
$salesResults[$secondordnum] = 0;
}
$salesResults[$secondordnum] += round($et_total, 2);
}
arsort($salesResults); // 공급가액 내림차순으로 정렬
// 전월 마지막 날짜 계산
$lastMonthDate = date("Y-m-t", strtotime($fromdate . " -1 month"));
// 전월 잔액 조회
$balanceSql = "
SELECT secondordnum, balance, num, invoice_issued, memo
FROM monthly_balances
WHERE closure_date = :lastMonthDate
";
$balanceStmt = $pdo->prepare($balanceSql);
$balanceStmt->execute([':lastMonthDate' => $lastMonthDate]);
$previousBalances = $balanceStmt->fetchAll(PDO::FETCH_ASSOC);
// 전월 잔액을 저장할 배열
$previousBalanceMap = [];
foreach ($previousBalances as $balanceRow) {
$previousBalanceMap[$balanceRow['secondordnum']] = [
'balance' => $balanceRow['balance'],
'invoice_issued' => $balanceRow['invoice_issued'],
'memo' => $balanceRow['memo'],
'num' => $balanceRow['num']
];
}
// 현재월 잔액 조회
$current_saleSql = "
SELECT secondordnum, sales, num, invoice_issued, memo
FROM monthly_sales
WHERE closure_date BETWEEN :fromdate AND :todate AND is_deleted IS NULL
";
$balanceStmt = $pdo->prepare($current_saleSql);
$balanceStmt->bindParam(':fromdate', $fromdate, PDO::PARAM_STR);
$balanceStmt->bindParam(':todate', $todate, PDO::PARAM_STR);
$balanceStmt->execute();
$currentBalances = $balanceStmt->fetchAll(PDO::FETCH_ASSOC);
// 이번달 잔액을 저장할 배열
$currentBalanceMap = [];
foreach ($currentBalances as $balanceRow) {
$currentBalanceMap[$balanceRow['secondordnum']] = [
'sales' => $balanceRow['sales'],
'invoice_issued' => $balanceRow['invoice_issued'],
'memo' => $balanceRow['memo'],
'num' => $balanceRow['num']
];
}
// 수금 내역 가져오기
$paymentSql = "SELECT secondordnum, SUM(CAST(REPLACE(payment, ',', '') AS UNSIGNED)) as total_payment
FROM getmoney
WHERE registedate BETWEEN :fromdate AND :todate AND is_deleted IS NULL
GROUP BY secondordnum";
$paymentStmt = $pdo->prepare($paymentSql);
$paymentStmt->bindParam(':fromdate', $fromdate, PDO::PARAM_STR);
$paymentStmt->bindParam(':todate', $todate, PDO::PARAM_STR);
$paymentStmt->execute();
$paymentData = $paymentStmt->fetchAll(PDO::FETCH_ASSOC);
// 수금 내역을 저장할 배열
$paymentMap = [];
foreach ($paymentData as $paymentRow) {
$paymentMap[$paymentRow['secondordnum']] = (int)str_replace(',', '', $paymentRow['total_payment']);
}
?>
<form id="board_form" name="board_form" method="post" enctype="multipart/form-data">
<input type="hidden" id="mode" name="mode" value="<?=$mode?>">
<input type="hidden" id="num" name="num">
<input type="hidden" id="tablename" name="tablename" value="<?=$tablename?>">
<input type="hidden" id="header" name="header" value="<?=$header?>">
<input type="hidden" id="secondordnum" name="secondordnum" value="<?=$secondordnum?>">
<!-- 모달창 가져오기 -->
<?php include 'modal.php'; ?>
<div class="container">
<div class="d-flex p-1 m-1 mt-1 mb-1 justify-content-center align-items-center">
<span class="text-center fs-5 me-4"><?=$title_message?></span>
<button type="button" class="btn btn-dark btn-sm me-1" onclick='location.href="month_sales.php"'>
<i class="bi bi-arrow-clockwise"></i>
</button>
</div>
<div class="d-flex p-1 m-1 mt-1 mb-1 justify-content-center align-items-center">
<span class="text-center fs-6 text-danger"> * 세금계산서 발행일은 매월 말일 기준으로 입력해 주세요! 현재날짜로 입력하면 화면에 안나올수 있습니다. </span>
</div>
<div class="card">
<div class="card-body">
<div class="d-flex p-1 m-1 mt-1 mb-1 justify-content-center align-items-center">
▷ <?= count($salesResults) ?> &nbsp;
<!-- 기간부터 검색까지 연결 묶음 start -->
<button type="button" class="btn btn-secondary btn-sm me-1 change_dateRange" onclick='prepre_month()'>전전월</button>
<button type="button" class="btn btn-secondary btn-sm me-1 change_dateRange" onclick='pre_month()'>전월</button>
<button type="button" class="btn btn-dark btn-sm me-1 change_dateRange" onclick='this_month()'>당월</button>
<input type="date" id="fromdate" name="fromdate" class="form-control" style="width:100px;" value="<?=$fromdate?>"> &nbsp; ~ &nbsp;
<input type="date" id="todate" name="todate" class="form-control me-1" style="width:100px;" value="<?=$todate?>"> &nbsp; </span>
<div class="inputWrap">
<input type="text" id="search" name="search" value="<?=$search?>" onkeydown="if(event.key === 'Enter') submitForm();" autocomplete="off" class="form-control" style="width:150px;"> &nbsp;
<button class="btnClear"></button>
</div>
<div id="autocomplete-list">
</div>
&nbsp;
<button id="searchBtn" type="button" class="btn btn-outline-dark btn-sm me-2" onclick="submitForm()"><i class="bi bi-search"></i> 검색</button>
<button type="button" class="btn btn-dark btn-sm me-2" onclick="location.href='../getmoney/list.php?header=header'"><i class="bi bi-journal-x"></i> 수금 </button>
<button type="button" class="btn btn-dark btn-sm me-1" onclick="location.href='../account_juil/S_transaction.php?header=header'"> <i class="bi bi-file-earmark-ruled"></i> 거래원장</button>
<button type="button" class="btn btn-dark btn-sm me-1" onclick="openMonthlyBalancePopup()"> <i class="bi bi-file-earmark-ruled"></i> 이월잔액</button>
<button type="button" class="btn btn-danger btn-sm me-2" onclick="location.href='../account_juil/receivable.php?header=header'"> <i class="bi bi-journal-x"></i> 미수금 </button>
</div>
<div class="d-flex p-1 m-1 mt-1 mb-1 justify-content-center align-items-center">
<table class="table table-hover" id="myTable">
<thead class="table-info">
<th class="text-center w50px">번호</th>
<th class="text-center w200px">회사명</th>
<th class="text-center w100px">공급가</th>
<th class="text-center w100px">부가세</th>
<th class="text-center w100px">당월금액</th>
<th class="text-center w50px">상세</th>
<th class="text-center w100px">발행금액</th>
<th class="text-center w100px">세금계산서</th>
<th class="text-center w200px">적요</th>
</thead>
<tbody>
<?php
try {
$start_num = 1;
$processedSecondOrdnums = []; // 처리된 secondordnum을 추적하는 배열
foreach ($salesResults as $secondordnum => $total_sales) {
if((int)$total_sales!==0 && intval($secondordnum) > 0 )
{
$processedSecondOrdnums[] = $secondordnum;
$sql = "SELECT * FROM ".$DB.".".$tablename."
WHERE secondordnum = '$secondordnum'
AND is_deleted IS NULL
AND represent='대표코드'";
if (checkNull($search)) {
$sql .= " AND (vendor_name LIKE '%$search%' OR representative_name LIKE '%$search%' OR manager_name LIKE '%$search%')";
}
$stmh = $pdo->query($sql);
while ($row = $stmh->fetch(PDO::FETCH_ASSOC)) {
include $_SERVER['DOCUMENT_ROOT'] . '/phonebook/_row.php';
if (empty($contact_info))
$contact_info = $phone;
if (intval($secondordnum) > 0)
$savenum = $secondordnum;
else
$savenum = $num;
}
// 수금 내역 가져오기
$payment_collection = 0;
if (isset($paymentMap[$secondordnum])) {
$payment_collection = $paymentMap[$secondordnum];
}
// 전월 잔액 조회
$previous_balance = 0;
$previous_balance_num = '';
if (isset($previousBalanceMap[$secondordnum])) {
$previous_balance = $previousBalanceMap[$secondordnum]['balance'];
$previous_balance_num = $previousBalanceMap[$secondordnum]['num'];
}
$vat = round(round($total_sales) * 0.1);
$total_amount = $total_sales + $vat;
$balance_due = $total_amount - $payment_collection;
// 현재달 잔액 조회
$current_sale = 0;
$current_sale_num = '';
$invoice_issued = '';
$memo = '';
// 기존데이터가 존재할때
if (isset($currentBalanceMap[$secondordnum])) {
$current_sales = $currentBalanceMap[$secondordnum]['sales'];
$current_sale_num = $currentBalanceMap[$secondordnum]['num'];
$invoice_issued = isset($currentBalanceMap[$secondordnum]['invoice_issued']) ? $currentBalanceMap[$secondordnum]['invoice_issued'] : ''; // 기본값을 제공
$memo = isset($currentBalanceMap[$secondordnum]['memo']) ? $currentBalanceMap[$secondordnum]['memo'] : ''; // 기본값을 제공
}
else{
// 기존데이터가 없을때 신규
$current_sales = 0;
$current_sale_num = '';
$invoice_issued = '';
$memo = '';
}
// 마지막 단위 원단위 중 1은 제거하는 로직
// 당월매출 마지막 1원 삭제
// 마지막 자리가 1로 끝나는 경우, 0으로 변경
// print_r($total_payment);
// $totalSalesAmount -= 5;
if (round($total_amount) % 10 === 1) {
$vat -= 1; // 1을 빼서 마지막 자리를 0으로 만듭니다.
$total_amount -= 1; // 1을 빼서 마지막 자리를 0으로 만듭니다.
}
if (round($balance_due) % 10 === 1) {
$balance_due -= 1; // 1을 빼서 마지막 자리를 0으로 만듭니다.
}
?>
<tr data-num="<?= $current_sale_num ?>" data-secondordnum="<?= $secondordnum ?>" data-vendorname="<?= $vendor_name ?>" data-totalamount="<?= $total_amount ?>">
<td class="text-center"><?= $start_num ?></td>
<td class="text-start text-primary" onclick="fetchMonthlyBalanceData('<?= $current_sale_num ?>', '<?= $secondordnum ?>', '<?= $vendor_name ?>', '<?= $total_amount ?>')"><?= $vendor_name ?></td>
<td class="text-end " onclick="fetchMonthlyBalanceData('<?= $current_sale_num ?>', '<?= $secondordnum ?>', '<?= $vendor_name ?>', '<?= $total_amount ?>')"><?= number_format($total_sales) ?></td>
<td class="text-end " onclick="fetchMonthlyBalanceData('<?= $current_sale_num ?>', '<?= $secondordnum ?>', '<?= $vendor_name ?>', '<?= $total_amount ?>')"><?= number_format($vat) ?></td>
<td class="text-end fw-bold text-primary" onclick="fetchMonthlyBalanceData('<?= $current_sale_num ?>', '<?= $secondordnum ?>', '<?= $vendor_name ?>', '<?= $total_amount ?>')"><?= number_format($total_amount) ?></td>
<td class="text-center" onclick="redirectToView('<?= $savenum ?>')"><span class="badge bg-secondary"> 상세 </span></td>
<td class="text-end fw-bold" onclick="fetchMonthlyBalanceData('<?= $current_sale_num ?>', '<?= $secondordnum ?>', '<?= $vendor_name ?>', '<?= $total_amount ?>')"><?= number_format($current_sales) ?></td>
<td class="text-center" onclick="fetchMonthlyBalanceData('<?= $current_sale_num ?>', '<?= $secondordnum ?>', '<?= $vendor_name ?>', '<?= $total_amount ?>')">
<?php if ($invoice_issued): ?>
<span class="badge bg-warning"><?= $invoice_issued ?></span>
<?php else: ?>
&nbsp;
<?php endif; ?>
</td>
<td class="text-start" onclick="fetchMonthlyBalanceData('<?= $current_sale_num ?>', '<?= $secondordnum ?>', '<?= $vendor_name ?>', '<?= $total_amount ?>')"><?= $memo ?></td>
</tr>
<?php
$start_num++;
}
}
?>
</tbody>
<tfoot class="table-secondary">
<tr>
<th class="text-end" colspan="2"> 합계 &nbsp; </th>
<th class="text-end"></th>
<th class="text-end"></th>
<th class="text-end"></th>
<th class="text-end"></th>
<th class="text-end"></th>
<th class="text-end"></th>
<th class="text-end"></th>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
</form>
<?php
} catch (PDOException $Exception) {
print "오류: ".$Exception->getMessage();
}
?>
<!-- 페이지로딩 -->
<script>
$(document).ready(function(){
var loader = document.getElementById('loadingOverlay');
loader.style.display = 'none';
// 모달창 닫기
$(document).on('click', '.close', function(e) {
$("#monthlysaleModal").modal("hide");
});
});
function submitForm() {
$('#board_form').submit();
}
</script>
<script>
var dataTable; // DataTables 인스턴스 전역 변수
var monthsalepageNumber; // 현재 페이지 번호 저장을 위한 전역 변수
$(document).ready(function() {
// DataTables 초기 설정
dataTable = $('#myTable').DataTable({
"paging": true,
"ordering": true,
"searching": true,
"pageLength": 50,
"lengthMenu": [50, 100, 200, 500, 1000],
"language": {
"lengthMenu": "Show _MENU_ entries",
"search": "Live Search:"
},
"order": [[2, 'desc']], // 금액 기준 내림차순 정렬
"dom": 't<"bottom"ip>', // search 창과 lengthMenu 숨기기
"footerCallback": function (row, data, start, end, display) {
var api = this.api();
var intVal = function (i) {
return typeof i === 'string' ?
i.replace(/[\$,]/g, '') * 1 :
typeof i === 'number' ?
i : 0;
};
var totalInitialReceivable = api
.column(2)
.data()
.reduce(function (a, b) {
return intVal(a) + intVal(b);
}, 0);
var totalSalesAmount = api
.column(3)
.data()
.reduce(function (a, b) {
return intVal(a) + intVal(b);
}, 0);
var totalissued = api
.column(4)
.data()
.reduce(function (a, b) {
return intVal(a) + intVal(b);
}, 0);
$(api.column(2).footer()).html(numberWithCommas(totalInitialReceivable));
$(api.column(3).footer()).html(numberWithCommas(totalSalesAmount));
$(api.column(4).footer()).html(numberWithCommas(totalissued));
}
});
// 페이지 번호 복원 (초기 로드 시)
var savedPageNumber = getCookie('monthsalepageNumber');
if (savedPageNumber) {
dataTable.page(parseInt(savedPageNumber) - 1).draw(false);
}
// 페이지 변경 이벤트 리스너
dataTable.on('page.dt', function() {
var monthsalepageNumber = dataTable.page.info().page + 1;
setCookie('monthsalepageNumber', monthsalepageNumber, 10); // 쿠키에 페이지 번호 저장
});
// 페이지 길이 셀렉트 박스 변경 이벤트 처리
$('#myTable_length select').on('change', function() {
var selectedValue = $(this).val();
dataTable.page.len(selectedValue).draw(); // 페이지 길이 변경 (DataTable 파괴 및 재초기화 없이)
// 변경 후 현재 페이지 번호 복원
savedPageNumber = getCookie('monthsalepageNumber');
if (savedPageNumber) {
dataTable.page(parseInt(savedPageNumber) - 1).draw(false);
}
});
});
function redirectToView(num) {
var fromdate = document.getElementById('fromdate').value;
var todate = document.getElementById('todate').value;
var url = "customer_sheet.php?num=" + num + "&fromdate=" + fromdate + "&todate=" + todate;
customPopup(url, '거래원장', 1000, 850);
}
function openMonthlyBalancePopup() {
var url = "monthly_balance_popup.php";
customPopup(url, '거래원장', 1000, 850);
}
function fetchMonthlyBalanceData(current_sale_num, secondordnum, vendor_name, total_amount) {
$.ajax({
type: 'POST',
url: 'fetch_closure_sale.php',
data: { num: current_sale_num },
dataType: 'json',
success: function(response) {
console.log(response); // 디버깅을 위해 response를 출력
var tableBody = $('#monthlysaleModalBody');
tableBody.empty();
var currentDate = new Date().toISOString().slice(0, 10);
var selectedRow = $('#myTable tr[data-num="' + current_sale_num + '"]'); // 현재 선택한 행
// 선택된 행이 없는 경우 처리
if (selectedRow.length === 0) {
console.error('Selected row not found.');
return;
}
var customer_name = vendor_name; // vendor_name을 직접 사용
var formattedSales = parseFloat(total_amount).toLocaleString(); // total_amount를 3자리마다 콤마를 추가하여 포맷팅
console.log('Selected Row:', selectedRow);
console.log('Customer Name:', customer_name);
console.log('Formatted Sales:', formattedSales);
if (Array.isArray(response) && response.length !== 1) {
// 여러 개의 배열이 반환된 경우 또는 데이터가 없는 경우
var row = '<tr>' +
'<td class="text-center"><input type="date" class="form-control text-center" value="' + currentDate + '"></td>' +
'<td class="text-center"><input type="text" class="form-control customer_name text-start " value="' + customer_name + '"></td>' +
'<td class="text-end"><input type="text" class="form-control text-end sales w-75" onkeyup="inputNumberFormat(this)" value="'+ formattedSales +'"></td>' +
'<td class="text-center"><input type="checkbox" class="form-check-input invoice_issued"></td>' +
'<td class="text-center"><input type="text" class="form-control memo" value=""></td>' +
'<td class="text-center"><input type="text" class="form-control w80px text-start num" readonly value="' + current_sale_num + '"></td>' +
'<td style="display:none;"><input type="hidden" class="text-start secondordnum" value="' + secondordnum + '"></td>' +
'</tr>';
tableBody.append(row);
} else if (Array.isArray(response) && response.length === 1) {
// 단일 데이터가 반환된 경우
response.forEach(function(item) {
var formattedsales = parseFloat(item.sales).toLocaleString();
var row = '<tr>' +
'<td class="text-center"><input type="date" class="form-control text-center" value="' + item.closure_date + '"></td>' +
'<td class="text-center"><input type="text" class="form-control customer_name text-start " value="' + (item.customer_name !== null ? item.customer_name : '') + '"></td>' +
'<td class="text-end"><input type="text" class="form-control text-end w120px sales w-75" onkeyup="inputNumberFormat(this)" value="' + formattedsales + '"></td>' +
'<td class="text-center"><input type="checkbox" class="form-check-input invoice_issued" ' + (item.invoice_issued === '발행' ? 'checked' : '') + '></td>' +
'<td class="text-center"><input type="text" class="form-control memo" value="' + (item.memo !== null ? item.memo : '') + '"></td>' +
'<td class="text-center"><input type="text" class="form-control w80px text-start num" readonly value="' + current_sale_num + '"></td>' +
'<td style="display:none;"><input type="hidden" class="text-start secondordnum" value="' + secondordnum + '"></td>' +
'</tr>';
tableBody.append(row);
});
} else {
// 빈 배열이 반환된 경우 (예외 처리)
var row = '<tr>' +
'<td class="text-center"><input type="date" class="form-control text-center" value="' + currentDate + '"></td>' +
'<td class="text-center"><input type="text" class="form-control customer_name text-start" value="' + customer_name + '"></td>' +
'<td class="text-end"><input type="text" class="form-control text-end sales w-75" onkeyup="inputNumberFormat(this)" value="'+ formattedSales +'"></td>' +
'<td class="text-center"><input type="checkbox" class="form-check-input invoice_issued"></td>' +
'<td class="text-center"><input type="text" class="form-control memo" value=""></td>' +
'<td class="text-center"><input type="text" class="form-control w80px text-start num" readonly value="' + current_sale_num + '"></td>' +
'<td style="display:none;"><input type="hidden" class="text-start secondordnum" value="' + secondordnum + '"></td>' +
'</tr>';
tableBody.append(row);
}
console.log('current_sale_num ',current_sale_num);
$('#monthlysaleModal').modal('show');
},
error: function(xhr, status, error) {
console.error("AJAX error: ", status, error);
}
});
}
function saveMonthlyBalanceData() {
var data = [];
$('#monthlysaleModalBody tr').each(function() {
var num = $(this).find('.num').val();
var closure_date = $(this).find('input[type="date"]').val();
var customer_name = $(this).find('.customer_name').val();
var sales = $(this).find('.sales').val().replace(/,/g, ''); // 콤마 제거
var invoice_issued = $(this).find('input[type="checkbox"]').is(':checked');
var memo = $(this).find('.memo').val();
var secondordnum = $(this).find('.secondordnum').val();
var mode = num ? 'update' : 'insert'; // num이 있는 경우 업데이트, 없는 경우 삽입
data.push({
mode: mode,
num: num,
closure_date: closure_date,
customer_name: customer_name,
sales: sales,
invoice_issued: invoice_issued,
secondordnum: secondordnum,
memo: memo
});
});
console.log('data',data);
// 버튼 비활성화
var saveButton = $('button[onclick="saveMonthlyBalanceData()"]');
saveButton.prop('disabled', true);
$.ajax({
type: 'POST',
url: 'insert_monthly_sale.php',
contentType: 'application/json',
data: JSON.stringify(data),
success: function(response) {
console.log(response);
toastAlert('파일저장');
// 1.5초 후에 모달창 닫고 화면 새로고침
setTimeout(function(){
$('#monthlysaleModal').modal('hide');
location.reload(); // 화면 새로고침
}, 1500);
},
error: function(xhr, status, error) {
console.error("AJAX error: ", status, error);
// 에러 발생 시 버튼 다시 활성화
saveButton.prop('disabled', false);
}
});
}
// 삭제처리
function saveMonthlyDelete() {
Swal.fire({
title: '계산서 발행 삭제',
text: "이 작업을 진행하시겠습니까?",
icon: 'warning',
showCancelButton: true,
confirmButtonText: '예',
cancelButtonText: '아니오'
}).then((result) => {
if (result.isConfirmed) {
var data = [];
$('#monthlysaleModalBody tr').each(function() {
var num = $(this).find('.num').val();
var mode = 'delete';
data.push({
mode: mode,
num: num
});
});
// 버튼 비활성화
var saveButton = $('button[onclick="saveMonthlyDelete()"]');
saveButton.prop('disabled', true);
$.ajax({
type: 'POST',
url: 'insert_monthly_sale.php',
contentType: 'application/json',
data: JSON.stringify(data),
success: function(response) {
toastAlert('파일삭제');
// 1.5초 후에 모달창 닫고 화면 새로고침
setTimeout(function(){
$('#monthlysaleModal').modal('hide');
location.reload(); // 화면 새로고침
}, 1500);
},
error: function(xhr, status, error) {
console.error("AJAX error: ", status, error);
// 에러 발생 시 버튼 다시 활성화
saveButton.prop('disabled', false);
}
});
} else {
// 사용자가 '아니오'를 누른 경우
Swal.fire('취소되었습니다.', '', 'info');
}
});
}
// 모달창 닫힐 때 버튼 다시 활성화
$('#monthlysaleModal').on('hidden.bs.modal', function () {
var saveButton = $('button[onclick="saveMonthlyBalanceData()"]');
saveButton.prop('disabled', false);
var saveButton_delete = $('button[onclick="saveMonthlyDelete()"]');
saveButton_delete.prop('disabled', false);
});
// 화면에 toastAlert() 표시
function toastAlert(Str){
// 오버레이 활성화
document.getElementById("overlay").style.display = "block";
Toastify({
text: Str,
duration: 3000,
close: true,
gravity: "top",
position: 'center',
}).showToast();
// 1초 후에 오버레이 비활성화
setTimeout(function(){
document.getElementById("overlay").style.display = "none";
}, 1000);
}
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
</script>
</body>
</html>

View File

@@ -0,0 +1,335 @@
<?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;
}
include $_SERVER['DOCUMENT_ROOT'] . '/load_header.php';
// 첫 화면 표시 문구
$title_message = '이월잔액 자료';
?>
<title> <?=$title_message?> </title>
</head>
<body>
<?php
$search = isset($_REQUEST['search']) ? $_REQUEST['search'] : '';
$fromdate = isset($_REQUEST['fromdate']) ? $_REQUEST['fromdate'] : '';
$todate = isset($_REQUEST['todate']) ? $_REQUEST['todate'] : '';
$mode = isset($_REQUEST['mode']) ? $_REQUEST['mode'] : '';
// 현재 날짜
$currentDate = date("Y-m-d");
// fromdate 또는 todate가 빈 문자열이거나 null인 경우
if ($fromdate === "" || $fromdate === null || $todate === "" || $todate === null) {
// 전월의 첫날과 말일을 계산하여 설정
$fromdate = date("Y-m-01", strtotime("first day of previous month")); // 전월의 첫날 설정
$todate = date("Y-m-t", strtotime("last day of previous month")); // 전월의 마지막 날 설정
$Transtodate = $todate;
} else {
// 지정된 fromdate와 todate의 월의 첫날과 마지막 날을 계산하여 설정
$fromdate = date("Y-m-01", strtotime($fromdate)); // 선택한 달의 첫날 설정
$todate = date("Y-m-t", strtotime($todate)); // 선택한 달의 마지막 날 설정
$Transtodate = $todate;
}
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
// 전월 마지막 날짜 계산
// $lastMonthDate = date("Y-m-t", strtotime("last month"));
$lastMonthDate = $Transtodate ;
// print $lastMonthDate;
// 전월 잔액 조회 (output + output_extra, outdate, ET_total)
$balanceSql = "
SELECT o.num, o.secondordnum, SUM(COALESCE(e.ET_total, 0)) AS balance, o.secondord AS secondord, '' AS memo, o.outdate AS closure_date
FROM output o
LEFT JOIN output_extra e ON o.num = e.parent_num
WHERE o.outdate = :lastMonthDate AND o.outdate BETWEEN :fromdate AND :todate AND ( o.is_deleted IS NULL or o.is_deleted = 0 )
GROUP BY o.secondordnum, o.outdate
";
if (!empty($search)) {
$balanceSql .= " AND o.secondordnum LIKE :search";
}
$balanceStmt = $pdo->prepare($balanceSql);
$balanceStmt->bindValue(':lastMonthDate', $lastMonthDate, PDO::PARAM_STR);
$balanceStmt->bindValue(':fromdate', $fromdate, PDO::PARAM_STR);
$balanceStmt->bindValue(':todate', $todate, PDO::PARAM_STR);
if (!empty($search)) {
$balanceStmt->bindValue(':search', '%' . $search . '%', PDO::PARAM_STR);
}
$balanceStmt->execute();
$previousBalances = $balanceStmt->fetchAll(PDO::FETCH_ASSOC);
?>
<form id="board_form" name="board_form" method="post" enctype="multipart/form-data">
<input type="hidden" id="mode" name="mode" value="<?=$mode?>">
<input type="hidden" id="num" name="num">
<input type="hidden" id="tablename" name="tablename" value="<?=$tablename?>">
<input type="hidden" id="header" name="header" value="<?=$header?>">
<input type="hidden" id="secondordnum" name="secondordnum" value="<?=$secondordnum?>">
<?php include 'modal.php'; ?>
<div class="container">
<div class="d-flex p-1 m-1 mt-1 mb-1 justify-content-center align-items-center">
<span class="text-center fs-5 me-4"><?=$title_message?></span>
<button type="button" class="btn btn-dark btn-sm me-1" onclick='location.reload();'>
<i class="bi bi-arrow-clockwise"></i>
</button>
</div>
<div class="card">
<div class="card-body">
<div class="d-flex p-1 m-1 mt-1 mb-1 justify-content-center align-items-center">
<ion-icon name="caret-forward-outline"></ion-icon> <?= count($previousBalances) ?> &nbsp;
<button type="button" class="btn btn-secondary btn-sm me-1 change_dateRange" onclick='prepre_month()'>전전월</button>
<button type="button" class="btn btn-secondary btn-sm me-1 change_dateRange" onclick='pre_month()'>전월</button>
<input type="date" id="fromdate" name="fromdate" class="form-control" style="width:100px;" value="<?=$fromdate?>"> &nbsp; ~ &nbsp;
<input type="date" id="todate" name="todate" class="form-control me-1" style="width:100px;" value="<?=$todate?>"> &nbsp; </span>
<div class="inputWrap">
<input type="text" id="search" name="search" value="<?=$search?>" onkeydown="if(event.key === 'Enter') submitForm();" autocomplete="off" class="form-control me-1" style="width:150px;"> &nbsp;
<button class="btnClear"></button>
</div>
<button id="searchBtn" type="button" class="btn btn-dark btn-sm me-2" onclick="submitForm()"> <i class="bi bi-search"></i> </button>
<button id="closeBtn" type="button" class="btn btn-secondary btn-sm ms-2" onclick="window.close();"> 창닫기 </button>
</div>
<div class="d-flex p-1 m-1 mt-1 mb-1 justify-content-center align-items-center">
<table class="table table-hover" id="balanceTable">
<thead class="table-info">
<th class="text-center w50px">번호</th>
<th class="text-center w100px">기준일자</th>
<th class="text-center w130px">거래처명</th>
<th class="text-end w100px">이월잔액</th>
<th class="text-center w150px">적요</th>
<th class="text-center w100px">거래처코드</th>
</thead>
<tbody>
<?php
try {
$start_num = 1;
foreach ($previousBalances as $row) {
$num = $row['num'];
$secondordnum = $row['secondordnum'];
$secondord = $row['secondord'];
$balance = $row['balance'];
$memo = isset($row['memo']) ? $row['memo'] : ''; // 기본값을 제공
?>
<tr data-toggle="modal" data-target="#monthlyBalanceModal" onclick="fetchMonthlyBalanceData(<?= $num ?>)">
<td class="text-center"><?= $start_num ?></td>
<td class="text-center"><?= $lastMonthDate ?></td>
<td class="text-start text-primary"><?= $secondord ?></td>
<td class="text-end"><?= $balance != 0 ? number_format($balance) : '' ?></td>
<td class="text-center"><?= $memo ?> </td>
<td class="text-center text-info"><?= $secondordnum ?></td>
</tr>
<?php
$start_num++;
}
} catch (PDOException $Exception) {
print "오류: ".$Exception->getMessage();
}
?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</form>
</body>
</html>
<script>
// 페이지 로딩
$(document).ready(function(){
var loader = document.getElementById('loadingOverlay');
loader.style.display = 'none';
// 모달창 닫기
$(document).on('click', '.close', function(e) {
$("#monthlyBalanceModal").modal("hide");
});
});
var dataTable; // DataTables 인스턴스 전역 변수
var bookpageNumber; // 현재 페이지 번호 저장을 위한 전역 변수
function inputNumberFormat(input) {
var value = input.value.replace(/,/g, ''); // 콤마 제거
if (!isNaN(value) && value !== '') {
input.value = parseFloat(value).toLocaleString();
}
}
$(document).ready(function() {
// DataTables 초기 설정
dataTable = $('#myTable').DataTable({
"paging": true,
"ordering": true,
"searching": true,
"pageLength": 50,
"lengthMenu": [50, 100, 200, 500, 1000],
"language": {
"lengthMenu": "Show _MENU_ entries",
"search": "Live Search:"
},
"order": [[2, 'desc']], // 공급가액 기준 내림차순 정렬
"dom": 't<"bottom"ip>' // search 창과 lengthMenu 숨기기
});
// 페이지 번호 복원 (초기 로드 시)
var savedPageNumber = getCookie('bookpageNumber');
if (savedPageNumber) {
dataTable.page(parseInt(savedPageNumber) - 1).draw(false);
}
// 페이지 변경 이벤트 리스너
dataTable.on('page.dt', function() {
var bookpageNumber = dataTable.page.info().page + 1;
setCookie('bookpageNumber', bookpageNumber, 10); // 쿠키에 페이지 번호 저장
});
// 페이지 길이 셀렉트 박스 변경 이벤트 처리
$('#myTable_length select').on('change', function() {
var selectedValue = $(this).val();
dataTable.page.len(selectedValue).draw(); // 페이지 길이 변경 (DataTable 파괴 및 재초기화 없이)
// 변경 후 현재 페이지 번호 복원
savedPageNumber = getCookie('bookpageNumber');
if (savedPageNumber) {
dataTable.page(parseInt(savedPageNumber) - 1).draw(false);
}
});
});
function submitForm() {
$('#board_form').submit();
}
function fetchMonthlyBalanceData(num) {
$.ajax({
type: 'POST',
url: 'fetch_closure.php',
data: { num: num },
dataType: 'json',
success: function(response) {
console.log(response);
if (!Array.isArray(response)) {
console.error("Response is not an array:", response);
return;
}
var tableBody = $('#monthlyBalanceModalBody');
tableBody.empty();
response.forEach(function(item) {
var formattedBalance = parseFloat(item.balance).toLocaleString();
var row = '<tr>' +
'<td class="text-center"><input type="date" class="form-control text-center" value="' + item.closure_date + '"></td>' +
'<td class="text-center"><input type="text" class="form-control secondord" value="' + (item.secondord !== null ? item.secondord : '') + '"></td>' +
'<td class="text-end"><input type="text" class="form-control text-end w120px balance" onkeyup="inputNumberFormat(this)" value="' + formattedBalance + '"></td>' +
'<td class="text-center"><input type="text" class="form-control memo" value="' + (item.memo !== null ? item.memo : '') + '"></td>' +
'<td style="display:none;" ><input type="hidden" class="num" value="' + item.num + '"></td>' +
'</tr>';
tableBody.append(row);
});
$('#monthlyBalanceModal').modal('show');
},
error: function(xhr, status, error) {
console.error("AJAX error: ", status, error);
}
});
}
function saveMonthlyBalanceData() {
var data = [];
$('#monthlyBalanceModalBody tr').each(function() {
var num = $(this).find('.num').val();
var closure_date = $(this).find('input[type="date"]').val();
var secondord = $(this).find('.secondord').val();
var balance = $(this).find('.balance').val().replace(/,/g, ''); // 콤마 제거
var memo = $(this).find('.memo').val();
data.push({
num: num,
closure_date: closure_date,
secondord: secondord,
balance: balance,
memo: memo
});
});
// 버튼 비활성화
var saveButton = $('button[onclick="saveMonthlyBalanceData()"]');
saveButton.prop('disabled', true);
$.ajax({
type: 'POST',
url: 'insert_monthly.php',
contentType: 'application/json',
data: JSON.stringify(data),
success: function(response) {
toastAlert('파일저장');
// 1.5초 후에 모달창 닫고 화면 새로고침
setTimeout(function(){
$('#monthlyBalanceModal').modal('hide');
location.reload(); // 화면 새로고침
}, 1500);
},
error: function(xhr, status, error) {
console.error("AJAX error: ", status, error);
// 에러 발생 시 버튼 다시 활성화
saveButton.prop('disabled', false);
}
});
}
// 모달창 닫힐 때 버튼 다시 활성화
$('#monthlyBalanceModal').on('hidden.bs.modal', function () {
var saveButton = $('button[onclick="saveMonthlyBalanceData()"]');
saveButton.prop('disabled', false);
});
// 화면에 toastAlert() 표시
function toastAlert(Str){
// 오버레이 활성화
document.getElementById("overlay").style.display = "block";
Toastify({
text: Str,
duration: 3000,
close: true,
gravity: "top",
position: 'center',
}).showToast();
// 1초 후에 오버레이 비활성화
setTimeout(function(){
document.getElementById("overlay").style.display = "none";
}, 1000);
}
</script>

910
account_juil/receivable.php Normal file
View File

@@ -0,0 +1,910 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
if (!isset($_SESSION["level"]) || $_SESSION["level"] > 5) {
sleep(1);
header("Location:" . $WebSite . "login/login_form.php");
exit;
}
include $_SERVER['DOCUMENT_ROOT'] . '/load_header.php';
// 첫 화면 표시 문구
$title_message = '미수금 현황';
?>
<link href="css/style.css" rel="stylesheet">
<title> <?=$title_message?> </title>
<style>
/* 테이블에 테두리 추가 */
#myTable, #myTable th, #myTable td {
border: 1px solid black;
border-collapse: collapse;
}
/* 테이블 셀 패딩 조정 */
#myTable th, #myTable td {
padding: 8px;
text-align: center;
}
</style>
</head>
<body>
<?php
if($user_id === '0266771300' ) {
require_once($_SERVER['DOCUMENT_ROOT'] . '/myheader_accountant1.php'); // 경리
} else {
require_once($_SERVER['DOCUMENT_ROOT'] . '/myheader1.php');
}
?>
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/account_juil/fetch_balance.php");
$search = isset($_REQUEST['search']) ? $_REQUEST['search'] : '';
$selectedYearMonth = isset($_REQUEST['yearMonth']) ? $_REQUEST['yearMonth'] : date("Ym");
// 현재 날짜가 속한 연월 계산
$currentYearMonth = date("Ym");
// 선택된 연월의 이전 달을 계산
$previousMonth = date("Ym", strtotime($selectedYearMonth . '01 -1 month'));
$previousMonthDisplay = date("m", strtotime($previousMonth . '01')) . "월";
// 기준년월에 따른 fromdate, todate 설정
$fromdate = $selectedYearMonth . '01';
$todate = date("Y-m-t", strtotime($fromdate));
// 검색 기간 표시를 위해 fromdate와 todate를 Y-m-d 형식으로 변환
$fromdate = date("Y-m-d", strtotime($fromdate));
$todate = date("Y-m-d", strtotime($todate));
$mode = isset($_REQUEST['mode']) ? $_REQUEST['mode'] : '';
function checkNull($strtmp) {
return $strtmp !== null && trim($strtmp) !== '';
}
$tablename = 'phonebook';
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
// 약속코멘트와 약속일을 가져온다.
$promisedate = [];
$memo = [];
$recordSql = "
SELECT secondordnum, primisedate, comment
FROM recordlist
WHERE (is_deleted IS NULL or is_deleted = 0)
ORDER BY num DESC
";
$recordStmt = $pdo->prepare($recordSql);
$recordStmt->execute();
$recordData = $recordStmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($recordData as $row) {
$secondordnum = $row['secondordnum'];
$primisedate = $row['primisedate'];
$comment = $row['comment'];
// 가장 최신의 약속일과 메모만 저장
if (!isset($promisedate[$secondordnum])) {
$promisedate[$secondordnum] = $primisedate;
$memo[$secondordnum] = $comment;
}
}
// 이월 잔액을 동적으로 계산하기 위한 로직
$previousMonthFromDate = date("Y-m-01", strtotime($previousMonth . '01'));
$previousMonthToDate = date("Y-m-t", strtotime($previousMonth . '01'));
// echo '<pre>';
// print_r($previousMonthFromDate);
// echo ', ';
// print_r($previousMonthToDate);
// echo '</pre>';
// 전월 매출 및 수금 데이터 가져오기
$previousMonthSalesSql = "
SELECT o.secondordnum, COALESCE(e.ET_total, 0) AS ET_total
FROM output o
LEFT JOIN output_extra e ON o.num = e.parent_num
WHERE (o.outdate BETWEEN date('$previousMonthFromDate') AND date('$previousMonthToDate')) AND (o.is_deleted IS NULL or o.is_deleted = 0)
";
$previousMonthSalesStmt = $pdo->prepare($previousMonthSalesSql);
$previousMonthSalesStmt->execute();
$previousMonthSalesData = $previousMonthSalesStmt->fetchAll(PDO::FETCH_ASSOC);
$previousMonthSales = [];
foreach ($previousMonthSalesData as $row) {
$secondordnum = $row['secondordnum'];
$total_sales_prev = (float)$row['ET_total'];
if (!isset($previousMonthSales[$secondordnum])) {
$previousMonthSales[$secondordnum] = 0;
}
$previousMonthSales[$secondordnum] += round($total_sales_prev, 2); // ET_total은 부가세 포함
}
// 당월 매출 데이터 가져오기
$salesSql = "
SELECT o.secondordnum, COALESCE(e.ET_total, 0) AS ET_total
FROM output o
LEFT JOIN output_extra e ON o.num = e.parent_num
WHERE (o.outdate BETWEEN date('$fromdate') AND date('$todate')) AND (o.is_deleted IS NULL or o.is_deleted = 0)
";
$salesStmt = $pdo->prepare($salesSql);
$salesStmt->execute();
$salesData = $salesStmt->fetchAll(PDO::FETCH_ASSOC);
$currentMonthSales = [];
foreach ($salesData as $row) {
$secondordnum = $row['secondordnum'];
$total_sales = (float)$row['ET_total'];
if (!isset($currentMonthSales[$secondordnum])) {
$currentMonthSales[$secondordnum] = 0;
}
$currentMonthSales[$secondordnum] += round($total_sales, 2);
}
// 전월까지의 매출 및 수금 데이터를 기반으로 이월 잔액을 계산
$initialBalances = [];
$lastMonthEnd = date("Y-m-t", strtotime($fromdate . " -1 month"));
$salesBeforeSql = "
SELECT o.secondordnum, SUM(COALESCE(e.ET_total, 0)) AS total_sales
FROM output o
LEFT JOIN output_extra e ON o.num = e.parent_num
WHERE o.outdate <= :lastMonthEnd AND (o.is_deleted IS NULL or o.is_deleted = 0)
GROUP BY o.secondordnum
";
$paymentBeforeSql = "
SELECT secondordnum, SUM(CAST(REPLACE(amount, ',', '') AS SIGNED)) AS total_payment
FROM account_juil
WHERE registDate <= :lastMonthEnd AND (is_deleted IS NULL or is_deleted = 0) AND content = '거래처 수금'
AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')
GROUP BY secondordnum
";
$salesBeforeStmt = $pdo->prepare($salesBeforeSql);
$salesBeforeStmt->execute([':lastMonthEnd' => $lastMonthEnd]);
$salesBeforeData = $salesBeforeStmt->fetchAll(PDO::FETCH_ASSOC);
// echo '<pre>';
// print_r($lastMonthEnd);
// echo '</pre>';
$paymentEnddate = date("Y-m-t", strtotime($todate));
$paymentBeforeStmt = $pdo->prepare($paymentBeforeSql);
$paymentBeforeStmt->execute([':lastMonthEnd' => $paymentEnddate]);
$paymentBeforeData = $paymentBeforeStmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($salesBeforeData as $row) {
$secondordnum = $row['secondordnum'];
$total_sales_before = round((float)$row['total_sales'], 2);
if (!isset($initialBalances[$secondordnum])) {
$initialBalances[$secondordnum] = 0;
}
$initialBalances[$secondordnum] += $total_sales_before;
}
foreach ($paymentBeforeData as $row) {
$secondordnum = $row['secondordnum'];
$total_payment_before = (float)$row['total_payment'];
if (!isset($initialBalances[$secondordnum])) {
$initialBalances[$secondordnum] = 0;
}
$initialBalances[$secondordnum] -= $total_payment_before;
}
// 거래처별 잔액을 계산
$balances = fetch_balances($DB, $fromdate, $todate);
// 모든 거래처 목록을 생성 (이월 잔액, 전월 매출, 당월 매출, 잔고)
$allResults = array_unique(array_merge(array_keys($initialBalances), array_keys($currentMonthSales), array_keys($previousMonthSales), array_keys($balances)));
// ksort($allResults);
// echo '<pre>';
// print_r($allResults[23]);
// echo '</pre>';
// 이번달 수금 금액 계산
$currentMonthPayments = [];
$currentMonthStart = date("Y-m-01", strtotime($todate));
$currentMonthEnd = date("Y-m-t", strtotime($todate));
$currentPaymentSql = "
SELECT secondordnum, SUM(CAST(REPLACE(amount, ',', '') AS SIGNED)) AS total_payment
FROM account_juil
WHERE registDate BETWEEN :currentMonthStart AND :currentMonthEnd
AND (is_deleted IS NULL or is_deleted = 0) AND content = '거래처 수금'
AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')
GROUP BY secondordnum
";
$currentPaymentStmt = $pdo->prepare($currentPaymentSql);
$currentPaymentStmt->execute([
':currentMonthStart' => $currentMonthStart,
':currentMonthEnd' => $currentMonthEnd
]);
$currentPaymentData = $currentPaymentStmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($currentPaymentData as $row) {
$secondordnum = $row['secondordnum'];
$total_payment_current = (float)$row['total_payment'];
if (!isset($currentMonthPayments[$secondordnum])) {
$currentMonthPayments[$secondordnum] = 0;
}
$currentMonthPayments[$secondordnum] += $total_payment_current;
}
// 미수금 계산
$receivables = []; // 미수금을 저장할 배열
$vendorNames = []; // 거래처 이름을 저장할 배열
$paydates = []; // 결제일을 저장할 배열
// 거래처 이름을 저장하는 배열 초기화
$vendorNames = [];
$paydates = [];
foreach ($allResults as $secondordnum) {
// 잔고, 전월매출, 당월매출, 이월 잔액 및 미수금을 계산
$previousMonthSale = isset($previousMonthSales[$secondordnum]) ? $previousMonthSales[$secondordnum] : 0;
$currentMonthSale = isset($currentMonthSales[$secondordnum]) ? $currentMonthSales[$secondordnum] : 0;
$balance = isset($balances[$secondordnum]) ? $balances[$secondordnum] : 0;
$currentMonthPayment = isset($currentMonthPayments[$secondordnum]) ? $currentMonthPayments[$secondordnum] : 0;
// 최종 잔고 계산 (이번달 수금액을 차감)
// $finalBalance = $balance - $currentMonthPayment; // 이코드 보류함 250414 수정 이중으로 차감됨
$finalBalance = $balance ;
if ($finalBalance > 0) {
$receivableAmount = $finalBalance - $currentMonthSale - $previousMonthSale;
if($receivableAmount > 0)
$receivables[$secondordnum] = $receivableAmount;
else
$receivables[$secondordnum] = 0;
} else {
$receivables[$secondordnum] = 0;
}
// 거래처 정보 가져오기
$dueDateSql = "SELECT paydate, vendor_name, note FROM {$DB}.phonebook
WHERE secondordnum = '$secondordnum' AND (is_deleted IS NULL or is_deleted = 0)";
$dueDateStmt = $pdo->prepare($dueDateSql);
$dueDateStmt->execute();
$dueDateRow = $dueDateStmt->fetch(PDO::FETCH_ASSOC);
// 거래처 이름과 결제일을 저장
$vendorNames[$secondordnum] = $dueDateRow['vendor_name'] ?? '';
$paydates[$secondordnum] = $dueDateRow['paydate'] ?? '';
}
// 거래처 이름으로 정렬
usort($allResults, function($a, $b) use ($vendorNames) {
return strcmp($vendorNames[$a], $vendorNames[$b]);
});
// echo '<pre>';
// print_r($receivables);
// echo '</pre>';
?>
<!-- 리스트 모달 창 -->
<div class="modal fade" id="recordListModal" tabindex="-1" aria-labelledby="recordListModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="recordListModalLabel">약속일 및 통화내역</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<ul id="recordList" class="list-group" style="max-height: 400px; overflow-y: auto;">
<!-- 여기에서 기록 리스트가 동적으로 추가됩니다. -->
</ul>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" id="newRecordButton">신규등록</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">닫기</button>
</div>
</div>
</div>
</div>
<!-- 수정/신규등록 모달 창 -->
<div class="modal fade" id="recordEditModal" tabindex="-1" aria-labelledby="recordEditModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="recordEditModalLabel">결재 약속일 및 통화내역 수정</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="recordForm">
<input type="hidden" id="recordNum" name="recordNum">
<div class="mb-3">
<label for="record" class="form-label">기록일시</label>
<input type="datetime-local" class="form-control" style="width:200px;" id="recordTime" name="recordTime">
</div>
<div class="mb-3">
<label for="comment" class="form-label">통화내용</label>
<textarea class="form-control" id="comment" name="comment" style="height:150px;" ></textarea>
</div>
<div class="mb-3">
<label for="primisedate" class="form-label">결재 약속일</label>
<input type="date" class="form-control" style="width:110px;" id="primisedate" name="primisedate" >
<input type="hidden" id="secondordID" name="secondordID" >
</div>
<button type="submit" class="btn btn-primary">저장</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">닫기</button>
</form>
</div>
</div>
</div>
</div>
<form id="board_form" name="board_form" method="post" enctype="multipart/form-data">
<div class="container mb-5">
<input type="hidden" id="mode" name="mode" value="<?=$mode?>">
<input type="hidden" id="num" name="num">
<input type="hidden" id="tablename" name="tablename" value="<?=$tablename?>">
<input type="hidden" id="header" name="header" value="<?=$header?>">
<input type="hidden" id="secondordnum" name="secondordnum" value="<?=$secondordnum?>">
<div class="d-flex p-1 m-1 mt-1 mb-1 justify-content-center align-items-center">
<span class="text-center fs-5 me-4"><?=$title_message?></span>
<button type="button" class="btn btn-dark btn-sm me-1" onclick='location.reload();'>
<i class="bi bi-arrow-clockwise"></i>
</button>
</div>
<!-- <div class="d-flex p-1 m-1 mt-1 mb-1 justify-content-center align-items-center">
<span class="badge bg-danger fs-6 me-4"> 미수금 현황은 <거래처원장> '차기월 이월금확정' 처리 완료 후 계산됩니다. </span>
</div>
-->
<div class="d-flex p-1 m-1 mt-1 mb-1 justify-content-center align-items-center">
<button type="button" class="btn btn-dark btn-sm me-2" onclick="location.href='../getmoney/list.php?header=header'"><i class="bi bi-journal-x"></i> 수금 </button>
<button type="button" class="btn btn-dark btn-sm me-1" onclick="location.href='../account_juil/S_transaction.php?header=header'"> <i class="bi bi-file-earmark-ruled"></i> 거래원장</button>
<button type="button" class="btn btn-dark btn-sm me-1" onclick="openMonthlyBalancePopup()"> <i class="bi bi-file-earmark-ruled"></i> 이월잔액</button>
<button type="button" class="btn btn-dark btn-sm me-1" onclick="location.href='../account_juil/month_sales.php?header=header'"> <i class="bi bi-file-earmark-ruled"></i> 판매일괄회계</button>
</div>
<!--
<div class="d-flex p-1 m-1 mt-1 mb-1 justify-content-center align-items-center">
<span class="badge bg-danger fs-3 me-3"> 현재개발중입니다. (미완성) </span>
</div>
-->
<div class="d-flex p-1 m-1 mt-1 mb-1 justify-content-center align-items-center">
<span class="text-primary fw-bold ms-2 me-3"> * 잔고(거래원장 잔액) - 당월매출 - 전월매출 = 미수금 (계산서 발행 후 결재일 넘기면 미수금)</span>
</div>
<div class="card">
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover" id="myTable">
<thead class="table-danger">
<th class="text-center ">번호</th>
<th class="text-center w150px">거래처명</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>
<th class="text-center ">원장</th>
<?php if($user_id == 'pro')
print '<th class="text-center w40px">Code</th>';
?>
<th style="display:none;" ></th>
</thead>
<tbody>
<?php
try {
$start_num = 1;
foreach ($allResults as $secondordnum) {
if (isset($receivables[$secondordnum]) && intval($receivables[$secondordnum]) > 0 ) {
?>
<tr data-secondordnum="<?=$secondordnum ?>" data-secondord="<?= htmlspecialchars($vendorNames[$secondordnum])?>"
data-promisedate="<?= htmlspecialchars($promisedate[$secondordnum] ?? '') ?>" data-memo="<?= htmlspecialchars($memo[$secondordnum] ?? '') ?>">
<td class="text-center choice"><?= $start_num ?></td>
<td class="text-start text-primary choice"
data-secondord="<?= htmlspecialchars($vendorNames[$secondordnum])?>"
onclick="redirectToView(this, '<?= $secondordnum ?>')">
<?= htmlspecialchars($vendorNames[$secondordnum]) ?>
</td>
<td class="text-center text-primary fw-bold choice"
onclick="redirectToView(this, '<?= $secondordnum ?>')">
<?= htmlspecialchars($paydates[$secondordnum]) ?>
</td>
<td class="text-end text-danger fw-bold choice"
onclick="redirectToView(this, '<?= $secondordnum ?>')">
<?= number_format($receivables[$secondordnum]) ?>
</td>
<td class="text-end text-secondary fw-bold choice"
onclick="redirectToView(this, '<?= $secondordnum ?>')">
<?= number_format(isset($previousMonthSales[$secondordnum]) ? $previousMonthSales[$secondordnum] : 0) ?>
</td>
<td class="text-end fw-bold choice"
onclick="redirectToView(this, '<?= $secondordnum ?>')">
<?= number_format(isset($currentMonthSales[$secondordnum]) ? $currentMonthSales[$secondordnum] : 0) ?>
</td>
<td class="text-end fw-bold choice" onclick="redirectToView(this, '<?= $secondordnum ?>')">
<?= number_format(isset($balances[$secondordnum]) ? $balances[$secondordnum] : 0) ?>
</td>
<td class="text-center choice" data-promisedate onclick="redirectToView(this, '<?= $secondordnum ?>')" >
<?= (isset($promisedate[$secondordnum]) && $promisedate[$secondordnum] !== "0000-00-00") ? htmlspecialchars($promisedate[$secondordnum]) : '' ?>
</td>
<td class="text-start choice" onclick="redirectToView(this, '<?= $secondordnum ?>')" data-memo title="<?= htmlspecialchars($memo[$secondordnum] ?? '') ?>">
<?php
if (isset($memo[$secondordnum])) {
$memoText = htmlspecialchars($memo[$secondordnum]);
// 한글 처리를 위해 mb_strlen과 mb_substr 사용
if (mb_strlen($memoText, 'UTF-8') > 40) {
echo mb_substr($memoText, 0, 40, 'UTF-8') . '...';
} else {
echo $memoText;
}
} else {
echo '';
}
?>
</td>
<td class="text-center" onclick="ViewtoCustomerSheet('<?= $secondordnum ?>')">
<span class="badge bg-secondary"> 보기 </span>
</td>
<?php if($user_id == 'pro')
echo '<td class="text-center w50px"> ' . $secondordnum . ' </td>';
?>
<td style="display:none;"><?= $secondordnum ?></td>
</tr>
<?php
$start_num++;
}
}
} catch (PDOException $Exception) {
print "오류: ".$Exception->getMessage();
}
?>
</tbody>
<tfoot class="table-secondary">
<tr>
<th class="text-end w80px" colspan="3"> 합계 &nbsp; </th>
<th class="text-end">
<?= number_format(array_sum(array_map(function($value) {
return floatval(str_replace(',', '', $value));
}, $receivables))) ?>
</th>
<th class="text-end"><?= number_format(array_sum($previousMonthSales)) ?></th>
<th class="text-end"><?= number_format(array_sum($currentMonthSales)) ?></th>
<th class="text-end"><?= number_format(array_sum($balances)) ?></th>
<th class="text-end "> </th>
<th class="text-end "> </th>
<th class="text-end "> </th>
<?php if($user_id == 'pro')
echo '<th class="text-center w50px"> </th>';
?>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
</form>
<!-- 페이지로딩 -->
<script>
$(document).ready(function(){
var loader = document.getElementById('loadingOverlay');
if(loader)
loader.style.display = 'none';
});
function submitForm() {
$('#board_form').submit();
}
var dataTable; // DataTables 인스턴스 전역 변수
var bookpageNumber; // 현재 페이지 번호 저장을 위한 전역 변수
$(document).ready(function() {
dataTable = $('#myTable').DataTable({
"paging": true,
"ordering": true,
"searching": true,
"pageLength": 100,
"lengthMenu": [100, 200, 500, 1000],
"language": {
"lengthMenu": "Show _MENU_ entries",
"search": "Live Search:"
},
// "order": [[3, 'desc']], // 잔액기준 내림차순 정렬
"dom": 't<"bottom"ip>', // search 창과 lengthMenu 숨기기
"footerCallback": function ( row, data, start, end, display ) {
var api = this.api(), data;
var intVal = function (i) {
return typeof i === 'string' ?
i.replace(/[\$,]/g, '')*1 :
typeof i === 'number' ?
i : 0;
};
totalInitialReceivable = api.column(4).data().reduce(function (a, b) { return intVal(a) + intVal(b); }, 0);
totalSalesAmount = api.column(5).data().reduce(function (a, b) { return intVal(a) + intVal(b); }, 0);
totalBalanceDue = api.column(6).data().reduce(function (a, b) { return intVal(a) + intVal(b); }, 0);
$(api.column(4).footer()).html(numberWithCommas(totalInitialReceivable));
$(api.column(5).footer()).html(numberWithCommas(totalSalesAmount));
$(api.column(6).footer()).html(numberWithCommas(totalBalanceDue));
}
});
var savedPageNumber = getCookie('bookpageNumber');
if (savedPageNumber) {
dataTable.page(parseInt(savedPageNumber) - 1).draw(false);
}
dataTable.on('page.dt', function() {
var bookpageNumber = dataTable.page.info().page + 1;
setCookie('bookpageNumber', bookpageNumber, 10);
});
$('#myTable_length select').on('change', function() {
var selectedValue = $(this).val();
dataTable.page.len(selectedValue).draw();
savedPageNumber = getCookie('bookpageNumber');
if (savedPageNumber) {
dataTable.page(parseInt(savedPageNumber) - 1).draw(false);
}
});
});
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
var selectedSecondordnum = null;
var selectedVendorName = null;
$(document).ready(function() {
// 특정 열(td)에서만 클릭 이벤트를 설정합니다.
$('#myTable').on('click', '.choice', function() {
var trElement = $(this).closest('tr');
// .attr()을 사용하여 속성 값을 가져옵니다.
selectedSecondordnum = trElement.attr('data-secondordnum');
selectedVendorName = trElement.attr('data-secondord');
// 데이터가 잘 가져와지는지 콘솔에 출력해봅니다.
console.log("Selected Vendor Name:", selectedVendorName);
console.log("Selected Secondordnum:", selectedSecondordnum);
if (!selectedSecondordnum || !selectedVendorName) {
console.error("secondordnum 또는 vendorName이 제대로 설정되지 않았습니다.");
}
});
// "새 기록" 버튼이 클릭되면 저장된 데이터를 사용합니다.
$('#newRecordButton').on('click', function() {
console.log("Selected Vendor Name:", selectedVendorName);
console.log("Selected Secondordnum:", selectedSecondordnum);
if (selectedVendorName && selectedSecondordnum) {
openNewRecordModal(selectedVendorName, selectedSecondordnum);
} else {
alert('먼저 거래처를 선택하세요.');
}
});
});
function redirectToView(element, secondordnum) {
var selectedSecondordnum = secondordnum;
// 클릭된 <td> 요소의 부모 <tr>에서 data-secondord 속성을 가져옵니다.
var vendorName = $(element).closest('tr').data('secondord');
// 기존에 같은 div가 있다면 제거
$('#recordListModal .modal-header').empty();
$('#recordListModal .vendor-name').empty();
// 거래처명을 표시할 div 요소 생성
var companyNameDiv = $('<div>', {
class: 'd-flex p-1 fs-4 m-1 mb-1 justify-content-center align-items-center vendor-name',
text: vendorName
});
selectedVendorName= vendorName;
// modal header에 거래처명 추가 (기존 h5 태그 위에)
$('#recordListModal .modal-header').prepend('(' + selectedSecondordnum + ')');
$('#recordListModal .modal-header').prepend(companyNameDiv);
$.ajax({
url: 'get_records.php',
type: 'GET',
data: { secondordnum: selectedSecondordnum },
success: function(data) {
try {
// JSON.parse 제거, data는 이미 JSON 객체임
var records = Array.isArray(data) ? data : [];
var recordList = $('#recordList');
recordList.empty();
if (records.length > 0) {
records.forEach(function(record) {
if (!record.primisedate || record.primisedate === '0000-00-00') {
record.primisedate = '';
}
// comment에 줄바꿈이나 특수 문자가 있을 경우 안전하게 변환
let safeComment = JSON.stringify(record.comment)
.replace(/\n/g, '\\n')
.replace(/\r/g, '\\r')
.replace(/"/g, '&quot;') // 큰따옴표 이스케이프
.replace(/'/g, '&#39;'); // 작은따옴표 이스케이프
recordList.append(
'<li class="list-group-item d-flex justify-content-between align-items-center">' +
record.recordTime + ' - ' + safeComment + ' - ' + record.primisedate +
'<button type="button" class="btn btn-danger btn-sm" onclick="deleteRecord(' + record.num + ')">삭제</button>' +
'<button type="button" class="btn btn-secondary btn-sm ms-2" onclick="editRecord(' + record.num + ')">수정</button>' +
'</li>'
);
});
} else {
recordList.append(
'<li class="list-group-item text-center">' +
'기록이 없습니다.' +
'</li>'
);
}
$('#recordListModal').modal('show');
} catch (e) {
console.error("Error processing data: ", e);
}
},
error: function(error) {
alert('오류 발생: ' + error.responseText);
}
});
}
function openNewRecordModal(vendorName, secondordNumber) {
var today = new Date();
// UTC 시간을 기반으로 한국 시간을 계산합니다.
var year = today.getUTCFullYear();
var month = String(today.getUTCMonth() + 1).padStart(2, '0'); // 월은 0부터 시작하므로 1을 더합니다.
var day = String(today.getUTCDate()).padStart(2, '0');
var hours = String(today.getUTCHours() + 9).padStart(2, '0'); // UTC 시간을 기준으로 9시간을 더합니다.
var minutes = String(today.getUTCMinutes()).padStart(2, '0');
if (hours >= 24) {
hours = String(hours - 24).padStart(2, '0');
day = String(parseInt(day) + 1).padStart(2, '0');
}
var formattedDateTime = `${year}-${month}-${day}T${hours}:${minutes}`;
// 기존에 같은 div가 있다면 제거
$('#recordEditModal .modal-header').empty();
$('#recordEditModal .vendor-name').empty();
// 거래처명을 표시할 div 요소 생성
var companyNameDiv = $('<div>', {
class: 'd-flex p-1 fs-4 m-1 mb-1 justify-content-center align-items-center vendor-name',
text: vendorName // 전달된 거래처 이름을 사용
});
// modal header에 거래처명 추가
$('#recordEditModal .modal-header').prepend('(' + secondordNumber + ') ');
$('#recordEditModal .modal-header').prepend(companyNameDiv);
// Set form values
$('#recordNum').val(0);
// $('#primisedate').val(formattedDateTime.substring(0, 10)); // 오늘 날짜를 기본값으로 설정
$('#primisedate').val(null); // 오늘 날짜를 기본값으로 설정
$('#recordTime').val(formattedDateTime); // 현재 시간을 기본값으로 설정
$('#comment').val('');
$('#secondordID').val(secondordNumber);
// Show the modal
$('#recordEditModal').modal('show');
}
function editRecord(num) {
// Ajax 요청으로 고유번호를 이용해 해당 레코드 데이터를 서버에서 가져온다.
$.ajax({
url: 'get_record_by_id.php', // 레코드 데이터를 가져오는 서버측 PHP 파일
type: 'POST',
data: { recordNum: num }, // 고유번호 전달
success: function(response) {
// JSON 데이터를 파싱하여 record 객체로 변환
let record;
try {
record = JSON.parse(response); // response가 JSON 문자열이면 파싱
} catch (e) {
record = response; // 이미 객체일 경우 그대로 사용
}
// 폼 초기화
$('#recordForm')[0].reset();
console.log(record);
if (!record) {
alert('레코드 데이터를 불러오는 데 실패했습니다.');
return;
}
// 기존에 같은 div가 있다면 제거
$('#recordNum').val(record.num);
$('#comment').val(decodeURIComponent(record.comment)); // 한글 인코딩 처리
$('#secondordID').val(record.secondordnum);
// primisedate가 '0000-00-00'일 경우 공백으로 설정
if (record.primisedate === '0000-00-00') {
$('#primisedate').val('');
} else {
$('#primisedate').val(record.primisedate);
}
// 거래처명을 표시할 div 요소 생성
var companyNameDiv = $('<div>', {
class: 'd-flex p-1 fs-4 m-1 mb-1 justify-content-center align-items-center vendor-name',
text: record.secondordnum
});
// modal header에 거래처명 추가
$('#recordEditModal .modal-header').prepend('(' + record.secondordnum + ') ');
$('#recordEditModal .modal-header').prepend(companyNameDiv);
// recordTime이 없을 경우 현재 시간으로 설정
if (!record.recordTime) {
var today = new Date();
today.setHours(today.getHours() + 9); // UTC+9 시간 설정
var formattedDateTime = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}T${String(today.getHours()).padStart(2, '0')}:${String(today.getMinutes()).padStart(2, '0')}`;
$('#recordTime').val(formattedDateTime);
} else {
$('#recordTime').val(record.recordTime);
}
// 모달 창을 열어 수정 폼을 표시
$('#recordEditModal').modal('show');
},
error: function() {
alert('레코드 데이터를 불러오는 데 오류가 발생했습니다.');
}
});
}
$('#recordForm').submit(function(event) {
event.preventDefault();
var formData = $(this).serialize();
$.ajax({
url: 'save_record.php',
type: 'POST',
data: formData,
success: function(data) {
console.log(data);
$('#recordEditModal').modal('hide');
// 테이블에서 해당 행을 찾고 약속일과 메모를 업데이트
var row = $('tr[data-secondordnum="' + data.secondordnum + '"]');
if (row.length > 0) {
row.find('td[data-promisedate]').text(data.primisedate);
row.find('td[data-memo]').text(data.comment);
row.find('td[data-recordTime]').text(data.recordTime);
}
// 모달 닫은 후 리로드
$('#recordListModal').modal('hide');
},
error: function(error) {
alert('오류 발생: ' + error.responseText);
}
});
});
function deleteRecord(num) {
if (confirm('정말로 삭제하시겠습니까?')) {
$.ajax({
url: 'delete_record.php',
type: 'POST',
data: { num: num },
success: function(data) {
// 삭제된 기록의 정보가 반환됩니다.
if (data && data.secondordnum) {
// 테이블에서 해당 행을 찾아서 갱신합니다.
var row = $('tr[data-secondordnum="' + data.secondordnum + '"]');
if (row.length > 0) {
// 약속일과 메모를 비워줍니다.
row.find('td[data-promisedate]').text('');
row.find('td[data-memo]').text('');
row.find('td[data-recordTime]').text('');
}
}
// 폼 초기화
$('#recordForm')[0].reset();
// 모달의 리스트를 다시 로드합니다.
redirectToView(this, data.secondordnum);
},
error: function(error) {
alert('오류 발생: ' + error.responseText);
}
});
}
}
function openMonthlyBalancePopup() {
var url = "monthly_balance_popup.php";
customPopup(url, '거래원장', 1000, 850);
}
function ViewtoCustomerSheet(num) {
var fromdate = '2024-03-01'; // 고정된 시작 날짜
var today = new Date();
var year = today.getFullYear();
var month = String(today.getMonth() + 1).padStart(2, '0');
var day = String(today.getDate()).padStart(2, '0');
var todate = year + '-' + month + '-' + day; // 현재 날짜
var url = "customer_sheet.php?num=" + num + "&fromdate=" + fromdate + "&todate=" + todate;
customPopup(url, '거래원장', 1000, 850);
}
$(document).ready(function(){
saveLogData('미수금 현황');
});
</script>
</body>
</html>

View File

@@ -0,0 +1,668 @@
<?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>
/* 테이블에 테두리 추가 */
#myTable, #myTable th, #myTable td {
border: 1px solid black;
border-collapse: collapse;
}
/* 테이블 셀 패딩 조정 */
#myTable th, #myTable td {
padding: 8px;
text-align: center;
}
</style>
</head>
<body>
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . '/myheader.php');
$search = isset($_REQUEST['search']) ? $_REQUEST['search'] : '';
$fromdate = isset($_REQUEST['fromdate']) ? $_REQUEST['fromdate'] : '';
$todate = isset($_REQUEST['todate']) ? $_REQUEST['todate'] : '';
$mode = isset($_REQUEST['mode']) ? $_REQUEST['mode'] : '';
// 현재 날짜
$currentDate = date("Y-m-d");
// fromdate 또는 todate가 빈 문자열이거나 null인 경우
if ($fromdate === "" || $fromdate === null || $todate === "" || $todate === null) {
// 현재 월의 1일을 fromdate로 설정
$fromdate = date("Y-m-01");
$todate = $currentDate;
$Transtodate = $todate;
} else {
$Transtodate = $todate;
}
function checkNull($strtmp) {
return $strtmp !== null && trim($strtmp) !== '';
}
$tablename = 'account_juil';
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
$inoutsep_select = isset($_REQUEST['inoutsep_select']) ? $_REQUEST['inoutsep_select'] : '';
$content_select = isset($_REQUEST['content_select']) ? $_REQUEST['content_select'] : '';
$order = " ORDER BY registDate ASC, num ASC ";
$sql_conditions = [];
$sql_params = [];
if (checkNull($search)) {
$sql_conditions[] = "searchtag LIKE :search";
$sql_params[':search'] = "%$search%";
}
$sql_conditions[] = "registDate BETWEEN :fromdate AND :todate";
$sql_params[':fromdate'] = $fromdate;
$sql_params[':todate'] = $todate;
$sql_conditions[] = "is_deleted = 0";
if (checkNull($inoutsep_select)) {
$sql_conditions[] = "inoutsep = :inoutsep";
$sql_params[':inoutsep'] = $inoutsep_select;
}
if (checkNull($content_select)) {
$sql_conditions[] = "content = :content";
$sql_params[':content'] = $content_select;
}
$sql = "SELECT * FROM " . $tablename . " WHERE " . implode(' AND ', $sql_conditions) . $order;
try {
$stmh = $pdo->prepare($sql);
foreach ($sql_params as $param => $value) {
$stmh->bindValue($param, $value);
}
$stmh->execute();
$total_row = $stmh->rowCount();
// 수입, 지출을 기반으로 초기 잔액 계산
$initialBalanceSql = "SELECT
SUM(CASE WHEN inoutsep = '수입' THEN amount ELSE 0 END) -
SUM(CASE WHEN inoutsep = '지출' THEN amount ELSE 0 END) AS balance
FROM $tablename WHERE is_deleted = '0' AND registDate < :fromdate";
$initialBalanceStmh = $pdo->prepare($initialBalanceSql);
$initialBalanceStmh->bindParam(':fromdate', $fromdate);
$initialBalanceStmh->execute();
$initialBalance = $initialBalanceStmh->fetch(PDO::FETCH_ASSOC)['balance'];
$totalIncomeSql = "SELECT SUM(amount) AS totalIncome FROM $tablename WHERE is_deleted = '0' AND inoutsep = '수입' AND registDate BETWEEN :fromdate AND :todate";
$totalIncomeStmh = $pdo->prepare($totalIncomeSql);
$totalIncomeStmh->bindParam(':fromdate', $fromdate);
$totalIncomeStmh->bindParam(':todate', $todate);
$totalIncomeStmh->execute();
$totalIncome = $totalIncomeStmh->fetch(PDO::FETCH_ASSOC)['totalIncome'];
$totalExpenseSql = "SELECT SUM(amount) AS totalExpense FROM $tablename WHERE is_deleted = '0' AND inoutsep = '지출' AND registDate BETWEEN :fromdate AND :todate";
$totalExpenseStmh = $pdo->prepare($totalExpenseSql);
$totalExpenseStmh->bindParam(':fromdate', $fromdate);
$totalExpenseStmh->bindParam(':todate', $todate);
$totalExpenseStmh->execute();
$totalExpense = $totalExpenseStmh->fetch(PDO::FETCH_ASSOC)['totalExpense'];
$finalBalance = $initialBalance + $totalIncome - $totalExpense;
// Bankbook options
$bankbookOptions = [];
$bankbookFilePath = $_SERVER['DOCUMENT_ROOT'] . "/account_juil/bankbook.txt";
if (file_exists($bankbookFilePath)) {
$bankbookOptions = file($bankbookFilePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
}
?>
<form id="board_form" name="board_form" method="post" enctype="multipart/form-data">
<input type="hidden" id="mode" name="mode" value="<?=$mode?>">
<input type="hidden" id="num" name="num">
<input type="hidden" id="tablename" name="tablename" value="<?=$tablename?>">
<div class="container-fluid">
<!-- Modal -->
<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">
<div class="card justify-content-center text-center mt-5">
<div class="card-header">
<span class="text-center fs-5"> <?=$title_message?> </span>
</div>
<div class="card-body">
<div class="d-flex justify-content-center align-items-center mt-2">
<span>
▷ <?= $total_row ?> &nbsp;
</span>
<!-- 기간부터 검색까지 연결 묶음 start -->
<span id="showdate" class="btn btn-dark btn-sm">기간</span> &nbsp;
<div id="showframe" class="card">
<div class="card-header" style="padding:2px;">
<div class="d-flex justify-content-center align-items-center">
기간 설정
</div>
</div>
<div class="card-body">
<div class="d-flex justify-content-center align-items-center">
<button type="button" class="btn btn-outline-success btn-sm me-1 change_dateRange" onclick='alldatesearch()'>전체</button>
<button type="button" class="btn btn-outline-primary btn-sm me-1 change_dateRange" onclick='pre_year()'>전년도</button>
<button type="button" class="btn btn-dark btn-sm me-1 change_dateRange" onclick='pre_month()'>전월</button>
<button type="button" class="btn btn-dark btn-sm me-1 change_dateRange" onclick='dayBeforeYesterday()'>전전일</button>
<button type="button" class="btn btn-dark btn-sm me-1 change_dateRange" onclick='yesterday()'>전일</button>
<button type="button" class="btn btn-outline-danger btn-sm me-1 change_dateRange" onclick='this_today()'>오늘</button>
<button type="button" class="btn btn-dark btn-sm me-1 change_dateRange" onclick='this_month()'>당월</button>
<button type="button" class="btn btn-dark btn-sm me-1 change_dateRange" onclick='this_year()'>당해년도</button>
</div>
</div>
</div>
<input type="date" id="fromdate" name="fromdate" class="form-control" style="width:110px;" value="<?=$fromdate?>"> &nbsp; ~ &nbsp;
<input type="date" id="todate" name="todate" class="form-control me-1" style="width:110px;" value="<?=$todate?>"> &nbsp;
<!-- 첫 번째 select 문: 수입/지출 구분 -->
<select id="inoutsep_select" name="inoutsep_select" class="form-control me-1" style="width:50px;">
<option value="">전체</option>
<option value="수입" <?= $inoutsep_select === '수입' ? 'selected' : '' ?>>수입</option>
<option value="지출" <?= $inoutsep_select === '지출' ? 'selected' : '' ?>>지출</option>
</select>
<!-- 두 번째 select 문: 항목 선택 -->
<select id="content_select" name="content_select" class="form-control me-1" style="width:100px;">
<option value="">전체</option>
<?php
$incomeOptions = [
'거래처 수금' => '거래처에서 입금한 금액',
'최초 현금 입력' => '금전출납부 시작'
];
$expenseOptions = [
'급여(인건비)' => '직원 급여',
'접대비' => '경조사비용',
'통신비' => '전화요금, 인터넷요금',
'세금과공과금' => '등록면허세, 취득세, 재산세등 각종세금',
'차량유지비' => '유류대, 통행료',
'보험료' => '차량보험료, 화재보험료등',
'운반비' => '택배운반비외 각종운반비',
'소모품비' => '각종 소모품 비용',
'수수료비용' => '이체수수료, 등기수수료등',
'복리후생비' => '직원 식대외 직원 작업복등',
'개발비' => '프로그램 개발비용',
'이자비용' => '이자비용',
'카드대금' => '카드대금',
'통관비' => '통관비',
'자재비' => '자재비'
];
$options = array_merge(array_keys($incomeOptions), array_keys($expenseOptions));
foreach ($options as $option) {
$selected = ($content_select === $option) ? 'selected' : '';
echo "<option value=\"$option\" $selected>$option</option>";
}
?>
</select>
<div class="inputWrap30">
<input type="text" id="search" class="form-control" style="width:150px;" name="search" value="<?=$search?>" onKeyPress="if (event.keyCode==13){ enter(); }">
<button class="btnClear"></button>
</div>
&nbsp;&nbsp;
<button class="btn btn-outline-dark btn-sm" type="button" id="searchBtn"> <i class="bi bi-search"></i> </button> &nbsp;&nbsp;&nbsp;&nbsp;
<button id="newBtn" type="button" class="btn btn-dark btn-sm me-2"> <i class="bi bi-pencil-square"></i> 신규 </button>
<button type="button" class="btn btn-secondary btn-sm me-1" onclick='location.reload();'> <i class="bi bi-arrow-clockwise"></i> 새로고침 </button>
<button type="button" class="btn btn-dark btn-sm me-2" onclick="generateExcel();" > <i class="bi bi-file-earmark-spreadsheet"></i> 엑셀다운로드 </button>
</div>
</div>
<div class="row w400px m-1 mt-2">
<table class="table table-bordered">
<thead class="table-secondary">
<tr>
<?php
$tmp = ' ' . $bankbookOptions[0] . ' (계좌 잔액) : ';
if (isset($finalBalance)) {
$tmp_balance = number_format($finalBalance);
}
?>
<th class="text-center" style="width:200px;"> <?=$tmp?> </th>
<th class="text-end text-primary fw-bold" style="width:100px;"> <?=$tmp_balance?> </th>
</tr>
</thead>
</table>
</div>
<div class="table-responsive">
<table class="table table-hover" id="myTable">
<thead class="table-info">
<tr>
<th class="text-center" style="width:60px;">번호</th>
<th class="text-center" style="width:100px;">등록일자</th>
<th class="text-center" style="width:100px;">항목</th>
<th class="text-center" style="width:150px;">상세내용</th>
<th class="text-center" style="width:100px;">수입</th>
<th class="text-center" style="width:100px;">지출</th>
<th class="text-center" style="width:100px;">잔액</th>
<th class="text-center" style="width:200px;">적요</th>
</tr>
</thead>
<tbody>
<?php
$start_num = $total_row;
$counter = 1;
$balance = $initialBalance; // 초기 잔액 설정
while($row = $stmh->fetch(PDO::FETCH_ASSOC)) {
include '_row.php';
if ($inoutsep === '수입') {
$balance += $amount;
} else {
$balance -= $amount;
}
?>
<tr onclick="loadForm('update', '<?=$num?>');">
<td class="text-center"><?= $counter ?></td>
<td class="text-center"><?= $registDate ?></td>
<td class="text-center fw-bold "> <?= $content ?> </td>
<td class="text-start"><?= $content_detail ?></td>
<?php if ($inoutsep === '수입') : ?>
<td class="text-end fw-bold text-primary">
<?= is_numeric($amount) ? number_format($amount) : htmlspecialchars($amount) ?>
</td>
<td class="text-end"></td>
<?php else : ?>
<td class="text-end"></td>
<td class="text-end fw-bold text-danger">
<?= is_numeric($amount) ? number_format($amount) : htmlspecialchars($amount) ?>
</td>
<?php endif; ?>
<td class="text-end fw-bold"><?= number_format($balance) ?></td>
<td class="text-start"><?= $dueDate ?></td>
</tr>
<?php
$start_num--;
$counter++;
}
} catch (PDOException $Exception) {
print "오류: ".$Exception->getMessage();
}
?>
</tbody>
<tfoot class="table-secondary">
<tr>
<th class="text-end" colspan="4"> 합계 &nbsp; </th>
<th class="text-end" id="totalIncomeAmount"></th>
<th class="text-end" id="totalExpenseAmount"></th>
<th class="text-end" id="totalBalanceAmount"></th>
<th class="text-end"></th>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
</form>
</body>
</html>
<script>
// 페이지 로딩
$(document).ready(function(){
var loader = document.getElementById('loadingOverlay');
loader.style.display = 'none';
});
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
document.addEventListener('DOMContentLoaded', function() {
const initialBalance = <?= json_encode($initialBalance) ?>;
const finalBalance = <?= json_encode($finalBalance) ?>;
$(document).ready(function() {
dataTable = $('#myTable').DataTable({
"paging": true,
"ordering": true,
"searching": true,
"pageLength": 2000,
"lengthMenu": [2000],
"language": {
"lengthMenu": "Show _MENU_ entries",
"search": "Live Search:"
},
// "order": [[0, 'desc']],
"dom": 't<"bottom"ip>',
"footerCallback": function (row, data, start, end, display) {
var api = this.api(), data;
var intVal = function (i) {
return typeof i === 'string' ?
i.replace(/[\$,]/g, '')*1 :
typeof i === 'number' ?
i : 0;
};
totalIncomeAmount = api.column(4, { page: 'current' }).data().reduce(function (a, b) { return intVal(a) + intVal(b); }, 0);
totalExpenseAmount = api.column(5, { page: 'current' }).data().reduce(function (a, b) { return intVal(a) + intVal(b); }, 0);
$(api.column(4).footer()).html(numberWithCommas(totalIncomeAmount));
$(api.column(5).footer()).html(numberWithCommas(totalExpenseAmount));
$(api.column(6).footer()).html(numberWithCommas(finalBalance));
}
});
});
});
</script>
<script>
let isSaving = false;
var ajaxRequest = null;
document.addEventListener('DOMContentLoaded', function() {
$("#newBtn").on("click", function() {
loadForm('insert');
});
$("#searchBtn").on("click", function() {
$("#board_form").submit();
});
});
function loadForm(mode, num = null) {
if (num == null) {
$("#mode").val('insert');
} else {
$("#mode").val('update');
$("#num").val(num);
}
if (ajaxRequest !== null) {
ajaxRequest.abort();
}
ajaxRequest = $.ajax({
type: "POST",
url: "fetch_modal.php",
data: { mode: mode, num: num },
dataType: "html",
success: function(response) {
document.querySelector(".modal-body .custom-card").innerHTML = response;
$("#myModal").show();
const expenseOptions = {
'급여(인건비)': '직원 급여',
'접대비': '경조사비용',
'통신비': '전화요금, 인터넷요금',
'세금과공과금': '등록면허세, 취득세, 재산세등 각종세금',
'차량유지비': '유류대, 통행료',
'보험료': '차량보험료, 화재보험료등',
'운반비': '택배운반비외 각종운반비',
'소모품비': '각종 소모품 비용',
'수수료비용': '이체수수료, 등기수수료등',
'복리후생비': '직원 식대외 직원 작업복등',
'개발비': '프로그램 개발비용',
'이자비용': '이자비용',
'카드대금': '카드대금',
'통관비': '통관비',
'자재비': '자재비',
'기계장치' : '기계구입'
};
const incomeOptions = {
'거래처 수금': '거래처에서 입금한 금액',
'최초 현금 입력': '금전출납부 시작'
};
function updateDescription() {
const contentSelect = document.getElementById('content');
const descriptionDiv = document.getElementById('content_description');
if (contentSelect && descriptionDiv) {
const selectedValue = contentSelect.value;
const descriptions = document.querySelector('input[name="inoutsep"]:checked').value === '수입' ? incomeOptions : expenseOptions;
descriptionDiv.innerText = descriptions[selectedValue] || '';
}
}
function updateContentOptions() {
const contentSelect = document.getElementById('content');
if (contentSelect) {
contentSelect.innerHTML = '';
const options = document.querySelector('input[name="inoutsep"]:checked').value === '수입' ? incomeOptions : expenseOptions;
for (const [value, text] of Object.entries(options)) {
const option = document.createElement('option');
option.value = value;
option.text = value;
contentSelect.appendChild(option);
}
updateDescription();
}
}
// 추가된 스크립트를 실행하도록 보장
// updateContentOptions();
$(document).on("click", "#closeBtn", function() {
$("#myModal").hide();
});
$(document).on("click", "#saveBtn", function() {
// if (isSaving) return;
// isSaving = true;
// AJAX 요청을 보냄
if (ajaxRequest !== null) {
ajaxRequest.abort();
}
ajaxRequest = $.ajax({
url: "/account_juil/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(),
dueDate: $("#dueDate").val(),
first_writer: $("#first_writer").val(),
content_detail: $("#content_detail").val(),
bankbook: $("#bankbook").val()
},
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); // 1.5초 후 실행
},
error: function(jqxhr, status, error) {
console.log("AJAX Error: ", status, error);
// 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();
$.ajax({
url: "/account_juil/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();
});
// 항목 선택 변경 시 설명 업데이트
$(document).on("change", "#content", updateDescription);
$(document).on("change", "input[name='inoutsep']", updateContentOptions);
},
error: function(jqxhr, status, error) {
console.log("AJAX error in loadForm:", status, error);
}
});
}
// 페이지 로딩
$(document).ready(function(){
var loader = document.getElementById('loadingOverlay');
loader.style.display = 'none';
});
</script>
<script>
function generateExcel() {
var table = document.getElementById('myTable');
var rows = table.getElementsByTagName('tr');
var data = [];
// 각 행을 반복하여 데이터 수집
for (var i = 1; i < rows.length; i++) { // 헤더 행을 건너뜀
var cells = rows[i].getElementsByTagName('td');
var rowData = {};
rowData['number'] = cells[0]?.innerText || '';
rowData['registDate'] = cells[1]?.innerText || '';
rowData['content'] = cells[2]?.innerText || '';
rowData['contentDetail'] = cells[3]?.innerText || '';
rowData['income'] = cells[4]?.innerText || '';
rowData['expense'] = cells[5]?.innerText || '';
rowData['balance'] = cells[6]?.innerText || '';
rowData['dueDate'] = cells[7]?.innerText || '';
data.push(rowData);
}
// saveExcel.php에 데이터 전송
var xhr = new XMLHttpRequest();
xhr.open("POST", "order_saveExcel.php", true);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
try {
var response = JSON.parse(xhr.responseText);
if (response.success) {
console.log('Excel file generated successfully.');
// 다운로드 스크립트로 리디렉션
window.location.href = 'downloadExcel.php?filename=' + encodeURIComponent(response.filename.split('/').pop());
} else {
console.log('Failed to generate Excel file: ' + response.message);
}
} catch (e) {
console.log('Error parsing response: ' + e.message + '\nResponse text: ' + xhr.responseText);
}
} else {
console.log('Failed to generate Excel file: Server returned status ' + xhr.status);
}
}
};
xhr.send(JSON.stringify(data));
}
</script>

View File

@@ -0,0 +1,26 @@
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$fileName = $_POST['fileName'] ?? 'accountContents.json';
$backupFileName = $_POST['backupFileName'] ?? '';
$data = $_POST['data'] ?? '';
// JSON 폴더 경로 확인 및 생성
$jsonFolder = $_SERVER['DOCUMENT_ROOT'] . '/account_juil/json/'; //################### 폴더 위치 주의 //
if (!is_dir($jsonFolder)) {
mkdir($jsonFolder, 0755, true); // 폴더 생성
}
// 데이터 저장
if (!empty($backupFileName)) {
$backupFilePath = $jsonFolder . basename($backupFileName);
file_put_contents($backupFilePath, $data); // 백업 파일 저장
}
$filePath = basename($fileName);
file_put_contents($filePath, $data); // 원본 파일 저장
echo json_encode(['message' => '데이터가 저장되었습니다.']);
} else {
http_response_code(405);
echo json_encode(['message' => 'Invalid request method.']);
}

View File

@@ -0,0 +1,90 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// JSON 데이터 받기
$jsonData = file_get_contents('php://input');
$data = json_decode($jsonData, true);
if (!$data) {
echo json_encode(['success' => false, 'message' => 'Invalid JSON data']);
exit;
}
// PHPExcel 라이브러리 포함
require_once($_SERVER['DOCUMENT_ROOT'] . '/PHPExcel_1.8.0/Classes/PHPExcel.php');
// 새로운 PHPExcel 객체 생성
$objPHPExcel = new PHPExcel();
$objPHPExcel->setActiveSheetIndex(0);
$sheet = $objPHPExcel->getActiveSheet();
// 헤더 설정
$headers = ['번호', '등록일자', '항목', '세부항목', '상세내용', '수입', '지출', '잔액', '적요'];
$col = 'A';
foreach ($headers as $header) {
$sheet->setCellValue($col . '1', $header);
// 헤더 스타일 설정
$sheet->getStyle($col . '1')->getFont()->setBold(true);
$sheet->getStyle($col . '1')->getFill()->setFillType(PHPExcel_Style_Fill::FILL_SOLID);
$sheet->getStyle($col . '1')->getFill()->getStartColor()->setRGB('D9D9D9');
$col++;
}
// 데이터 입력
$row = 2;
foreach ($data as $item) {
$sheet->setCellValue('A' . $row, $item['number']);
$sheet->setCellValue('B' . $row, $item['registDate']);
$sheet->setCellValue('C' . $row, $item['content']);
$sheet->setCellValue('D' . $row, $item['contentSub']);
$sheet->setCellValue('E' . $row, $item['contentDetail']);
$sheet->setCellValue('F' . $row, $item['income']);
$sheet->setCellValue('G' . $row, $item['expense']);
$sheet->setCellValue('H' . $row, $item['balance']);
$sheet->setCellValue('I' . $row, $item['dueDate']);
$row++;
}
// 열 너비 자동 조정
foreach(range('A','I') as $columnID) {
$sheet->getColumnDimension($columnID)->setAutoSize(true);
}
// 파일 저장
$filename = 'account_' . date('Ymd_His') . '.xlsx';
$filepath = $_SERVER['DOCUMENT_ROOT'] . '/account_juil/excel/' . $filename;
// 디렉토리가 없으면 생성
if (!file_exists($_SERVER['DOCUMENT_ROOT'] . '/account_juil/excel')) {
mkdir($_SERVER['DOCUMENT_ROOT'] . '/account_juil/excel', 0777, true);
}
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
$objWriter->save($filepath);
echo json_encode(['success' => true, 'filename' => $filename]);
exit;
}
else if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['download'])) {
// 파일 다운로드 처리
$filename = $_GET['download'];
$filepath = $_SERVER['DOCUMENT_ROOT'] . '/account_juil/excel/' . $filename;
if (file_exists($filepath)) {
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Cache-Control: max-age=0');
readfile($filepath);
// 파일 삭제
unlink($filepath);
exit;
} else {
echo "File not found";
exit;
}
} else {
echo json_encode(['success' => false, 'message' => 'Invalid request method']);
exit;
}

394
account_juil/settings.php Normal file
View File

@@ -0,0 +1,394 @@
<?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 = '계정관리(수입,지출)';
?>
<title> <?=$title_message?> </title>
<style>
.editable {
cursor: pointer;
}
/* +, - 버튼 패딩 2px 4px로 */
.add-main-account, .add-sub-account, .delete-account {
padding: 2px 4px !important;
}
/* 각 list 아이템의 padding을 절반으로 */
.list-group-item {
padding-top: 0.5rem !important;
padding-bottom: 0.5rem !important;
padding-left: 0.75rem !important;
padding-right: 0.75rem !important;
}
/* card 요소의 여백(패딩/마진) 절반으로 줄이기 */
.card {
padding: 0.5rem !important;
margin-bottom: 0.5rem !important;
}
.card-body, .card-header, .card-footer {
padding: 0.5rem !important;
}
/* 1단계 트리 노드(최상위 계정) 폰트 크기 크게 */
.editable[data-level="0"] {
font-size: 1.15rem;
font-weight: 600;
}
</style>
</head>
<body>
<div class="container mt-4">
<div class="d-flex justify-content-start mb-1">
<h3>수입/지출 계정 관리</h3> <button type="button" class="btn btn-dark btn-sm ms-3 me-2" onclick='location.reload()'> <i class="bi bi-arrow-clockwise"></i> </button>
</div>
<div class="d-flex justify-content-end mb-3">
<button class="btn btn-dark btn-sm me-1 ms-1 saveData">
<i class="bi bi-floppy2-fill"></i> 저장
</button>
<button class="btn btn-secondary btn-sm" onclick="self.close();">
<i class="bi bi-x-lg"></i> 닫기
</button>
</div>
<ul id="accountList" class="list-group"></ul>
</div>
<script>
$(document).ready(function () {
// 로딩 오버레이 제거
var loader = $('#loadingOverlay');
if (loader.length) {
loader.hide();
}
const fileName = '/account_juil/accountContents.json';
let accountData = {}; // 데이터를 전역 변수로 관리
/*캐시 문제
$.getJSON(fileName, ...)로 JSON 파일을 불러올 때, 브라우저가 파일을 캐시하고 있을 가능성이 있습니다. 이 경우 파일을 저장한 후에도 이전 캐시된 데이터가 불러와져 최신 수정 내용이 반영되지 않을 수 있습니다.
해결 방법으로는 AJAX 요청 시 캐시 방지 파라미터(예: 타임스탬프)를 추가하거나, jQuery의 AJAX 설정에서 cache: false 옵션을 사용하는 방법이 있습니다.
*/
function loadAccounts() {
$.getJSON(fileName + '?_=' + new Date().getTime(), function (data) {
// console.log('Loaded Account Data:', data);
accountData = data;
renderAccounts(data);
}).fail(function () {
alert('JSON 파일을 로드할 수 없습니다.');
});
}
// JSON 데이터 저장
function saveAccounts() {
const now = new Date();
const formattedDate = now.toISOString().slice(0, 10).replace(/-/g, '');
const formattedTime = now.toTimeString().slice(0, 8).replace(/:/g, '');
const backupFileName = `${formattedDate}_${formattedTime}_backup.json`;
$.post('/account_juil/saveAccountContents.php', {
fileName,
backupFileName,
data: JSON.stringify(accountData)
}, function (response) {
const result = JSON.parse(response);
Swal.fire('저장 완료', `데이터가 서버에 저장되었습니다.\n백업 파일: ${backupFileName}`, 'success');
setTimeout(function() {
// 부모 창 리로드
if (window.opener && !window.opener.closed) {
window.opener.location.reload();
}
// 자신을 1.5초 후 리로드
setTimeout(function() {
window.location.reload();
}, 2000);
}, 1500);
});
}
// 계정 렌더링
function renderAccounts(data) {
$('#accountList').empty();
$.each(data, function (category, accounts) {
const categoryItem = $(`<li class="list-group-item">
<span class="editable" data-category="${category}" data-level="0">${category}</span>
<button class="btn btn-sm btn-outline-primary ms-2 add-main-account" data-category="${category}">+</button>
<ul class="list-group mt-2 ms-3"></ul>
</li>`);
const subAccountList = categoryItem.find('ul');
$.each(accounts, function (accountName, accountDetails) {
appendAccountItem(subAccountList, category, accountName, accountDetails, category);
});
$('#accountList').append(categoryItem);
});
}
// 하위 계정 추가
function appendAccountItem(parentList, category, accountName, accountDetails, parentName) {
// 디버깅용 로그 추가
// console.log('Appending Account:', {
// category,
// accountName,
// accountDetails,
// parentName,
// });
// 추가 버튼 여부 결정
const addButton = accountDetails.level < 2 ? `
<button class="btn btn-sm btn-outline-primary ms-2 add-sub-account"
data-category="${category}"
data-account="${accountName}">
+
</button>
` : ''; // level 3에서는 추가 버튼이 나오지 않음
const accountItem = $(`<li class="list-group-item">
<span class="editable"
data-category="${category}"
data-account="${accountName}"
data-level="${accountDetails.level}"
data-description="${accountDetails.description}"
data-parent="${parentName}">
${accountName}
</span>
${addButton}
<button class="btn btn-sm btn-outline-danger ms-2 delete-account"
data-category="${category}"
data-account="${accountName}">
-
</button>
<ul class="list-group mt-2 ms-3"></ul>
</li>`);
const subAccountList = accountItem.find('ul');
// 하위 계정이 있을 경우 처리
if (accountDetails.하위계정 && accountDetails.하위계정.length > 0) {
accountDetails.하위계정.forEach(subAccount => {
const subAccountName = Object.keys(subAccount)[0];
const subAccountDetails = subAccount[subAccountName];
// 디버깅용 로그 추가
// console.log('Appending Sub Account:', {
// subAccountName,
// subAccountDetails,
// });
appendAccountItem(subAccountList, category, subAccountName, subAccountDetails, accountName);
});
} else {
console.log(`No Sub Accounts for: ${accountName}`);
}
parentList.append(accountItem);
}
// 계정 추가
function addAccount(category, parentAccount, name, description, isMain) {
if (isMain) {
accountData[category][name] = {
level: 1,
description,
parent: category,
하위계정: []
};
} else {
const parent = accountData[category][parentAccount];
if (!parent.하위계정) parent.하위계정 = [];
parent.하위계정.push({
[name]: {
level: (parent.level || 1) + 1,
description,
parent: parentAccount,
하위계정: []
}
});
}
}
// 계정 삭제
function deleteAccount(category, account) {
const parentAccount = accountData[category];
if (parentAccount[account]) {
delete parentAccount[account];
} else {
// Find and delete in subaccounts
$.each(parentAccount, function (key, value) {
if (value.하위계정) {
const index = value.하위계정.findIndex(sub => Object.keys(sub)[0] === account);
if (index !== -1) {
value.하위계정.splice(index, 1);
return false; // Exit loop
}
}
});
}
}
// 계정 수정
$('#accountList').on('click', '.editable', function () {
const currentName = $(this).text().trim(); // 현재 계정 이름
const currentDescription = $(this).data('description') || ''; // 현재 설명
const parentCategory = $(this).closest('ul').closest('li').find('> .editable').data('category'); // 최상위 카테고리
const level = $(this).data('level'); // 계정 레벨 정보
// 디버깅 정보 출력
// console.log('DEBUG: currentName =', currentName);
// console.log('DEBUG: currentDescription =', currentDescription);
// console.log('DEBUG: parentCategory =', parentCategory);
// console.log('DEBUG: level =', level);
// 최상위 레벨은 수정 불가
if (level !== 1 && level !== 2 ) {
Swal.fire('알림', '최상위 계정은 수정할 수 없습니다.', 'info');
return;
}
Swal.fire({
title: '계정 수정',
html: `
<input type="text" id="accountName" class="swal2-input" placeholder="새 계정 이름" value="${currentName}" autocomplete="off">
<input type="text" id="accountDescription" class="swal2-input" placeholder="새 계정 설명" value="${currentDescription}" autocomplete="off">
`,
showCancelButton: true,
confirmButtonText: '수정',
cancelButtonText: '취소',
preConfirm: () => {
const newName = $('#accountName').val().trim();
const newDescription = $('#accountDescription').val().trim();
if (!newName || !newDescription) {
Swal.showValidationMessage('모든 입력란을 채워주세요.');
}
return { newName, newDescription };
}
}).then((result) => {
if (result.isConfirmed) {
const { newName, newDescription } = result.value;
try {
let found = false;
// 최상위 카테고리 탐색
if (accountData[parentCategory]) {
$.each(accountData[parentCategory], function (key, value) {
if (key === currentName) {
// 최상위 계정 수정
accountData[parentCategory][newName] = value;
delete accountData[parentCategory][currentName];
accountData[parentCategory][newName].description = newDescription;
found = true;
return false; // 루프 종료
}
// 하위 계정 탐색
if (value.하위계정) {
value.하위계정.forEach((subAccount, index) => {
const subAccountName = Object.keys(subAccount)[0];
if (subAccountName === currentName) {
// 하위 계정 수정
value.하위계정[index] = {
[newName]: {
...subAccount[subAccountName],
description: newDescription
}
};
found = true;
return false; // 루프 종료
}
});
}
});
}
if (!found) {
throw new Error(`계정을 찾을 수 없습니다. currentName: ${currentName}, parentCategory: ${parentCategory}`);
}
renderAccounts(accountData); // UI 업데이트
} catch (error) {
console.error('Error updating account:', error);
Swal.fire('오류', `계정을 수정하는 중 문제가 발생했습니다.\n${error.message}`, 'error');
}
}
});
});
// 버튼 핸들러
$('#accountList').on('click', '.add-main-account, .add-sub-account, .delete-account', function () {
const isMain = $(this).hasClass('add-main-account');
const isDelete = $(this).hasClass('delete-account');
const category = $(this).data('category');
const account = $(this).data('account');
if (isDelete) {
Swal.fire({
title: '삭제 확인',
text: '해당 계정을 삭제하시겠습니까?',
icon: 'warning',
showCancelButton: true,
confirmButtonText: '삭제',
cancelButtonText: '취소'
}).then(result => {
if (result.isConfirmed) {
deleteAccount(category, account);
renderAccounts(accountData);
}
});
} else {
Swal.fire({
title: isMain ? `${category}의 하위 계정 추가` : `${account}의 하위 계정 추가`,
html: `
<input type="text" id="accountName" class="swal2-input" placeholder="계정 이름" autocomplete="off">
<input type="text" id="accountDescription" class="swal2-input" placeholder="계정 설명" autocomplete="off">
`,
focusConfirm: false,
showCancelButton: true,
preConfirm: () => {
const name = $('#accountName').val().trim();
const description = $('#accountDescription').val().trim();
if (!name || !description) {
Swal.showValidationMessage('모든 입력란을 채워주세요.');
}
return { name, description };
}
}).then(result => {
if (result.isConfirmed) {
const { name, description } = result.value;
addAccount(category, account, name, description, isMain);
renderAccounts(accountData);
}
});
}
});
// 저장 버튼 클릭
$('.saveData').on('click', saveAccounts);
loadAccounts();
});
</script>
</body>
</html>