초기 커밋: 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,442 @@
<?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>
/* 테이블에 테두리 추가 */
#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
require_once($_SERVER['DOCUMENT_ROOT'] . '/myheader.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';
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-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 mt-5">
<div class="card justify-content-center text-center mt-5">
<div class="card-header">
<span class="text-center fs-5"> <?=$title_message?>
<button type="button" class="btn btn-dark btn-sm me-1" onclick='location.reload()'> <i class="bi bi-arrow-clockwise"></i> </button>
</span>
</div>
<div class="card-body">
<!-- <div class="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="row mb-3">
<div class="d-flex justify-content-center align-items-center">
<select id="year" name="year" class="form-control me-2" style="width:80px;" 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-control me-1" style="width:60px;" 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-control me-5 " style="width:60px;" onchange="loadDetails()">
<?php for ($i = 1; $i <= 12; $i++): ?>
<option value="<?=$i?>" <?=($endMonth == $i) ? 'selected' : ''?>><?=$i?>월</option>
<?php endfor; ?>
</select>
<button id="newBtn" type="button" class="btn btn-dark btn-sm me-2"> <i class="bi bi-pencil-square"></i> 신규 </button>
</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>
</form>
</body>
</html>
<script>
let isSaving = false;
var ajaxRequest = null;
// 페이지 로딩
$(document).ready(function(){
var loader = document.getElementById('loadingOverlay');
loader.style.display = 'none';
$("#newBtn").on("click", function() {
loadForm('insert');
});
});
// 모달창에 내용을 넣는 구조임 모달을 부르고 내용을 동적으로 넣는다.
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_plan.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');
const selectedValue = contentSelect.value;
// 수입인지 지출인지에 따라 설명 변경
const descriptions = document.querySelector('input[name="inoutsep"]:checked').value === '수입' ? incomeOptions : expenseOptions;
descriptionDiv.innerText = descriptions[selectedValue] || '';
// '거래처 수금'이 선택되었을 때 전화번호 검색 화면을 띄움
if (selectedValue === '거래처 수금') {
phonebookBtn('');
}
}
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/insert_plan.php",
type: "post",
data: {
mode: $("#mode").val(),
num: $("#num").val(),
update_log: $("#update_log").val(),
registDate: $("#registDate").val(),
inoutsep: $("input[name='inoutsep']:checked").val(),
content: $("#content").val(),
amount: $("#amount").val(),
memo: $("#memo").val(),
first_writer: $("#first_writer").val(),
content_detail: $("#content_detail").val(),
bankbook: $("#bankbook").val(),
secondordnum: $("#secondordnum").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/insert_plan.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);
}
});
}
// 기존 loadDetails 함수 유지
function loadDetails() {
const year = document.getElementById('year').value;
const startMonth = document.getElementById('startMonth').value;
const endMonth = document.getElementById('endMonth').value;
window.location.href = `MonthAccountPlan.php?year=${year}&startMonth=${startMonth}&endMonth=${endMonth}`;
}
// 새로운 함수 추가: 특정 월 선택 시 호출
function loadSpecificMonth(month) {
const year = document.getElementById('year').value;
window.location.href = `MonthAccountPlan.php?year=${year}&startMonth=${month}&endMonth=${month}`;
}
</script>

19
account_plan/_request.php Normal file
View File

@@ -0,0 +1,19 @@
<?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'] : '';
$amount = isset($_REQUEST['amount']) ? $_REQUEST['amount'] : '';
$memo = isset($_REQUEST['memo']) ? $_REQUEST['memo'] : '';
$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'] : '';
$ForeDate = isset($_REQUEST['ForeDate']) ? $_REQUEST['ForeDate'] : '';
$approvalRequest = isset($_REQUEST['approvalRequest']) ? $_REQUEST['approvalRequest'] : '';
$eworksNum = isset($_REQUEST['eworksNum']) ? $_REQUEST['eworksNum'] : '';
$workDone = isset($_REQUEST['workDone']) ? $_REQUEST['workDone'] : '';
?>

19
account_plan/_row.php Normal file
View File

@@ -0,0 +1,19 @@
<?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'] : '';
$amount = isset($row['amount']) ? $row['amount'] : '';
$memo = isset($row['memo']) ? $row['memo'] : '';
$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'] : '';
$ForeDate = isset($row['ForeDate']) ? $row['ForeDate'] : '';
$approvalRequest = isset($row['approvalRequest']) ? $row['approvalRequest'] : '';
$eworksNum = isset($row['eworksNum']) ? $row['eworksNum'] : '';
$workDone = isset($row['workDone']) ? $row['workDone'] : '';
?>

View File

@@ -0,0 +1 @@
국민은행 253401-04-381605

View File

