From b6de7fc7223c3e4f441c00b4d246a11fc87430a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=ED=98=81=EC=84=B1?= Date: Wed, 21 Jan 2026 10:39:17 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20expense=5Faccounts=20=ED=85=8C=EC=9D=B4?= =?UTF-8?q?=EB=B8=94=20=EB=B0=8F=20=EB=AA=A8=EB=8D=B8=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=20(=EB=B3=B5=EB=A6=AC=ED=9B=84=EC=83=9D=EB=B9=84/=EC=A0=91?= =?UTF-8?q?=EB=8C=80=EB=B9=84=EC=9A=A9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LOGICAL_RELATIONSHIPS.md | 65 ++++++++++++- app/Models/Tenants/ExpenseAccount.php | 93 +++++++++++++++++++ ...1_103734_create_expense_accounts_table.php | 61 ++++++++++++ 3 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 app/Models/Tenants/ExpenseAccount.php create mode 100644 database/migrations/2026_01_21_103734_create_expense_accounts_table.php diff --git a/LOGICAL_RELATIONSHIPS.md b/LOGICAL_RELATIONSHIPS.md index 726f5fd..4ebd731 100644 --- a/LOGICAL_RELATIONSHIPS.md +++ b/LOGICAL_RELATIONSHIPS.md @@ -1,6 +1,6 @@ # 논리적 데이터베이스 관계 문서 -> **자동 생성**: 2026-01-20 20:15:39 +> **자동 생성**: 2026-01-21 10:38:32 > **소스**: Eloquent 모델 관계 분석 ## 📊 모델별 관계 현황 @@ -26,6 +26,15 @@ ### bad_debt_memos - **badDebt()**: belongsTo → `bad_debts` - **creator()**: belongsTo → `users` +### biddings +**모델**: `App\Models\Bidding\Bidding` + +- **quote()**: belongsTo → `quotes` +- **client()**: belongsTo → `clients` +- **bidder()**: belongsTo → `users` +- **creator()**: belongsTo → `users` +- **updater()**: belongsTo → `users` + ### boards **모델**: `App\Models\Boards\Board` @@ -128,6 +137,38 @@ ### contracts - **contractManager()**: belongsTo → `users` - **constructionPm()**: belongsTo → `users` +- **creator()**: belongsTo → `users` +- **updater()**: belongsTo → `users` +- **handoverReport()**: hasOne → `handover_reports` + +### handover_reports +**모델**: `App\Models\Construction\HandoverReport` + +- **contract()**: belongsTo → `contracts` +- **contractManager()**: belongsTo → `users` +- **constructionPm()**: belongsTo → `users` +- **creator()**: belongsTo → `users` +- **updater()**: belongsTo → `users` +- **managers()**: hasMany → `handover_report_managers` +- **items()**: hasMany → `handover_report_items` + +### handover_report_items +**모델**: `App\Models\Construction\HandoverReportItem` + +- **handoverReport()**: belongsTo → `handover_reports` +- **creator()**: belongsTo → `users` +- **updater()**: belongsTo → `users` + +### handover_report_managers +**모델**: `App\Models\Construction\HandoverReportManager` + +- **handoverReport()**: belongsTo → `handover_reports` +- **creator()**: belongsTo → `users` +- **updater()**: belongsTo → `users` + +### structure_reviews +**모델**: `App\Models\Construction\StructureReview` + - **creator()**: belongsTo → `users` - **updater()**: belongsTo → `users` @@ -224,6 +265,7 @@ ### item_receipts **모델**: `App\Models\Items\ItemReceipt` - **item()**: belongsTo → `items` +- **creator()**: belongsTo → `users` ### login_tokens **모델**: `App\Models\LoginToken` @@ -332,10 +374,14 @@ ### orders **모델**: `App\Models\Orders\Order` - **quote()**: belongsTo → `quotes` +- **client()**: belongsTo → `clients` +- **writer()**: belongsTo → `users` - **item()**: belongsTo → `items` - **items()**: hasMany → `order_items` - **histories()**: hasMany → `order_histories` - **versions()**: hasMany → `order_versions` +- **workOrders()**: hasMany → `work_orders` +- **shipments()**: hasMany → `shipments` ### order_historys **모델**: `App\Models\Orders\OrderHistory` @@ -414,6 +460,7 @@ ### work_orders **모델**: `App\Models\Production\WorkOrder` - **salesOrder()**: belongsTo → `orders` +- **process()**: belongsTo → `processes` - **assignee()**: belongsTo → `users` - **team()**: belongsTo → `departments` - **creator()**: belongsTo → `users` @@ -422,6 +469,7 @@ ### work_orders - **primaryAssignee()**: hasMany → `work_order_assignees` - **items()**: hasMany → `work_order_items` - **issues()**: hasMany → `work_order_issues` +- **shipments()**: hasMany → `shipments` - **bendingDetail()**: hasOne → `work_order_bending_details` ### work_order_assignees @@ -509,6 +557,8 @@ ### inspections **모델**: `App\Models\Qualitys\Inspection` - **item()**: belongsTo → `items` +- **inspector()**: belongsTo → `users` +- **creator()**: belongsTo → `users` ### lots **모델**: `App\Models\Qualitys\Lot` @@ -527,11 +577,13 @@ ### quotes - **client()**: belongsTo → `clients` - **item()**: belongsTo → `items` - **order()**: belongsTo → `orders` +- **siteBriefing()**: belongsTo → `site_briefings` - **finalizer()**: belongsTo → `users` - **creator()**: belongsTo → `users` - **updater()**: belongsTo → `users` - **items()**: hasMany → `quote_items` - **revisions()**: hasMany → `quote_revisions` +- **orders()**: hasMany → `orders` ### quote_formulas **모델**: `App\Models\Quote\QuoteFormula` @@ -774,6 +826,8 @@ ### setting_field_defs ### shipments **모델**: `App\Models\Tenants\Shipment` +- **order()**: belongsTo → `orders` +- **workOrder()**: belongsTo → `work_orders` - **creator()**: belongsTo → `users` - **updater()**: belongsTo → `users` - **items()**: hasMany → `shipment_items` @@ -791,6 +845,15 @@ ### sites - **updater()**: belongsTo → `users` - **client()**: belongsTo → `clients` +### site_briefings +**모델**: `App\Models\Tenants\SiteBriefing` + +- **partner()**: belongsTo → `clients` +- **site()**: belongsTo → `sites` +- **creator()**: belongsTo → `users` +- **updater()**: belongsTo → `users` +- **quotes()**: hasMany → `quotes` + ### stocks **모델**: `App\Models\Tenants\Stock` diff --git a/app/Models/Tenants/ExpenseAccount.php b/app/Models/Tenants/ExpenseAccount.php new file mode 100644 index 0000000..eb3b3f8 --- /dev/null +++ b/app/Models/Tenants/ExpenseAccount.php @@ -0,0 +1,93 @@ + 'date', + 'amount' => 'decimal:2', + ]; + + // 계정 유형 상수 + public const TYPE_WELFARE = 'welfare'; + public const TYPE_ENTERTAINMENT = 'entertainment'; + public const TYPE_TRAVEL = 'travel'; + public const TYPE_OFFICE = 'office'; + + // 세부 유형 상수 (복리후생) + public const SUB_TYPE_MEAL = 'meal'; + public const SUB_TYPE_HEALTH = 'health'; + public const SUB_TYPE_EDUCATION = 'education'; + + // 결제 수단 상수 + public const PAYMENT_CARD = 'card'; + public const PAYMENT_CASH = 'cash'; + public const PAYMENT_TRANSFER = 'transfer'; + + /** + * 거래처 관계 + */ + public function vendor(): BelongsTo + { + return $this->belongsTo(Client::class, 'vendor_id'); + } + + /** + * 복리후생비 스코프 + */ + public function scopeWelfare($query) + { + return $query->where('account_type', self::TYPE_WELFARE); + } + + /** + * 접대비 스코프 + */ + public function scopeEntertainment($query) + { + return $query->where('account_type', self::TYPE_ENTERTAINMENT); + } + + /** + * 기간 필터 스코프 + */ + public function scopeInPeriod($query, string $startDate, string $endDate) + { + return $query->whereBetween('expense_date', [$startDate, $endDate]); + } +} \ No newline at end of file diff --git a/database/migrations/2026_01_21_103734_create_expense_accounts_table.php b/database/migrations/2026_01_21_103734_create_expense_accounts_table.php new file mode 100644 index 0000000..be8ca55 --- /dev/null +++ b/database/migrations/2026_01_21_103734_create_expense_accounts_table.php @@ -0,0 +1,61 @@ +id(); + $table->unsignedBigInteger('tenant_id')->comment('테넌트 ID'); + + // 비용 유형 + $table->string('account_type', 50)->comment('계정 유형: welfare, entertainment, etc.'); + $table->string('sub_type', 50)->nullable()->comment('세부 유형: meal, gift, etc.'); + + // 비용 정보 + $table->date('expense_date')->comment('지출일'); + $table->decimal('amount', 15, 2)->default(0)->comment('금액'); + $table->string('description', 500)->nullable()->comment('비용 내역'); + $table->string('receipt_no', 100)->nullable()->comment('증빙번호'); + + // 거래처 정보 (접대비 등에서 사용) + $table->unsignedBigInteger('vendor_id')->nullable()->comment('거래처 ID'); + $table->string('vendor_name', 200)->nullable()->comment('거래처명 (직접 입력)'); + + // 카드/결제 정보 + $table->string('payment_method', 50)->nullable()->comment('결제수단: card, cash, transfer'); + $table->string('card_no', 50)->nullable()->comment('카드 마지막 4자리'); + + // 감사 컬럼 + $table->unsignedBigInteger('created_by')->nullable()->comment('등록자'); + $table->unsignedBigInteger('updated_by')->nullable()->comment('수정자'); + $table->unsignedBigInteger('deleted_by')->nullable()->comment('삭제자'); + + $table->timestamps(); + $table->softDeletes(); + + // 인덱스 + $table->index(['tenant_id', 'account_type', 'expense_date']); + $table->index(['tenant_id', 'expense_date']); + + // 외래키 + $table->foreign('tenant_id')->references('id')->on('tenants')->onDelete('cascade'); + $table->foreign('vendor_id')->references('id')->on('clients')->onDelete('set null'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('expense_accounts'); + } +}; \ No newline at end of file