Files
usher-manage-stack/app/Http/Controllers/BankReconciliationController.php

273 lines
9.0 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Http\Controllers;
use App\Models\BankReconciliation;
use App\Models\CashierLedgerEntry;
use App\Support\AuditLogger;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
class BankReconciliationController extends Controller
{
/**
* Display a listing of bank reconciliations
*/
public function index(Request $request)
{
$query = BankReconciliation::query()
->with([
'preparedByCashier',
'reviewedByAccountant',
'approvedByManager'
])
->orderByDesc('reconciliation_month');
// Filter by status
if ($request->filled('reconciliation_status')) {
$query->where('reconciliation_status', $request->reconciliation_status);
}
// Filter by month
if ($request->filled('month')) {
$query->whereYear('reconciliation_month', '=', substr($request->month, 0, 4))
->whereMonth('reconciliation_month', '=', substr($request->month, 5, 2));
}
$reconciliations = $query->paginate(15);
return view('admin.bank-reconciliations.index', [
'reconciliations' => $reconciliations,
]);
}
/**
* Show the form for creating a new bank reconciliation
*/
public function create(Request $request)
{
// Check authorization
$this->authorize('prepare_bank_reconciliation');
// Default to current month
$month = $request->input('month', now()->format('Y-m'));
// Get system book balance from cashier ledger
$systemBalance = CashierLedgerEntry::getLatestBalance();
return view('admin.bank-reconciliations.create', [
'month' => $month,
'systemBalance' => $systemBalance,
]);
}
/**
* Store a newly created bank reconciliation
*/
public function store(Request $request)
{
// Check authorization
$this->authorize('prepare_bank_reconciliation');
$validated = $request->all();
DB::beginTransaction();
try {
// Handle bank statement file upload
$statementPath = null;
if ($request->hasFile('bank_statement_file')) {
$statementPath = $request->file('bank_statement_file')->store('bank-statements', 'local');
}
// Create reconciliation record
$reconciliation = new BankReconciliation([
'reconciliation_month' => ($validated['reconciliation_month'] ?? now()->format('Y-m')) . '-01',
'bank_statement_balance' => $validated['bank_statement_balance'] ?? 0,
'bank_statement_date' => $validated['bank_statement_date'] ?? now()->format('Y-m-d'),
'bank_statement_file_path' => $statementPath,
'system_book_balance' => $validated['system_book_balance'] ?? 0,
'outstanding_checks' => $validated['outstanding_checks'] ?? [],
'deposits_in_transit' => $validated['deposits_in_transit'] ?? [],
'bank_charges' => $validated['bank_charges'] ?? [],
'prepared_by_cashier_id' => $request->user()->id,
'prepared_at' => now(),
'notes' => $validated['notes'] ?? null,
]);
// Ensure required numeric fields
$adjusted = (float) $reconciliation->calculateAdjustedBalance();
$reconciliation->adjusted_balance = $adjusted ?: 0;
$reconciliation->discrepancy_amount = (float) $reconciliation->calculateDiscrepancy();
$reconciliation->reconciliation_status = BankReconciliation::STATUS_PENDING;
$reconciliation->save();
DB::commit();
$message = '銀行調節表已建立。';
if ($reconciliation->hasDiscrepancy()) {
$message .= ' 發現差異金額NT$ ' . number_format($reconciliation->discrepancy_amount, 2);
}
return redirect()
->route('admin.bank-reconciliations.show', $reconciliation)
->with('status', $message);
} catch (\Exception $e) {
DB::rollBack();
return redirect()
->back()
->withInput()
->with('error', '建立銀行調節表時發生錯誤:' . $e->getMessage());
}
}
/**
* Display the specified bank reconciliation
*/
public function show(BankReconciliation $bankReconciliation)
{
$bankReconciliation->load([
'preparedByCashier',
'reviewedByAccountant',
'approvedByManager'
]);
// Get outstanding items summary
$summary = $bankReconciliation->getOutstandingItemsSummary();
return view('admin.bank-reconciliations.show', [
'reconciliation' => $bankReconciliation,
'summary' => $summary,
]);
}
/**
* Accountant reviews the bank reconciliation
*/
public function review(Request $request, BankReconciliation $bankReconciliation)
{
// Check authorization
$this->authorize('review_bank_reconciliation');
// Check if can be reviewed
if (!$bankReconciliation->canBeReviewed()) {
return redirect()
->route('admin.bank-reconciliations.show', $bankReconciliation)
->with('error', '此銀行調節表無法覆核。');
}
$validated = $request->validate([
'review_notes' => ['nullable', 'string'],
]);
DB::beginTransaction();
try {
$bankReconciliation->update([
'reviewed_by_accountant_id' => $request->user()->id,
'reviewed_at' => now(),
]);
DB::commit();
return redirect()
->route('admin.bank-reconciliations.show', $bankReconciliation)
->with('status', '銀行調節表已完成會計覆核。');
} catch (\Exception $e) {
DB::rollBack();
return redirect()
->back()
->with('error', '覆核銀行調節表時發生錯誤:' . $e->getMessage());
}
}
/**
* Manager approves the bank reconciliation
*/
public function approve(Request $request, BankReconciliation $bankReconciliation)
{
// Check authorization
$this->authorize('approve_bank_reconciliation');
// Check if can be approved
if (!$bankReconciliation->canBeApproved()) {
return redirect()
->route('admin.bank-reconciliations.show', $bankReconciliation)
->with('error', '此銀行調節表無法核准。');
}
DB::beginTransaction();
try {
// Determine final status
$finalStatus = $bankReconciliation->hasDiscrepancy()
? BankReconciliation::STATUS_DISCREPANCY
: BankReconciliation::STATUS_COMPLETED;
$bankReconciliation->update([
'approved_by_manager_id' => $request->user()->id,
'approved_at' => now(),
'reconciliation_status' => $finalStatus,
]);
DB::commit();
$message = '銀行調節表已核准。';
if ($finalStatus === BankReconciliation::STATUS_DISCREPANCY) {
$message .= ' 請注意:仍有差異需要處理。';
}
return redirect()
->route('admin.bank-reconciliations.show', $bankReconciliation)
->with('status', $message);
} catch (\Exception $e) {
DB::rollBack();
return redirect()
->back()
->with('error', '核准銀行調節表時發生錯誤:' . $e->getMessage());
}
}
/**
* Download bank statement file
*/
public function downloadStatement(BankReconciliation $bankReconciliation)
{
if (!$bankReconciliation->bank_statement_file_path) {
abort(404, '找不到銀行對帳單檔案');
}
if (!Storage::disk('local')->exists($bankReconciliation->bank_statement_file_path)) {
abort(404, '銀行對帳單檔案不存在');
}
return Storage::disk('local')->download($bankReconciliation->bank_statement_file_path);
}
/**
* Export reconciliation to PDF
*/
public function exportPdf(BankReconciliation $bankReconciliation)
{
// Check authorization
$this->authorize('view_cashier_ledger');
$bankReconciliation->load([
'preparedByCashier',
'reviewedByAccountant',
'approvedByManager'
]);
$summary = $bankReconciliation->getOutstandingItemsSummary();
// Generate PDF (you would need to implement PDF generation library like DomPDF or TCPDF)
// For now, return a view that can be printed
return view('admin.bank-reconciliations.pdf', [
'reconciliation' => $bankReconciliation,
'summary' => $summary,
]);
}
}