@@ -0,0 +1,111 @@
<?php
/**
* 대량등록 모달에서 전달된 데이터를 account_plan 테이블에 저장
*/
ob_start();
header('Content-Type: application/json; charset=utf-8');
// 세션 및 권한 검사
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
if (!isset($_SESSION["level"]) || $_SESSION["level"] > 5) {
ob_end_clean();
echo json_encode(['status' => 'error', 'message' => '권한이 없습니다.']);
exit;
}
// DB 연결
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
$DB = 'chandj';
$tablename = 'account_plan';
// 클라이언트로부터 JSON 받기
$input = file_get_contents('php://input');
$data = json_decode($input, true);
// 자바스크립트에서 _bulk는 제거되서 넘어옴
if (empty($data['entries']) || !is_array($data['entries'])) {
ob_end_clean();
echo json_encode(['status' => 'error', 'message' => '저장할 데이터가 없습니다.']);
exit;
}
try {
$pdo->beginTransaction();
$insertedCount = 0;
$errors = [];
$sql = "INSERT INTO {$DB}.{$tablename} (
registDate, inoutsep, content, amount, memo,
ForeDate, first_writer, searchtag, update_log
) VALUES (
:registDate, :inoutsep, :content, :amount, :memo,
:ForeDate, :first_writer, :searchtag, :update_log
)";
$stmt = $pdo->prepare($sql);
foreach ($data['entries'] as $entry) {
// bulk 필드에서 원본 컬럼으로 매핑
$registDate = $entry['registDate'] ?? date('Y-m-d');
$inoutsep = $entry['inoutsep'] ?? '';
$content = $entry['content'] ?? '';
$amount = str_replace(',', '', $entry['amount']) ?? '' ;
$memo = $entry['memo'] ?? '';
$ForeDate = $entry['ForeDate'] ?? '';
// Construct the searchtag value
$searchtag = $registDate . ' ' . $inoutsep . ' ' . $content . ' ' . $amount . $memo ;
$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";
$ok = $stmt->execute([
':registDate' => $registDate,
':inoutsep' => $inoutsep,
':content' => $content,
':amount' => $amount,
':memo' => $memo,
':ForeDate' => $ForeDate,
':first_writer' => $first_writer,
':searchtag' => $searchtag,
':update_log' => $update_log
]);
if ($ok) {
$insertedCount++;
} else {
$errors[] = "등록 실패: {$content} ({$registDate})";
}
}
if (!empty($errors)) {
$pdo->rollBack();
ob_end_clean();
echo json_encode([
'status' => 'error',
'message' => '일부 저장 실패: ' . implode('; ', $errors)
]);
exit;
}
$pdo->commit();
ob_end_clean();
echo json_encode([
'status' => 'success',
'message' => "{$insertedCount}건 저장 완료",
'insertedCount'=> $insertedCount
]);
} catch (Exception $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
ob_end_clean();
echo json_encode([
'status' => 'error',
'message' => '서버 오류: ' . $e->getMessage()
]);
}

135
account_plan/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: 80%;
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: 15px;
}
.custom-card {
background-color: #f9f9f9;
padding: 20px;
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;
}

