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>
This commit is contained in:
40
database/factories/AuditLogFactory.php
Normal file
40
database/factories/AuditLogFactory.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\AuditLog;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class AuditLogFactory extends Factory
|
||||
{
|
||||
protected $model = AuditLog::class;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'user_id' => User::factory(),
|
||||
'action' => $this->faker->randomElement([
|
||||
'member_created',
|
||||
'member_status_changed',
|
||||
'payment_approved',
|
||||
'payment_rejected',
|
||||
'finance_document_created',
|
||||
'finance_document_approved',
|
||||
'user_login',
|
||||
'role_assigned',
|
||||
]),
|
||||
'auditable_type' => $this->faker->randomElement([
|
||||
'App\Models\Member',
|
||||
'App\Models\MembershipPayment',
|
||||
'App\Models\FinanceDocument',
|
||||
'App\Models\User',
|
||||
]),
|
||||
'auditable_id' => $this->faker->numberBetween(1, 100),
|
||||
'metadata' => [
|
||||
'ip_address' => $this->faker->ipv4(),
|
||||
'user_agent' => $this->faker->userAgent(),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
32
database/factories/BankReconciliationFactory.php
Normal file
32
database/factories/BankReconciliationFactory.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\BankReconciliation;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class BankReconciliationFactory extends Factory
|
||||
{
|
||||
protected $model = BankReconciliation::class;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
$bankBalance = $this->faker->numberBetween(50000, 500000);
|
||||
$bookBalance = $bankBalance + $this->faker->numberBetween(-5000, 5000);
|
||||
|
||||
return [
|
||||
'reconciliation_month' => now()->startOfMonth(),
|
||||
'bank_statement_date' => now(),
|
||||
'bank_statement_balance' => $bankBalance,
|
||||
'system_book_balance' => $bookBalance,
|
||||
'outstanding_checks' => [],
|
||||
'deposits_in_transit' => [],
|
||||
'bank_charges' => [],
|
||||
'prepared_by_cashier_id' => User::factory(),
|
||||
'prepared_at' => now(),
|
||||
'reconciliation_status' => 'pending',
|
||||
'discrepancy_amount' => abs($bankBalance - $bookBalance),
|
||||
];
|
||||
}
|
||||
}
|
||||
16
database/factories/BudgetCategoryFactory.php
Normal file
16
database/factories/BudgetCategoryFactory.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class BudgetCategoryFactory extends Factory
|
||||
{
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->unique()->words(2, true),
|
||||
'description' => $this->faker->sentence(),
|
||||
];
|
||||
}
|
||||
}
|
||||
22
database/factories/ChartOfAccountFactory.php
Normal file
22
database/factories/ChartOfAccountFactory.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\ChartOfAccount;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class ChartOfAccountFactory extends Factory
|
||||
{
|
||||
protected $model = ChartOfAccount::class;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'code' => $this->faker->unique()->numerify('####'),
|
||||
'name' => $this->faker->words(3, true),
|
||||
'type' => $this->faker->randomElement(['asset', 'liability', 'equity', 'revenue', 'expense']),
|
||||
'description' => $this->faker->sentence(),
|
||||
'is_active' => true,
|
||||
];
|
||||
}
|
||||
}
|
||||
23
database/factories/DocumentCategoryFactory.php
Normal file
23
database/factories/DocumentCategoryFactory.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\DocumentCategory;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class DocumentCategoryFactory extends Factory
|
||||
{
|
||||
protected $model = DocumentCategory::class;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->unique()->words(2, true),
|
||||
'slug' => $this->faker->unique()->slug(2),
|
||||
'description' => $this->faker->sentence(),
|
||||
'icon' => $this->faker->randomElement(['📄', '📁', '📋', '📊', '📈']),
|
||||
'sort_order' => $this->faker->numberBetween(1, 100),
|
||||
'default_access_level' => $this->faker->randomElement(['public', 'members', 'admin', 'board']),
|
||||
];
|
||||
}
|
||||
}
|
||||
31
database/factories/DocumentFactory.php
Normal file
31
database/factories/DocumentFactory.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Document;
|
||||
use App\Models\DocumentCategory;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class DocumentFactory extends Factory
|
||||
{
|
||||
protected $model = Document::class;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'document_category_id' => DocumentCategory::factory(),
|
||||
'title' => $this->faker->sentence(3),
|
||||
'document_number' => 'DOC-'.now()->format('Y').'-'.str_pad(rand(1, 9999), 4, '0', STR_PAD_LEFT),
|
||||
'description' => $this->faker->paragraph(),
|
||||
'public_uuid' => (string) Str::uuid(),
|
||||
'access_level' => $this->faker->randomElement(['public', 'members', 'admin']),
|
||||
'status' => 'active',
|
||||
'created_by_user_id' => User::factory(),
|
||||
'view_count' => $this->faker->numberBetween(0, 100),
|
||||
'download_count' => $this->faker->numberBetween(0, 50),
|
||||
'version_count' => 1,
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user