checkLogin(); $user = $this->getCurrentUser(); if ($user['role'] === self::ROLE_SUPER_ADMIN) { return $user; } if ($user['role'] === self::ROLE_ADMIN && ($user['category'] ?? '') === self::CATEGORY_FINANCE) { return $user; } header('Location: ' . BASE_URL . '/Front/index'); exit; } public function index() { $user = $this->checkCategoryAccess(); $financeRecord = new FinanceRecord(); $receivablePayable = new ReceivablePayable(); // 本月收支汇总 $monthStart = date('Y-m-01'); $monthEnd = date('Y-m-t'); $summary = $financeRecord->getSummary($monthStart, $monthEnd); $incomeTotal = 0; $expenseTotal = 0; foreach ($summary as $row) { if ($row['type'] === 'income') $incomeTotal = (float)$row['total']; if ($row['type'] === 'expense') $expenseTotal = (float)$row['total']; } // 应收应付统计 $receivables = $receivablePayable->getByType('receivable'); $payables = $receivablePayable->getByType('payable'); $receivableTotal = 0; $payableTotal = 0; foreach ($receivables as $r) { $receivableTotal += (float)($r['amount'] ?? 0); } foreach ($payables as $p) { $payableTotal += (float)($p['amount'] ?? 0); } $this->assign('title', '财务概览'); $this->assign('user', $user); $this->assign('activeMenu', 'finance_dashboard'); $this->assign('incomeTotal', $incomeTotal); $this->assign('expenseTotal', $expenseTotal); $this->assign('profit', $incomeTotal - $expenseTotal); $this->assign('receivableTotal', $receivableTotal); $this->assign('payableTotal', $payableTotal); $this->assign('recordCount', $financeRecord->getCount()); $this->render(); } // ========== 账务管理 ========== public function accounts() { $user = $this->checkCategoryAccess(); $financeRecord = new FinanceRecord(); $typeFilter = $_GET['type'] ?? ''; $startDate = $_GET['start_date'] ?? date('Y-m-01'); $endDate = $_GET['end_date'] ?? date('Y-m-d'); if ($typeFilter || $startDate || $endDate) { $records = $financeRecord->getByDateRange($startDate, $endDate, $typeFilter); } else { $records = $financeRecord->getAll(); } $this->assign('title', '账务管理'); $this->assign('user', $user); $this->assign('activeMenu', 'accounts'); $this->assign('records', $records); $this->assign('typeFilter', $typeFilter); $this->assign('startDate', $startDate); $this->assign('endDate', $endDate); $this->render(); } public function accountsAdd() { $user = $this->checkCategoryAccess(); if ($_SERVER['REQUEST_METHOD'] === 'POST') { $this->csrfVerify(); $data = [ 'record_no' => trim($_POST['record_no'] ?? ''), 'type' => trim($_POST['type'] ?? 'expense'), 'category' => trim($_POST['category'] ?? ''), 'amount' => (float)($_POST['amount'] ?? 0), 'record_date' => trim($_POST['record_date'] ?? date('Y-m-d')), 'description' => trim($_POST['description'] ?? ''), 'related_party' => trim($_POST['related_party'] ?? ''), 'payment_method' => trim($_POST['payment_method'] ?? ''), 'remark' => trim($_POST['remark'] ?? ''), 'operator' => $user['emp_name'], ]; if (empty($data['description'])) { $this->assign('error', '摘要不能为空'); $this->assign('title', '添加账务记录'); $this->assign('user', $user); $this->assign('activeMenu', 'accounts'); $this->assign('csrfToken', $this->csrfToken()); $this->render(); return; } if ($data['amount'] <= 0) { $this->assign('error', '金额必须大于0'); $this->assign('title', '添加账务记录'); $this->assign('user', $user); $this->assign('activeMenu', 'accounts'); $this->assign('csrfToken', $this->csrfToken()); $this->render(); return; } try { $financeRecord = new FinanceRecord(); $financeRecord->add($data); header('Location: ' . BASE_URL . '/Finance/accounts'); exit; } catch (\Throwable $e) { error_log('[accountsAdd] ' . $e->getMessage()); $this->assign('error', '添加失败:' . $e->getMessage()); $this->assign('title', '添加账务记录'); $this->assign('user', $user); $this->assign('activeMenu', 'accounts'); $this->assign('csrfToken', $this->csrfToken()); $this->render(); return; } } $this->assign('title', '添加账务记录'); $this->assign('user', $user); $this->assign('activeMenu', 'accounts'); $this->assign('csrfToken', $this->csrfToken()); $this->render(); } public function accountsEdit() { $user = $this->checkCategoryAccess(); $id = (int)($_GET['id'] ?? 0); $financeRecord = new FinanceRecord(); $record = $financeRecord->getById($id); if (!$record) exit('记录不存在'); if ($_SERVER['REQUEST_METHOD'] === 'POST') { $this->csrfVerify(); $data = [ 'record_no' => trim($_POST['record_no'] ?? ''), 'type' => trim($_POST['type'] ?? 'expense'), 'category' => trim($_POST['category'] ?? ''), 'amount' => (float)($_POST['amount'] ?? 0), 'record_date' => trim($_POST['record_date'] ?? ''), 'description' => trim($_POST['description'] ?? ''), 'related_party' => trim($_POST['related_party'] ?? ''), 'payment_method' => trim($_POST['payment_method'] ?? ''), 'remark' => trim($_POST['remark'] ?? ''), ]; try { $financeRecord->where(['id = :id'], [':id' => $id])->update($data); header('Location: ' . BASE_URL . '/Finance/accounts'); exit; } catch (\Throwable $e) { error_log('[accountsEdit] ' . $e->getMessage()); $this->assign('error', '更新失败:' . $e->getMessage()); $this->assign('title', '编辑账务记录'); $this->assign('user', $user); $this->assign('activeMenu', 'accounts'); $this->assign('record', $record); $this->assign('csrfToken', $this->csrfToken()); $this->render(); return; } } $this->assign('title', '编辑账务记录'); $this->assign('user', $user); $this->assign('activeMenu', 'accounts'); $this->assign('record', $record); $this->assign('csrfToken', $this->csrfToken()); $this->render(); } public function accountsDelete() { $this->checkLogin(); $this->requireMethod('post'); $this->csrfVerify(); $id = (int)($_POST['id'] ?? 0); $financeRecord = new FinanceRecord(); $financeRecord->delete($id); header('Location: ' . BASE_URL . '/Finance/accounts'); exit; } // ========== 应收账款 ========== public function receivable() { $user = $this->checkCategoryAccess(); $receivablePayable = new ReceivablePayable(); $records = $receivablePayable->getByType('receivable'); $this->assign('title', '应收账款'); $this->assign('user', $user); $this->assign('activeMenu', 'receivable'); $this->assign('records', $records); $this->render(); } public function receivableAdd() { $user = $this->checkCategoryAccess(); if ($_SERVER['REQUEST_METHOD'] === 'POST') { $this->csrfVerify(); $data = [ 'type' => 'receivable', 'party_name' => trim($_POST['party_name'] ?? ''), 'amount' => (float)($_POST['amount'] ?? 0), 'paid_amount' => (float)($_POST['paid_amount'] ?? 0), 'due_date' => trim($_POST['due_date'] ?? ''), 'status' => trim($_POST['status'] ?? 'pending'), 'description' => trim($_POST['description'] ?? ''), 'remark' => trim($_POST['remark'] ?? ''), 'operator' => $user['emp_name'], ]; try { $receivablePayable = new ReceivablePayable(); $receivablePayable->add($data); header('Location: ' . BASE_URL . '/Finance/receivable'); exit; } catch (\Throwable $e) { error_log('[receivableAdd] ' . $e->getMessage()); $this->assign('error', '添加失败:' . $e->getMessage()); $this->assign('title', '添加应收账款'); $this->assign('user', $user); $this->assign('activeMenu', 'receivable'); $this->assign('csrfToken', $this->csrfToken()); $this->render(); return; } } $this->assign('title', '添加应收账款'); $this->assign('user', $user); $this->assign('activeMenu', 'receivable'); $this->assign('csrfToken', $this->csrfToken()); $this->render(); } public function receivableEdit() { $user = $this->checkCategoryAccess(); $id = (int)($_GET['id'] ?? 0); $receivablePayable = new ReceivablePayable(); $record = $receivablePayable->getById($id); if (!$record) exit('记录不存在'); if ($_SERVER['REQUEST_METHOD'] === 'POST') { $this->csrfVerify(); $data = [ 'party_name' => trim($_POST['party_name'] ?? ''), 'amount' => (float)($_POST['amount'] ?? 0), 'paid_amount' => (float)($_POST['paid_amount'] ?? 0), 'due_date' => trim($_POST['due_date'] ?? ''), 'status' => trim($_POST['status'] ?? 'pending'), 'description' => trim($_POST['description'] ?? ''), 'remark' => trim($_POST['remark'] ?? ''), ]; try { $receivablePayable->where(['id = :id'], [':id' => $id])->update($data); header('Location: ' . BASE_URL . '/Finance/receivable'); exit; } catch (\Throwable $e) { error_log('[receivableEdit] ' . $e->getMessage()); $this->assign('error', '更新失败:' . $e->getMessage()); $this->assign('title', '编辑应收账款'); $this->assign('user', $user); $this->assign('activeMenu', 'receivable'); $this->assign('record', $record); $this->assign('csrfToken', $this->csrfToken()); $this->render(); return; } } $this->assign('title', '编辑应收账款'); $this->assign('user', $user); $this->assign('activeMenu', 'receivable'); $this->assign('record', $record); $this->assign('csrfToken', $this->csrfToken()); $this->render(); } public function receivableDelete() { $this->checkLogin(); $this->requireMethod('post'); $this->csrfVerify(); $id = (int)($_POST['id'] ?? 0); $receivablePayable = new ReceivablePayable(); $receivablePayable->delete($id); header('Location: ' . BASE_URL . '/Finance/receivable'); exit; } // ========== 应付账款 ========== public function payable() { $user = $this->checkCategoryAccess(); $receivablePayable = new ReceivablePayable(); $records = $receivablePayable->getByType('payable'); $this->assign('title', '应付账款'); $this->assign('user', $user); $this->assign('activeMenu', 'payable'); $this->assign('records', $records); $this->render(); } public function payableAdd() { $user = $this->checkCategoryAccess(); if ($_SERVER['REQUEST_METHOD'] === 'POST') { $this->csrfVerify(); $data = [ 'type' => 'payable', 'party_name' => trim($_POST['party_name'] ?? ''), 'amount' => (float)($_POST['amount'] ?? 0), 'paid_amount' => (float)($_POST['paid_amount'] ?? 0), 'due_date' => trim($_POST['due_date'] ?? ''), 'status' => trim($_POST['status'] ?? 'pending'), 'description' => trim($_POST['description'] ?? ''), 'remark' => trim($_POST['remark'] ?? ''), 'operator' => $user['emp_name'], ]; try { $receivablePayable = new ReceivablePayable(); $receivablePayable->add($data); header('Location: ' . BASE_URL . '/Finance/payable'); exit; } catch (\Throwable $e) { error_log('[payableAdd] ' . $e->getMessage()); $this->assign('error', '添加失败:' . $e->getMessage()); $this->assign('title', '添加应付账款'); $this->assign('user', $user); $this->assign('activeMenu', 'payable'); $this->assign('csrfToken', $this->csrfToken()); $this->render(); return; } } $this->assign('title', '添加应付账款'); $this->assign('user', $user); $this->assign('activeMenu', 'payable'); $this->assign('csrfToken', $this->csrfToken()); $this->render(); } public function payableEdit() { $user = $this->checkCategoryAccess(); $id = (int)($_GET['id'] ?? 0); $receivablePayable = new ReceivablePayable(); $record = $receivablePayable->getById($id); if (!$record) exit('记录不存在'); if ($_SERVER['REQUEST_METHOD'] === 'POST') { $this->csrfVerify(); $data = [ 'party_name' => trim($_POST['party_name'] ?? ''), 'amount' => (float)($_POST['amount'] ?? 0), 'paid_amount' => (float)($_POST['paid_amount'] ?? 0), 'due_date' => trim($_POST['due_date'] ?? ''), 'status' => trim($_POST['status'] ?? 'pending'), 'description' => trim($_POST['description'] ?? ''), 'remark' => trim($_POST['remark'] ?? ''), ]; try { $receivablePayable->where(['id = :id'], [':id' => $id])->update($data); header('Location: ' . BASE_URL . '/Finance/payable'); exit; } catch (\Throwable $e) { error_log('[payableEdit] ' . $e->getMessage()); $this->assign('error', '更新失败:' . $e->getMessage()); $this->assign('title', '编辑应付账款'); $this->assign('user', $user); $this->assign('activeMenu', 'payable'); $this->assign('record', $record); $this->assign('csrfToken', $this->csrfToken()); $this->render(); return; } } $this->assign('title', '编辑应付账款'); $this->assign('user', $user); $this->assign('activeMenu', 'payable'); $this->assign('record', $record); $this->assign('csrfToken', $this->csrfToken()); $this->render(); } public function payableDelete() { $this->checkLogin(); $this->requireMethod('post'); $this->csrfVerify(); $id = (int)($_POST['id'] ?? 0); $receivablePayable = new ReceivablePayable(); $receivablePayable->delete($id); header('Location: ' . BASE_URL . '/Finance/payable'); exit; } // ========== 财务报表 ========== public function report() { $user = $this->checkCategoryAccess(); $financeRecord = new FinanceRecord(); $month = $_GET['month'] ?? date('Y-m'); $startDate = $month . '-01'; $endDate = date('Y-m-t', strtotime($startDate)); $summary = $financeRecord->getSummary($startDate, $endDate); $incomeTotal = 0; $expenseTotal = 0; foreach ($summary as $row) { if ($row['type'] === 'income') $incomeTotal = (float)$row['total']; if ($row['type'] === 'expense') $expenseTotal = (float)$row['total']; } // 按类别统计 $records = $financeRecord->getByDateRange($startDate, $endDate); $categorySummary = []; foreach ($records as $r) { $cat = $r['category'] ?: '未分类'; $type = $r['type']; if (!isset($categorySummary[$cat])) { $categorySummary[$cat] = ['income' => 0, 'expense' => 0]; } $categorySummary[$cat][$type] += (float)$r['amount']; } $this->assign('title', '财务报表'); $this->assign('user', $user); $this->assign('activeMenu', 'report'); $this->assign('incomeTotal', $incomeTotal); $this->assign('expenseTotal', $expenseTotal); $this->assign('profit', $incomeTotal - $expenseTotal); $this->assign('categorySummary', $categorySummary); $this->assign('month', $month); $this->render(); } }