195
account_plan/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';
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-control me-2" style="width:80px;" 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-control me-1" style="width:60px;" 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-control me-5 " style="width:60px;" 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,166 @@
<?php
// eworks_process.php
require_once($_SERVER['DOCUMENT_ROOT'] . '/session.php');
header("Content-Type: application/json; charset=utf-8");
// DB 연결
require_once($_SERVER['DOCUMENT_ROOT'] . '/lib/mydb.php');
$pdo = db_connect();
$DB = 'chandj';
$planTable = 'account_plan';
// 1) JSON 바디 파싱
$body = json_decode(file_get_contents('php://input'), true);
$items = $body['items'] ?? [];
if (empty($items)) {
echo json_encode([
'success' => false,
'message' => '전달된 지출 데이터가 없습니다.'
], JSON_UNESCAPED_UNICODE);
exit;
}
// 2) 공통 변수 세팅
$first = $items[0];
$payDate = $first['payDate']; // payDate 키 사용
$indate = $payDate;
$outdate = $payDate;
$mytitle = '일일지출내역서'; // 문서 제목
$content = ''; // 본문
$content_reason = ''; // 사유
$first_writer = $_SESSION['name'] . ' _' . date('Y-m-d H:i:s');
$author = '정미영'; // 결재 작성자
$author_id = 'jmy';
$update_log = date('Y-m-d H:i:s')
. ' - ' . $_SESSION['name']
. ' 일일지출내역서 발송&#10';
$suppliercost = array_sum(array_column($items, 'amount'));
$store = '';
$secondordnum = '';
$secondordpaydate = $payDate;
// 3) eworks에 저장할 contents JSON
$eworks_contents = [
'e_title' => $mytitle,
'indate' => $indate,
'author' => $author,
'expense_data' => $items,
];
$contents = json_encode($eworks_contents, JSON_UNESCAPED_UNICODE);
// 4) 결재라인 조회
try {
$msql = "SELECT first_approval_id, first_approval_name
FROM {$DB}.member
WHERE name = ?";
$mstmt = $pdo->prepare($msql);
$mstmt->execute([ $author ]);
$member = $mstmt->fetch(PDO::FETCH_ASSOC) ?: [];
$first_approval_id = trim($member['first_approval_id'] ?? '');
$first_approval_name = trim($member['first_approval_name'] ?? '');
} catch (PDOException $e) {
echo json_encode([
'success' => false,
'message' => '멤버 조회 오류: ' . $e->getMessage()
], JSON_UNESCAPED_UNICODE);
exit;
}
// 5) 결재 상태 및 라인 결정
$status = 'send';
$e_line_id = $first_approval_id;
$e_line = $first_approval_name;
// 6) eworks 신규 등록 & account_plan 컬럼 업데이트
try {
$pdo->beginTransaction();
// 6a) eworks INSERT
$sql = "INSERT INTO {$DB}.eworks (
indate,
outdate,
outworkplace,
request_comment,
first_writer,
author,
update_log,
contents,
e_title,
eworks_item,
registdate,
author_id,
status,
e_line_id,
e_line,
al_content,
suppliercost,
store,
secondordnum,
secondordpaydate
) VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
)";
$stmt = $pdo->prepare($sql);
$stmt->execute([
$indate,
$outdate,
$mytitle,
$content_reason,
$first_writer,
$author,
$update_log,
$contents,
$mytitle,
$mytitle, // eworks_item = 일일지출내역서
date('Y-m-d H:i:s'),
$author_id,
$status,
$e_line_id,
$e_line,
$content, // al_content
$suppliercost,
$store,
$secondordnum,
$secondordpaydate
]);
// 6b) 방금 등록된 eworks num 가져오기
$eworksNum = $pdo->lastInsertId();
// 6c) account_plan 3개 컬럼 업데이트
$uSql = "UPDATE {$DB}.{$planTable}
SET approvalRequest = ?,
eworksNum = ?,
workDone = ?
WHERE num = ?
LIMIT 1";
$uStmt = $pdo->prepare($uSql);
foreach ($items as $item) {
$uStmt->execute([
$indate, // approvalRequest
$eworksNum,
$status === 'send' ? '요청중' : '완료',
(int)$item['num']
]);
}
$pdo->commit();
echo json_encode([
'success' => true,
'message' => count($items) . '건 결재요청 및 eworks 등록 완료',
'eworksNum' => $eworksNum,
], JSON_UNESCAPED_UNICODE);
} catch (PDOException $e) {
$pdo->rollBack();
echo json_encode([
'success' => false,
'message' => 'DB 오류: ' . $e->getMessage()
], JSON_UNESCAPED_UNICODE);
}

View File

@@ -0,0 +1,39 @@
<?php
/**
* 제외 항목 저장
*
* 이 파일은 클라이언트에서 요청한 제외 항목 정보를 JSON 파일로 저장합니다.
*/
// 에러 표시 설정
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
$yearMonth = $_POST['yearMonth'];
$customerName = $_POST['customerName'];
$amount = $_POST['amount'];
// "(주)"는 유지하고 "(계산서발행)" 등 나머지 괄호 내용 제거
$cleanCustomerName = preg_replace('/\s*\((?!주\)).*?\)\s*/', '', $customerName);
// 데이터 유효성 검사 (필요한 경우 추가)
$excludedItem = [
'yearMonth' => $yearMonth,
'customerName' => $cleanCustomerName,
'amount' => $amount
];
$excludedItemsFile = $_SERVER['DOCUMENT_ROOT'] . "/account_plan/excluded_items.json";
$excludedItems = [];
if (file_exists($excludedItemsFile)) {
$excludedItems = json_decode(file_get_contents($excludedItemsFile), true);
}
$excludedItems[] = $excludedItem;
file_put_contents($excludedItemsFile, json_encode($excludedItems));
echo json_encode(['success' => true]);
?>

View File

@@ -0,0 +1 @@
[{"yearMonth":"202506","customerName":"\uba85\ubcf4\uc5d0\uc2a4\ud2f0","amount":"164530128"},{"yearMonth":null,"customerName":"","amount":null},{"yearMonth":null,"customerName":"","amount":null},{"yearMonth":null,"customerName":"","amount":null},{"yearMonth":null,"customerName":"","amount":null}]

105
account_plan/fetch_in.php Normal file
View File

