Files
usher-manage-stack/resources/views/admin/trial-balance/index.blade.php
Gbanyan 642b879dd4 Add membership fee system with disability discount and fix document permissions
Features:
- Implement two fee types: entrance fee and annual fee (both NT$1,000)
- Add 50% discount for disability certificate holders
- Add disability certificate upload in member profile
- Integrate disability verification into cashier approval workflow
- Add membership fee settings in system admin

Document permissions:
- Fix hard-coded role logic in Document model
- Use permission-based authorization instead of role checks

Additional features:
- Add announcements, general ledger, and trial balance modules
- Add income management and accounting entries
- Add comprehensive test suite with factories
- Update UI translations to Traditional Chinese

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 09:56:01 +08:00

311 lines
22 KiB
PHP

<x-app-layout>
<x-slot name="header">
<h2 class="text-xl font-semibold leading-tight text-gray-800 dark:text-gray-200">
試算表
</h2>
</x-slot>
<div class="py-12">
<div class="mx-auto max-w-7xl sm:px-6 lg:px-8 space-y-6">
<!-- Filter Form -->
<div class="bg-white dark:bg-gray-800 shadow sm:rounded-lg">
<div class="px-4 py-5 sm:p-6">
<form method="GET" action="{{ route('admin.trial-balance.index') }}" class="space-y-4">
<div class="grid grid-cols-1 gap-4 sm:grid-cols-3">
<!-- Start Date -->
<div>
<label for="start_date" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
開始日期
</label>
<input type="date" name="start_date" id="start_date" value="{{ $startDate }}"
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:text-gray-100">
</div>
<!-- End Date -->
<div>
<label for="end_date" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
結束日期
</label>
<input type="date" name="end_date" id="end_date" value="{{ $endDate }}"
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:text-gray-100">
</div>
<!-- Buttons -->
<div class="flex items-end gap-4">
<button type="submit" class="inline-flex justify-center rounded-md bg-indigo-600 dark:bg-indigo-500 px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-700 dark:hover:bg-indigo-600 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800">
產生
</button>
<a href="{{ route('admin.trial-balance.index') }}" class="inline-flex justify-center rounded-md bg-white dark:bg-gray-700 px-4 py-2 text-sm font-semibold text-gray-900 dark:text-gray-100 shadow-sm ring-1 ring-inset ring-gray-300 dark:ring-gray-600 hover:bg-gray-50 dark:hover:bg-gray-600">
重設
</a>
</div>
</div>
</form>
</div>
</div>
<!-- Balance Status Alert -->
@if($isBalanced)
<div class="rounded-md bg-green-50 dark:bg-green-900/30 p-4 border border-green-200 dark:border-green-800">
<div class="flex">
<div class="flex-shrink-0">
<svg class="h-5 w-5 text-green-400" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd" />
</svg>
</div>
<div class="ml-3">
<h3 class="text-sm font-medium text-green-800 dark:text-green-200">
借貸平衡
</h3>
<p class="mt-1 text-sm text-green-700 dark:text-green-300">
借方總計等於貸方總計,試算表正確
</p>
</div>
</div>
</div>
@else
<div class="rounded-md bg-red-50 dark:bg-red-900/30 p-4 border border-red-200 dark:border-red-800">
<div class="flex">
<div class="flex-shrink-0">
<svg class="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z" clip-rule="evenodd" />
</svg>
</div>
<div class="ml-3">
<h3 class="text-sm font-medium text-red-800 dark:text-red-200">
借貸不平衡
</h3>
<p class="mt-1 text-sm text-red-700 dark:text-red-300">
差額: NT$ {{ number_format(abs($difference), 2) }}
({{ $difference > 0 ? '借方多' : '貸方多' }})
</p>
</div>
</div>
</div>
@endif
<!-- Summary Cards -->
<div class="grid grid-cols-1 gap-4 sm:grid-cols-3">
<!-- Debit Total -->
<div class="bg-blue-50 dark:bg-blue-900/30 shadow sm:rounded-lg border-l-4 border-blue-400">
<div class="px-4 py-5 sm:p-6">
<dt class="text-sm font-medium text-blue-800 dark:text-blue-200">
借方總計
</dt>
<dd class="mt-1 text-3xl font-semibold text-blue-900 dark:text-blue-100">
NT$ {{ number_format($grandDebitTotal, 2) }}
</dd>
</div>
</div>
<!-- Credit Total -->
<div class="bg-purple-50 dark:bg-purple-900/30 shadow sm:rounded-lg border-l-4 border-purple-400">
<div class="px-4 py-5 sm:p-6">
<dt class="text-sm font-medium text-purple-800 dark:text-purple-200">
貸方總計
</dt>
<dd class="mt-1 text-3xl font-semibold text-purple-900 dark:text-purple-100">
NT$ {{ number_format($grandCreditTotal, 2) }}
</dd>
</div>
</div>
<!-- Difference -->
<div class="bg-white dark:bg-gray-800 shadow sm:rounded-lg border-l-4 {{ $isBalanced ? 'border-green-400' : 'border-red-400' }}">
<div class="px-4 py-5 sm:p-6">
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">
差額
</dt>
<dd class="mt-1 text-3xl font-semibold {{ $isBalanced ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400' }}">
NT$ {{ number_format(abs($difference), 2) }}
</dd>
</div>
</div>
</div>
@php
$typeLabels = [
'asset' => '資產 (Assets)',
'liability' => '負債 (Liabilities)',
'net_asset' => '淨資產/基金 (Net Assets)',
'income' => '收入 (Income)',
'expense' => '支出 (Expenses)',
];
$typeOrder = ['asset', 'liability', 'net_asset', 'income', 'expense'];
@endphp
<!-- Accounts by Type -->
@if($accounts->count() > 0)
@foreach($typeOrder as $type)
@if(isset($accountsByType[$type]) && $accountsByType[$type]->count() > 0)
<div class="bg-white dark:bg-gray-800 shadow sm:rounded-lg">
<div class="px-4 py-5 sm:p-6">
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100 mb-4 flex items-center">
@switch($type)
@case('asset')
<span class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-green-100 dark:bg-green-900/50 text-green-600 dark:text-green-400 mr-2">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</span>
@break
@case('liability')
<span class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-red-100 dark:bg-red-900/50 text-red-600 dark:text-red-400 mr-2">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 14l6-6m-5.5.5h.01m4.99 5h.01M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16l3.5-2 3.5 2 3.5-2 3.5 2z" />
</svg>
</span>
@break
@case('net_asset')
<span class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-indigo-100 dark:bg-indigo-900/50 text-indigo-600 dark:text-indigo-400 mr-2">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
</svg>
</span>
@break
@case('income')
<span class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-emerald-100 dark:bg-emerald-900/50 text-emerald-600 dark:text-emerald-400 mr-2">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6" />
</svg>
</span>
@break
@case('expense')
<span class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-orange-100 dark:bg-orange-900/50 text-orange-600 dark:text-orange-400 mr-2">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 17h8m0 0V9m0 8l-8-8-4 4-6-6" />
</svg>
</span>
@break
@endswitch
{{ $typeLabels[$type] ?? ucfirst($type) }}
</h3>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead class="bg-gray-50 dark:bg-gray-700">
<tr>
<th scope="col" class="px-4 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500 dark:text-gray-300">
科目代碼
</th>
<th scope="col" class="px-4 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500 dark:text-gray-300">
科目名稱
</th>
<th scope="col" class="px-4 py-3 text-right text-xs font-medium uppercase tracking-wider text-blue-600 dark:text-blue-400">
借方
</th>
<th scope="col" class="px-4 py-3 text-right text-xs font-medium uppercase tracking-wider text-purple-600 dark:text-purple-400">
貸方
</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 dark:divide-gray-700 bg-white dark:bg-gray-800">
@php $typeDebitTotal = 0; $typeCreditTotal = 0; @endphp
@foreach($accountsByType[$type] as $item)
@php
$typeDebitTotal += $item['debit_total'];
$typeCreditTotal += $item['credit_total'];
@endphp
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700">
<td class="whitespace-nowrap px-4 py-3 text-sm font-mono text-gray-900 dark:text-gray-100">
<a href="{{ route('admin.general-ledger.index', ['account_id' => $item['account']->id, 'start_date' => $startDate, 'end_date' => $endDate]) }}"
class="text-indigo-600 dark:text-indigo-400 hover:underline">
{{ $item['account']->account_code }}
</a>
</td>
<td class="px-4 py-3 text-sm text-gray-900 dark:text-gray-100">
{{ $item['account']->account_name_zh }}
<span class="text-xs text-gray-500 dark:text-gray-400">
{{ $item['account']->account_name_en }}
</span>
</td>
<td class="whitespace-nowrap px-4 py-3 text-sm text-right text-blue-600 dark:text-blue-400">
{{ $item['debit_total'] > 0 ? number_format($item['debit_total'], 2) : '' }}
</td>
<td class="whitespace-nowrap px-4 py-3 text-sm text-right text-purple-600 dark:text-purple-400">
{{ $item['credit_total'] > 0 ? number_format($item['credit_total'], 2) : '' }}
</td>
</tr>
@endforeach
<!-- Type Subtotal -->
<tr class="bg-gray-50 dark:bg-gray-700 font-semibold">
<td class="whitespace-nowrap px-4 py-3 text-sm text-gray-900 dark:text-gray-100" colspan="2">
小計
</td>
<td class="whitespace-nowrap px-4 py-3 text-sm text-right text-blue-700 dark:text-blue-300">
{{ $typeDebitTotal > 0 ? number_format($typeDebitTotal, 2) : '' }}
</td>
<td class="whitespace-nowrap px-4 py-3 text-sm text-right text-purple-700 dark:text-purple-300">
{{ $typeCreditTotal > 0 ? number_format($typeCreditTotal, 2) : '' }}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
@endif
@endforeach
<!-- Grand Total -->
<div class="bg-gray-900 dark:bg-gray-950 shadow sm:rounded-lg">
<div class="px-4 py-5 sm:p-6">
<div class="overflow-x-auto">
<table class="min-w-full">
<tbody>
<tr class="text-white">
<td class="px-4 py-4 text-lg font-bold">
總計
</td>
<td class="whitespace-nowrap px-4 py-4 text-right">
<span class="text-sm text-gray-400">借方</span>
<div class="text-2xl font-bold text-blue-400">
NT$ {{ number_format($grandDebitTotal, 2) }}
</div>
</td>
<td class="whitespace-nowrap px-4 py-4 text-right">
<span class="text-sm text-gray-400">貸方</span>
<div class="text-2xl font-bold text-purple-400">
NT$ {{ number_format($grandCreditTotal, 2) }}
</div>
</td>
<td class="whitespace-nowrap px-4 py-4 text-right">
<span class="text-sm text-gray-400">差額</span>
<div class="text-2xl font-bold {{ $isBalanced ? 'text-green-400' : 'text-red-400' }}">
NT$ {{ number_format(abs($difference), 2) }}
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
@else
<!-- No Data -->
<div class="bg-white dark:bg-gray-800 shadow sm:rounded-lg">
<div class="px-4 py-12 text-center">
<svg class="mx-auto h-12 w-12 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17v-2m3 2v-4m3 4v-6m2 10H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
<h3 class="mt-2 text-sm font-medium text-gray-900 dark:text-gray-100">
無會計分錄
</h3>
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
所選期間內沒有會計分錄
</p>
<div class="mt-6">
<a href="{{ route('admin.finance.create') }}" class="inline-flex items-center rounded-md bg-indigo-600 dark:bg-indigo-500 px-4 py-2 text-sm font-medium text-white hover:bg-indigo-700 dark:hover:bg-indigo-600">
<svg class="-ml-1 mr-2 h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
</svg>
建立財務憑證
</a>
</div>
</div>
</div>
@endif
</div>
</div>
</x-app-layout>