Files
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

273 lines
20 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.
<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-3xl sm:px-6 lg:px-8">
<div class="bg-white dark:bg-gray-800 shadow sm:rounded-lg">
<div class="px-4 py-5 sm:p-6">
<form method="POST" action="{{ route('admin.incomes.store') }}" enctype="multipart/form-data">
@csrf
<div class="space-y-6">
{{-- 基本資訊 --}}
<div>
<h3 class="text-lg font-medium leading-6 text-gray-900 dark:text-gray-100">基本資訊</h3>
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">輸入收入的基本資料。</p>
</div>
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2">
{{-- 標題 --}}
<div class="sm:col-span-2">
<label for="title" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
標題 <span class="text-red-500">*</span>
</label>
<input type="text" name="title" id="title" value="{{ old('title') }}" required
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-900 dark:text-gray-300"
placeholder="例如2024年度會費收入">
@error('title')
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
@enderror
</div>
{{-- 收入日期 --}}
<div>
<label for="income_date" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
收入日期 <span class="text-red-500">*</span>
</label>
<input type="date" name="income_date" id="income_date" value="{{ old('income_date', date('Y-m-d')) }}" required
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-900 dark:text-gray-300">
@error('income_date')
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
@enderror
</div>
{{-- 金額 --}}
<div>
<label for="amount" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
金額 (NT$) <span class="text-red-500">*</span>
</label>
<input type="number" name="amount" id="amount" value="{{ old('amount') }}" required
step="0.01" min="0.01"
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-900 dark:text-gray-300"
placeholder="0.00">
@error('amount')
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
@enderror
</div>
{{-- 收入類型 --}}
<div>
<label for="income_type" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
收入類型 <span class="text-red-500">*</span>
</label>
<select name="income_type" id="income_type" required
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-900 dark:text-gray-300">
<option value="">請選擇收入類型</option>
<option value="membership_fee" @selected(old('income_type') == 'membership_fee')>會費</option>
<option value="entrance_fee" @selected(old('income_type') == 'entrance_fee')>入會費</option>
<option value="donation" @selected(old('income_type') == 'donation')>捐款</option>
<option value="activity" @selected(old('income_type') == 'activity')>活動收入</option>
<option value="grant" @selected(old('income_type') == 'grant')>補助款</option>
<option value="interest" @selected(old('income_type') == 'interest')>利息收入</option>
<option value="other" @selected(old('income_type') == 'other')>其他</option>
</select>
@error('income_type')
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
@enderror
</div>
{{-- 會計科目 --}}
<div>
<label for="chart_of_account_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
會計科目 <span class="text-red-500">*</span>
</label>
<select name="chart_of_account_id" id="chart_of_account_id" required
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-900 dark:text-gray-300">
<option value="">請選擇會計科目</option>
@foreach ($chartOfAccounts as $account)
<option value="{{ $account->id }}" @selected(old('chart_of_account_id') == $account->id)>
{{ $account->account_code }} - {{ $account->account_name_zh }}
</option>
@endforeach
</select>
@error('chart_of_account_id')
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
@enderror
</div>
</div>
<hr class="border-gray-200 dark:border-gray-700">
{{-- 付款資訊 --}}
<div>
<h3 class="text-lg font-medium leading-6 text-gray-900 dark:text-gray-100">付款資訊</h3>
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">記錄付款方式與相關資訊。</p>
</div>
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2">
{{-- 付款方式 --}}
<div>
<label for="payment_method" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
付款方式 <span class="text-red-500">*</span>
</label>
<select name="payment_method" id="payment_method" required
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-900 dark:text-gray-300">
<option value="">請選擇付款方式</option>
<option value="cash" @selected(old('payment_method') == 'cash')>現金</option>
<option value="bank_transfer" @selected(old('payment_method') == 'bank_transfer')>銀行轉帳</option>
<option value="check" @selected(old('payment_method') == 'check')>支票</option>
</select>
@error('payment_method')
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
@enderror
</div>
{{-- 銀行帳號 --}}
<div>
<label for="bank_account" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
銀行帳號
</label>
<input type="text" name="bank_account" id="bank_account" value="{{ old('bank_account') }}"
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-900 dark:text-gray-300"
placeholder="例如012-12345678">
@error('bank_account')
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
@enderror
</div>
{{-- 付款人姓名 --}}
<div>
<label for="payer_name" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
付款人姓名
</label>
<input type="text" name="payer_name" id="payer_name" value="{{ old('payer_name') }}"
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-900 dark:text-gray-300"
placeholder="付款人姓名">
@error('payer_name')
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
@enderror
</div>
{{-- 關聯會員 --}}
<div>
<label for="member_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
關聯會員
</label>
<select name="member_id" id="member_id"
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-900 dark:text-gray-300">
<option value="">不關聯會員</option>
@foreach ($members as $member)
<option value="{{ $member->id }}" @selected(old('member_id', $selectedMember?->id) == $member->id)>
{{ $member->full_name }}
</option>
@endforeach
</select>
@error('member_id')
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
@enderror
</div>
{{-- 收據編號 --}}
<div>
<label for="receipt_number" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
收據編號
</label>
<input type="text" name="receipt_number" id="receipt_number" value="{{ old('receipt_number') }}"
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-900 dark:text-gray-300"
placeholder="收據編號">
@error('receipt_number')
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
@enderror
</div>
{{-- 交易參考號 --}}
<div>
<label for="transaction_reference" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
交易參考號
</label>
<input type="text" name="transaction_reference" id="transaction_reference" value="{{ old('transaction_reference') }}"
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-900 dark:text-gray-300"
placeholder="銀行交易參考號">
@error('transaction_reference')
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
@enderror
</div>
</div>
<hr class="border-gray-200 dark:border-gray-700">
{{-- 說明與備註 --}}
<div>
<h3 class="text-lg font-medium leading-6 text-gray-900 dark:text-gray-100">說明與備註</h3>
</div>
<div class="grid grid-cols-1 gap-6">
{{-- 說明 --}}
<div>
<label for="description" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
說明
</label>
<textarea name="description" id="description" rows="3"
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-900 dark:text-gray-300"
placeholder="收入來源說明">{{ old('description') }}</textarea>
@error('description')
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
@enderror
</div>
{{-- 備註 --}}
<div>
<label for="notes" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
內部備註
</label>
<textarea name="notes" id="notes" rows="2"
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-900 dark:text-gray-300"
placeholder="內部備註(僅管理員可見)">{{ old('notes') }}</textarea>
@error('notes')
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
@enderror
</div>
{{-- 附件 --}}
<div>
<label for="attachment" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
附件
</label>
<input type="file" name="attachment" id="attachment"
class="mt-1 block w-full text-sm text-gray-500 dark:text-gray-400
file:mr-4 file:py-2 file:px-4
file:rounded-md file:border-0
file:text-sm file:font-semibold
file:bg-indigo-50 file:text-indigo-700
dark:file:bg-indigo-900 dark:file:text-indigo-300
hover:file:bg-indigo-100 dark:hover:file:bg-indigo-800">
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">支援 PDF、圖片等格式最大 10MB</p>
@error('attachment')
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
@enderror
</div>
</div>
{{-- 提交按鈕 --}}
<div class="flex justify-end space-x-3 pt-6">
<a href="{{ route('admin.incomes.index') }}"
class="inline-flex items-center rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-600">
取消
</a>
<button type="submit"
class="inline-flex items-center rounded-md border border-transparent 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 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2">
建立收入記錄
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</x-app-layout>