@@ -0,0 +1,105 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
$mode = isset($_POST['mode']) ? $_POST['mode'] : '';
$num = isset($_POST['num']) ? $_POST['num'] : '';
$tablename = isset($_POST['tablename']) ? $_POST['tablename'] : '';
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 {
include '_request.php';
$mode = 'insert';
$registDate = date('Y-m-d');
$inoutsep = '수입';
$amount = 0;
$content = ''; // 기본값 설정
}
$title_message = ($mode === 'update') ? '수입 (계산서발생) 수정' : '수입 (계산서발행) 신규 등록';
?>
<input type="hidden" id="update_log" name="update_log" value="<?=$update_log?>">
<input type="hidden" id="first_writer" name="first_writer" value="<?=$first_writer?>">
<input type="hidden" id="secondordnum" name="secondordnum" value="<?=$secondordnum?>">
<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"><?=$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 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="<?=$registDate?>">
</td>
<td class="text-center fs-6 fw-bold" style="width:150px;">구분</td>
<td class="text-center" style="width:200px;">
<div>
<input type="radio" class="form-check-input" id="expense" name="inoutsep" value="수입" <?= $inoutsep === '수입' ? 'checked' : '' ?>>
<label for="expense" class="form-check-label fs-6">수입</label>
</div>
</td>
</tr>
<tr>
<td class="text-center fs-6 fw-bold"> 거래처 </td>
<td class="text-start" colspan="3">
<div class="d-flex align-items-center justify-content-start">
<input type="text" id="content" name="content" value="<?=$content?>" class="form-control noborder-input text-start fs-6" autocomplete="off" style="width:70%;" onkeydown="if(event.keyCode == 13) { phonebookBtn('content'); }" placeholder="코드연동을 위해 검색해서 입력해주세요" > &nbsp;
<button type="button" class="btn btn-dark-outline btn-sm restrictbtn" onclick="phonebookBtn('content');"> <i class="bi bi-gear"></i> </button>
</div>
</td>
</tr>
<tr>
<td class="text-center fs-6 fw-bold" style="width:150px;">금액</td>
<td class="text-center">
<input type="text" class="form-control fs-6 noborder-input text-end" id="amount" name="amount" value="<?= isset($amount) ? number_format($amount) : '' ?>" autocomplete="off" onkeyup="inputNumberFormat(this)">
</td>
<td class="text-center" colspan="2">
</td>
</tr>
</tbody>
</table>
</div>
</div>
<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="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>

View File

@@ -0,0 +1,110 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
$mode = isset($_POST['mode']) ? $_POST['mode'] : '';
$num = isset($_POST['num']) ? $_POST['num'] : '';
$tablename = isset($_POST['tablename']) ? $_POST['tablename'] : '';
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 {
include '_request.php';
$mode = 'insert';
$registDate = date('Y-m-d');
$inoutsep = '지출';
$amount = 0;
$content = ''; // 기본값 설정
}
$title_message = ($mode === 'update') ? '지출 계획 수정' : '지출 계획 신규 등록';
?>
<input type="hidden" id="update_log" name="update_log" value="<?=$update_log?>">
<input type="hidden" id="first_writer" name="first_writer" value="<?=$first_writer?>">
<input type="hidden" id="approvalRequest" name="approvalRequest" value="<?=$approvalRequest?>">
<input type="hidden" id="eworksNum" name="eworksNum" value="<?=$eworksNum?>">
<input type="hidden" id="workDone" name="workDone" value="<?=$workDone?>">
<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"><?=$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 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 noborder-input" id="registDate" name="registDate" style="width:130px;" value="<?=$registDate?>">
</td>
<td class="text-center fs-6 fw-bold" style="width:150px;">구분</td>
<td class="text-center" style="width:200px;">
<div class="d-flex justify-content-center align-items-center">
<input type="radio" class="form-check-input" id="expense" name="inoutsep" value="지출" <?= $inoutsep === '지출' ? 'checked' : '' ?>>
<label for="expense" class="form-check-label mx-1 fs-6">지출</label>
</div>
</td>
</tr>
<tr>
<td class="text-center fs-6 fw-bold">내역</td>
<td class="text-start" colspan="3">
<input type="text" class="form-control text-start fs-6 noborder-input" id="content" name="content" value="<?=$content?>" autocomplete="off">
</td>
</tr>
<tr>
<td class="text-center fs-6 fw-bold" style="width:150px;">금액</td>
<td class="text-center">
<input type="text" class="form-control fs-6 noborder-input text-end" id="amount" name="amount" value="<?= isset($amount) ? number_format($amount) : '' ?>" autocomplete="off" onkeyup="inputNumberFormat(this)">
</td>
<td class="text-center fs-6 fw-bold" style="width:150px;">예상지급일</td>
<td class="text-center">
<input type="date" class="form-control fs-6 noborder-input text-start" id="ForeDate" name="ForeDate" value="<?= isset($ForeDate) ? $ForeDate : '' ?>" >
</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 noborder-input text-start" id="memo" name="memo" value="<?=$memo?>" autocomplete="off">
</td>
</tr>
</tbody>
</table>
</div>
</div>
<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="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>

View File

@@ -0,0 +1,172 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
$mode = isset($_POST['mode']) ? $_POST['mode'] : '';
$num = isset($_POST['num']) ? $_POST['num'] : '';
// Now, $mode will contain 'modify', and $num will contain the value from the data attribute
// echo "Mode: " . $mode . "<br>";
// echo "Num: " . $num . "<br>";
$tablename = 'todos_monthly';
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
try {
// Prepare SQL query to fetch data from todos_monthly table
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) {
// Existing record
$title = $row['title'];
$registdate = $row['registdate'];
$itemsep = $row['itemsep'];
$specialday = $row['specialday'];
$first_writer = $row['first_writer'];
$update_log = $row['update_log'];
$searchtag = $row['searchtag'];
} else {
echo "Record not found.";
exit;
}
} else {
// New record
$title = '';
$registdate = date('Y-m-d');
$itemsep = '';
$specialday = '';
$first_writer = $user_name ;
$update_log = '';
$searchtag = '';
}
} catch (PDOException $Exception) {
echo "오류: " . $Exception->getMessage();
exit;
}
$incomeOptions = [
'거래처 수금' => '거래처에서 입금한 금액',
'최초 현금 입력' => '금전출납부 시작'
];
$expenseOptions = [
'급여(인건비)' => '직원 급여',
'접대비' => '경조사비용',
'통신비' => '전화요금, 인터넷요금',
'세금과공과금' => '등록면허세, 취득세, 재산세등 각종세금',
'차량유지비' => '유류대, 통행료',
'보험료' => '차량보험료, 화재보험료등',
'운반비' => '택배운반비외 각종운반비',
'소모품비' => '각종 소모품 비용',
'수수료비용' => '이체수수료, 등기수수료등',
'복리후생비' => '직원 식대외 직원 작업복등',
'개발비' => '프로그램 개발비용',
'이자비용' => '이자비용',
'카드대금' => '카드대금',
'통관비' => '통관비',
'자재비' => '자재비',
'기계장치' => '기계구입',
'선급금' => '미리 지급하는 금액',
'지급임차료' => '지급임차료',
'지급수수료' => '지금수수료'
];
?>
<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" style="width:200px;">
<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>
<td class="text-center fs-6 fw-bold" style="width:150px;">항목</td>
<td class="text-center" colspan="3">
<select class="form-control fs-6" id="itemsep" name="itemsep">
<optgroup label="수입 항목">
<?php foreach ($incomeOptions as $key => $value): ?>
<option value="<?= htmlspecialchars($key) ?>" <?= $itemsep === $key ? 'selected' : '' ?>>
<?= htmlspecialchars($key) ?>
</option>
<?php endforeach; ?>
</optgroup>
<optgroup label="지출 항목">
<?php foreach ($expenseOptions as $key => $value): ?>
<option value="<?= htmlspecialchars($key) ?>" <?= $itemsep === $key ? 'selected' : '' ?>>
<?= htmlspecialchars($key) ?>
</option>
<?php endforeach; ?>
</optgroup>
</select>
</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>

105
account_plan/insert.php Normal file
View File

@@ -0,0 +1,105 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
$tablename = isset($_REQUEST['tablename']) ? $_REQUEST['tablename'] : 'account_plan';
$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 . ' ' . $amount . $content_detail ;
try {
if ($mode == "update") {
$update_log = date("Y-m-d H:i:s") . " - " . $_SESSION["name"] . " " . $update_log . "&#10";
$pdo->beginTransaction();
// Prepare the SQL query for updating the account information
$sql = "UPDATE {$DB}.{$tablename} SET ";
$sql .= "registDate = ?, inoutsep = ?, content = ?, content_detail = ?, amount = ?, memo = ?, searchtag = ?, update_log = ?, first_writer = ?, bankbook = ?, secondordnum = ?, ForeDate = ?, approvalRequest = ?, eworksNum = ?, workDone = ? ";
$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, $memo, 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, $ForeDate, PDO::PARAM_STR);
$stmh->bindValue(13, $approvalRequest, PDO::PARAM_STR);
$stmh->bindValue(14, $eworksNum, PDO::PARAM_STR);
$stmh->bindValue(15, $workDone, PDO::PARAM_STR);
$stmh->bindValue(16, $num, PDO::PARAM_INT);
// Execute the statement
$stmh->execute();
$pdo->commit();
}
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
$pdo->beginTransaction();
// Updated columns and values to be inserted
$sql = "INSERT INTO {$DB}.{$tablename} (";
$sql .= "registDate, inoutsep, content, content_detail, amount, memo, searchtag, update_log, first_writer, bankbook, secondordnum, ForeDate, approvalRequest, eworksNum, workDone ";
$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, $memo, 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, $ForeDate, PDO::PARAM_STR);
$stmh->bindValue(13, $approvalRequest, PDO::PARAM_STR);
$stmh->bindValue(14, $eworksNum, PDO::PARAM_STR);
$stmh->bindValue(15, $workDone, PDO::PARAM_STR);
// Execute the statement
$stmh->execute();
$pdo->commit();
}
if ($mode == "delete") { // Data deletion
$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();
}
$data = [
'num' => $num,
'mode' => $mode
];
echo json_encode($data, JSON_UNESCAPED_UNICODE);
} catch (PDOException $Exception) {
$pdo->rollBack();
echo json_encode(['error' => $Exception->getMessage()], JSON_UNESCAPED_UNICODE);
}
?>

1916
account_plan/list.php Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,31 @@
<?php
/**
* 제외 항목 목록 로드 (수정)
*
* 이 파일은 excluded_items.json 파일에서 제외 항목 목록을 읽어와 HTML 테이블 코드로 반환합니다.
* 복구 버튼이 추가되었습니다.
*/
$excludedItemsFile = $_SERVER['DOCUMENT_ROOT'] . "/account_plan/excluded_items.json";
$excludedItems = [];
if (file_exists($excludedItemsFile)) {
$excludedItems = json_decode(file_get_contents($excludedItemsFile), true);
}
$tableRows = '';
if (!empty($excludedItems)) {
foreach ($excludedItems as $item) {
$tableRows .= "<tr>";
$tableRows .= "<td>" . htmlspecialchars($item['yearMonth']) . "</td>";
$tableRows .= "<td>" . htmlspecialchars($item['customerName']) . "</td>";
$tableRows .= "<td>" . number_format($item['amount']) . "</td>";
$tableRows .= "<td><button class='btn btn-secondary btn-sm restore-btn' data-year-month='" . htmlspecialchars($item['yearMonth']) . "' data-customer-name='" . htmlspecialchars($item['customerName']) . "' data-amount='" . htmlspecialchars($item['amount']) . "'>복구</button></td>";
$tableRows .= "</tr>";
}
} else {
$tableRows = "<tr><td colspan='4'>제외된 항목이 없습니다.</td></tr>";
}
echo $tableRows;
?>

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' => '번호',
'registDate' => '등록일자',
'content' => '항목',
'contentDetail' => '상세내용',
'income' => '수입',
'expense' => '지출',
'balance' => '잔액',
'memo' => '적요'
];
// 헤더를 엑셀에 추가
$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('D')->setWidth(45);
$sheet->getColumnDimension('G')->setWidth(25);
$sheet->getColumnDimension('H')->setWidth(60);
// 나머지 열의 폭을 글씨에 맞추기
foreach (range('A', 'H') as $columnID) {
if (!in_array($columnID, ['D', 'G','H'])) {
$sheet->getColumnDimension($columnID)->setWidth(15);
}
}
// 테두리 설정
$styleArray = [
'borders' => [
'allborders' => [
'style' => PHPExcel_Style_Border::BORDER_THIN,
],
],
];
$sheet->getStyle('A1:H' . ($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);
?>

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';
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/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();'> <ion-icon name="refresh-outline"></ion-icon> 새로고침 </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"><?= $memo ?></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/insert.php",
type: "post",
data: {
mode: $("#mode").val(),
num: $("#num").val(),
update_log: $("#update_log").val(),
registDate: $("#registDate").val(),
inoutsep: $("input[name='inoutsep']:checked").val(),
content: $("#content").val(),
amount: $("#amount").val(),
memo: $("#memo").val(),
first_writer: $("#first_writer").val(),
content_detail: $("#content_detail").val(),
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/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['memo'] = 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,40 @@
<?php
/**
* 제외 항목 복구
*
* 이 파일은 클라이언트에서 요청한 제외 항목을 excluded_items.json 파일에서 삭제합니다.
*/
// 에러 표시 설정
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
$yearMonth = $_POST['yearMonth'];
$customerName = $_POST['customerName'];
$amount = $_POST['amount'];
$excludedItemsFile = $_SERVER['DOCUMENT_ROOT'] . "/account_plan/excluded_items.json";
$excludedItems = [];
if (file_exists($excludedItemsFile)) {
$excludedItems = json_decode(file_get_contents($excludedItemsFile), true);
}
// 제외 항목 배열에서 해당 항목 제거
$updatedExcludedItems = array_filter($excludedItems, function ($item) use ($yearMonth, $customerName, $amount) {
return !(
$item['yearMonth'] === $yearMonth &&
$item['customerName'] === $customerName &&
intval($item['amount']) === intval($amount)
);
});
// 배열 인덱스 재정렬
$updatedExcludedItems = array_values($updatedExcludedItems);
// 업데이트된 제외 항목 배열을 JSON 파일에 저장
file_put_contents($excludedItemsFile, json_encode($updatedExcludedItems));
echo json_encode(['success' => true]);
?>

405
account_plan/schedule.php Normal file
View File

@@ -0,0 +1,405 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
if(!isset($_SESSION["level"]) ||intval($_SESSION["level"]) > 7) {
/* alert("관리자 승인이 필요합니다."); */
sleep(1);
header("Location:" . $WebSite . "login/login_form.php");
exit;
}
$today = date("Y-m-d");
require_once($_SERVER['DOCUMENT_ROOT'] . "/load_header.php");
$titlemessage = '회계 일정관리';
?>
<script src="https://dh2024.co.kr/js/todolist_account.js"></script>
<style>
.editable-item {
cursor: pointer;
}
</style>
<title> <?=$titlemessage?> </title>
<!-- Favicon-->
<link rel="icon" type="image/x-icon" href="favicon.ico"> <!-- 33 x 33 -->
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico"> <!-- 144 x 144 -->
<link rel="apple-touch-icon" type="image/x-icon" href="favicon.ico">
</head>
<?php require_once($_SERVER['DOCUMENT_ROOT'] . '/myheader.php'); ?>
<form id="board_form" name="board_form" method="post" enctype="multipart/form-data" >
<input type="hidden" id="num" name="num" value="<?= isset($num) ? $num : '' ?>" >
<input type="hidden" id="mode" name="mode" value="<?= isset($mode) ? $mode : '' ?>" >
<!-- todo모달 컨테이너 -->
<div class="container-fluid">
<!-- Modal -->
<div id="todoModal" class="modal">
<div class="modal-content" style="width:800px;">
<div class="modal-header">
<span class="modal-title">회계일정</span>
<span class="todo-close">&times;</span>
</div>
<div class="modal-body">
<div class="custom-card"></div>
</div>
</div>
</div>
</div>
<!-- 매월 -->
<div class="container-fluid">
<!-- Modal -->
<div id="todoModalMonthly" class="modal">
<div class="modal-content" style="width:800px;">
<div class="modal-header">
<span class="modal-title">월별 고정 회계일정</span>
<span class="todo-close">&times;</span>
</div>
<div class="modal-body">
<div class="custom-card"></div>
</div>
</div>
</div>
</div>
<?php // include $_SERVER['DOCUMENT_ROOT'] . '/mymodal.php'; ?>
<div class="container-fluid">
<!-- todo Calendar -->
<?php if($chkMobile==false) { ?>
<div class="container">
<?php } else { ?>
<div class="container-fluid">
<?php } ?>
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
try {
$sql = "SELECT num, specialday, title FROM todos_monthly WHERE is_deleted IS NULL ORDER BY specialday ASC";
$stmh = $pdo->prepare($sql);
$stmh->execute();
$data = $stmh->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $Exception) {
echo "오류: " . $Exception->getMessage();
exit;
}
?>
<div class="card mt-1">
<div class="card-body">
<div class="row">
<?php
$counter = 0;
foreach ($data as $row) {
$specialday = htmlspecialchars($row['specialday']);
$title = htmlspecialchars($row['title']);
$num = isset($row['num']) ? htmlspecialchars($row['num']) : ''; // Check if 'num' exists
echo '<div class="col-sm-3 mb-3">';
echo '<div class="d-flex justify-content-start align-items-center fs-5">';
echo '<span class="badge bg-success me-2"> 매월 ' . $specialday . '일 </span>';
echo '<span class="editable-item" data-num="' . $num . '" style="cursor: pointer;">' . $title . '</span>';
echo '</div>';
echo '</div>';
// Move to the next row after every 4 columns
$counter++;
if ($counter % 4 == 0) {
echo '</div><div class="row">';
}
}
?>
</div>
</div>
</div>
<div class="card mt-1">
<div class="card-body">
<div class="row d-flex ">
<!-- Calendar Controls -->
<div class="col-sm-3">
<div class="d-flex justify-content-start align-items-center ">
<h5> <회계부분 상세일정> </h5> &nbsp; &nbsp; (매월)&nbsp;
<button type='button' class='btn btn-danger btn-sm add-row me-2' data-table='acountTable' style='margin-right: 5px;'>+</button>
</div>
</div>
<div class="col-sm-6">
<div class="d-flex justify-content-center align-items-center mb-2">
<button type="button" id="todo-prev-month_account" class="btn btn-danger btn-sm me-2"><ion-icon name="arrow-back-outline"></ion-icon> </button>
<span id="todo-current-period" class="text-dark fs-6 me-2"></span>
<button type="button" id="todo-next-month_account" class="btn btn-danger btn-sm me-2"> <ion-icon name="arrow-forward-outline"></ion-icon></button>
<button type="button" id="todo-current-month_account" class="btn btn-outline-danger fw-bold btn-sm me-5"> <?php echo date("m",time()); ?> 월</button>
<button type="button" class="btn btn-dark btn-sm me-1" onclick='location.reload()'> <i class="bi bi-arrow-clockwise"></i> </button>
</div>
</div>
<div class="col-sm-3"> </div>
</div>
<div id="todo-calendar-container_account" class="d-flex p-1 justify-content-center"></div>
</div>
</div>
</div>
<div class="container-fluid">
<?php include $_SERVER['DOCUMENT_ROOT'] .'/footer.php'; ?>
</div>
</div>
</div> <!-- container-fulid end -->
</form>
</body>
</html>
<script>
// 페이지 로딩
$(document).ready(function(){
var loader = document.getElementById('loadingOverlay');
loader.style.display = 'none';
});
alreadyShown = getCookie("notificationShown");
var intervalId; // 인터벌 식별자를 저장할 변수
function closeMsg(){
var dialog = document.getElementById("myMsgDialog");
dialog.close();
}
function restorePageNumber(){
window.location.reload();
}
document.querySelector('.add-row').addEventListener('click', function() {
// Open the modal
var modal = document.getElementById('todoModalMonthly');
modal.style.display = 'block';
// Fetch data
fetch('/account/fetch_todoMonthly.php')
.then(response => response.text())
.then(data => {
// Insert the fetched data into the modal's body
document.querySelector('#todoModalMonthly .custom-card').innerHTML = data;
$(".todo-close").on("click", function() {
$("#todoModalMonthly").hide();
});
$("#saveBtn_month").on("click", function() {
// alert('asdfaf');
var formData = $("#board_form").serialize();
console.log(formData);
$.ajax({
url: "/todo_account/process_month.php",
type: "post",
data: formData,
success: function(response) {
console.log(response);
Toastify({
text: "저장완료",
duration: 3000,
close: true,
gravity: "top",
position: "center",
backgroundColor: "#4fbe87",
}).showToast();
$("#todoModalMonthly").hide();
location.reload();
},
error: function(jqxhr, status, error) {
console.log(jqxhr, status, error);
}
});
});
// 월별일정 삭제 버튼
$("#deleteBtn_month").on("click", function() {
var user_name = $("#user_name").val();
var first_writer = $("#first_writer").val();
if (user_name !== first_writer) {
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: "/todo_account/process_month.php",
type: "post",
data: formData,
success: function(response) {
Toastify({
text: "일정 삭제완료",
duration: 2000,
close: true,
gravity: "top",
position: "center",
style: {
background: "linear-gradient(to right, #00b09b, #96c93d)"
},
}).showToast();
$("#todoModalMonthly").hide();
location.reload();
},
error: function(jqxhr, status, error) {
console.log(jqxhr, status, error);
}
});
}
});
});
})
.catch(error => console.error('Error fetching the monthly schedule:', error));
});
$(document).on("click", "#closeBtn_month", function() {
$("#todoModalMonthly").hide();
});
$(document).on('click', '.editable-item', function() {
var num = $(this).data('num');
console.log('num',num);
// Fetch data for the specific item
$.ajax({
url: '/account/fetch_todoMonthly.php',
type: 'post',
data: { num: num , mode : 'modify' },
success: function(response) {
// Populate the modal with the fetched data
$('#todoModalMonthly .custom-card').html(response);
// Show the modal
var modal = document.getElementById('todoModalMonthly');
modal.style.display = 'block';
$(".todo-close").on("click", function() {
$("#todoModalMonthly").hide();
});
// Set up the save and delete buttons inside the modal
$("#saveBtn_month").on("click", function() {
var formData = $("#board_form").serialize();
$.ajax({
url: "/todo_account/process_month.php",
type: "post",
data: formData,
success: function(response) {
console.log(response);
Toastify({
text: "저장완료",
duration: 3000,
close: true,
gravity: "top",
position: "center",
backgroundColor: "#4fbe87",
}).showToast();
$("#todoModalMonthly").hide();
location.reload();
},
error: function(jqxhr, status, error) {
console.log(jqxhr, status, error);
}
});
});
$("#deleteBtn_month").on("click", function() {
var user_name = $("#user_name").val();
var first_writer = $("#first_writer").val();
if (user_name !== first_writer) {
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: "/todo_account/process_month.php",
type: "post",
data: formData,
success: function(response) {
Toastify({
text: "일정 삭제완료",
duration: 2000,
close: true,
gravity: "top",
position: "center",
style: {
background: "linear-gradient(to right, #00b09b, #96c93d)"
},
}).showToast();
$("#todoModalMonthly").hide();
location.reload();
},
error: function(jqxhr, status, error) {
console.log(jqxhr, status, error);
}
});
}
});
});
$("#closeBtn_month").on("click", function() {
$("#todoModalMonthly").hide();
});
},
error: function(jqxhr, status, error) {
console.log(jqxhr, status, error);
}
});
});
</script>

View File

@@ -0,0 +1,33 @@
<?php
// 출력 버퍼링 시작
ob_start();
// 에러 출력 억제
ini_set('display_errors', 0);
ini_set('display_startup_errors', 0);
error_reporting(0);
// 세션 확인
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
// 데이터베이스 연결 설정 파일 로드
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
// JSON 데이터 받기
$input = file_get_contents('php://input');
// 버퍼 클리어
ob_end_clean();
// 응답 헤더 설정
header('Content-Type: application/json');
// 간단한 응답
echo json_encode([
'success' => true,
'message' => '기본 테스트 성공',
'input_length' => strlen($input),
'session_level' => $_SESSION["level"] ?? 'not set',
'pdo_status' => isset($pdo) ? 'connected' : 'not connected'
]);
?>

View File

@@ -0,0 +1,27 @@
<?php
// 에러 표시 설정
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
// 세션 확인
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
// 데이터베이스 연결 설정 파일 로드
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
// JSON 데이터 받기
$input = file_get_contents('php://input');
// 응답 헤더 설정
header('Content-Type: application/json');
// 간단한 테스트 응답
echo json_encode([
'success' => true,
'message' => '테스트 성공',
'input' => $input,
'session_level' => $_SESSION["level"] ?? 'not set',
'pdo_status' => isset($pdo) ? 'connected' : 'not connected'
]);
?>