Files
sam-api/database/seeders/ComprehensiveAnalysisSeeder.php
kent 472cf53289 fix: 종합분석 오늘의 이슈 승인/반려 버그 수정
- ComprehensiveAnalysisService::getTodayIssue() 수정
  - 현재 사용자가 결재자인 문서만 조회하도록 whereHas 조건 추가
  - 이전: 테넌트의 모든 대기 결재 표시 → "결재 순서가 아닙니다" 오류
  - 수정: 현재 로그인 사용자가 approver_id인 문서만 표시

- ComprehensiveAnalysisSeeder 테스트 데이터 수정
  - Tenant 287 (프론트_테스트회사) 기준
  - User 33 (홍킬동) 기준으로 결재 단계 생성

- Client 모델 재무 컬럼 추가 (마이그레이션 포함)
  - outstanding_balance: 미수금
  - credit_limit: 여신한도

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-27 18:47:46 +09:00

312 lines
12 KiB
PHP

<?php
namespace Database\Seeders;
use App\Models\BadDebts\BadDebt;
use App\Models\Orders\Client;
use App\Models\Tenants\Approval;
use App\Models\Tenants\ApprovalForm;
use App\Models\Tenants\ApprovalStep;
use App\Models\Tenants\Deposit;
use App\Models\Tenants\ExpectedExpense;
use Carbon\Carbon;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
/**
* 종합분석 페이지 테스트 데이터 Seeder
*
* 다음 테이블에 샘플 데이터를 생성합니다:
* - ApprovalForm, Approval (결재 대기)
* - ExpectedExpense (예상 지출)
* - Deposit (입금)
* - BadDebt (채권추심)
* - Client (미수금/여신한도 업데이트)
*/
class ComprehensiveAnalysisSeeder extends Seeder
{
private int $tenantId = 287; // 프론트_테스트회사
private int $userId = 33; // 홍킬동 (Tenant 287 기본 사용자)
public function run(): void
{
$this->command->info('종합분석 테스트 데이터 생성 시작...');
DB::transaction(function () {
$this->seedApprovalForms();
$this->seedApprovals();
$this->seedExpectedExpenses();
$this->seedDeposits();
$this->seedBadDebts();
$this->updateClientBalances();
});
$this->command->info('종합분석 테스트 데이터 생성 완료!');
}
/**
* 결재 양식 생성
*/
private function seedApprovalForms(): void
{
$forms = [
['code' => 'REQ-001', 'name' => '품의서', 'category' => 'request'],
['code' => 'EXP-001', 'name' => '지출결의서', 'category' => 'expense'],
['code' => 'EST-001', 'name' => '지출 예상 내역서', 'category' => 'expense_estimate'],
];
foreach ($forms as $form) {
ApprovalForm::firstOrCreate(
['tenant_id' => $this->tenantId, 'code' => $form['code']],
[
'name' => $form['name'],
'category' => $form['category'],
'template' => ['fields' => []],
'is_active' => true,
'created_by' => $this->userId,
]
);
}
$this->command->info(' - 결재 양식 3건 생성');
}
/**
* 결재 대기 문서 생성
*/
private function seedApprovals(): void
{
$form = ApprovalForm::where('tenant_id', $this->tenantId)->first();
if (! $form) {
$this->command->warn(' - 결재 양식이 없어 결재 문서 생성 건너뜀');
return;
}
$approvals = [
['title' => '12월 사무용품 구매 품의', 'time' => '09:15'],
['title' => '연말 회식비 지출결의', 'time' => '10:30'],
['title' => '출장비 정산 요청', 'time' => '11:45'],
['title' => '서버 호스팅 비용 결재', 'time' => '14:20'],
['title' => '신규 장비 구매 품의', 'time' => '15:00'],
];
$today = Carbon::today();
foreach ($approvals as $i => $approval) {
$approvalRecord = Approval::firstOrCreate(
[
'tenant_id' => $this->tenantId,
'document_number' => 'DOC-'.date('Ymd').'-'.str_pad($i + 1, 3, '0', STR_PAD_LEFT),
],
[
'form_id' => $form->id,
'title' => $approval['title'],
'content' => ['description' => $approval['title'].' 내용입니다.'],
'status' => Approval::STATUS_PENDING,
'drafter_id' => $this->userId,
'drafted_at' => $today->copy()->setTimeFromTimeString($approval['time']),
'current_step' => 1,
'created_by' => $this->userId,
]
);
// 결재 단계 생성 (현재 로그인 사용자가 승인/반려할 수 있도록)
ApprovalStep::firstOrCreate(
[
'approval_id' => $approvalRecord->id,
'step_order' => 1,
],
[
'step_type' => 'approval', // ApprovalLine::STEP_TYPE_APPROVAL
'approver_id' => $this->userId,
'status' => ApprovalStep::STATUS_PENDING,
]
);
}
$this->command->info(' - 결재 대기 문서 5건 + 결재 단계 생성');
}
/**
* 예상 지출 데이터 생성
*/
private function seedExpectedExpenses(): void
{
$today = Carbon::today();
$thisMonth = $today->copy()->startOfMonth();
$lastMonth = $today->copy()->subMonth()->startOfMonth();
$expenses = [
// 이번 달 지출
['type' => 'purchase', 'amount' => 5000000, 'status' => 'paid', 'date' => $thisMonth->copy()->addDays(5)],
['type' => 'purchase', 'amount' => 3000000, 'status' => 'pending', 'date' => $thisMonth->copy()->addDays(15)],
['type' => 'salary', 'amount' => 25000000, 'status' => 'paid', 'date' => $thisMonth->copy()->addDays(25)],
['type' => 'insurance', 'amount' => 2500000, 'status' => 'pending', 'date' => $thisMonth->copy()->addDays(28)],
['type' => 'rent', 'amount' => 3000000, 'status' => 'paid', 'date' => $thisMonth->copy()->addDays(1)],
['type' => 'utilities', 'amount' => 500000, 'status' => 'pending', 'date' => $thisMonth->copy()->addDays(20)],
['type' => 'tax', 'amount' => 1500000, 'status' => 'pending', 'date' => $thisMonth->copy()->addDays(25)],
['type' => 'other', 'amount' => 2000000, 'status' => 'paid', 'date' => $thisMonth->copy()->addDays(10)],
// 가지급금/선급금
['type' => 'suspense', 'amount' => 5000000, 'status' => 'pending', 'date' => $thisMonth->copy()->addDays(3)],
['type' => 'suspense', 'amount' => 3000000, 'status' => 'pending', 'date' => $thisMonth->copy()->addDays(12)],
['type' => 'advance', 'amount' => 2000000, 'status' => 'pending', 'date' => $thisMonth->copy()->addDays(8)],
// 연체 (지난 달)
['type' => 'purchase', 'amount' => 1500000, 'status' => 'pending', 'date' => $lastMonth->copy()->addDays(20)],
];
foreach ($expenses as $expense) {
ExpectedExpense::create([
'tenant_id' => $this->tenantId,
'expected_payment_date' => $expense['date'],
'transaction_type' => $expense['type'],
'amount' => $expense['amount'],
'payment_status' => $expense['status'],
'approval_status' => 'approved',
'description' => ExpectedExpense::TRANSACTION_TYPES[$expense['type']].' 지출',
'created_by' => $this->userId,
]);
}
$this->command->info(' - 예상 지출 12건 생성');
}
/**
* 입금 데이터 생성
*/
private function seedDeposits(): void
{
$today = Carbon::today();
$thisMonth = $today->copy()->startOfMonth();
$deposits = [
// 오늘 입금
['amount' => 5000000, 'method' => 'transfer', 'date' => $today, 'client' => '(주)테스트고객A'],
['amount' => 3000000, 'method' => 'transfer', 'date' => $today, 'client' => '(주)테스트고객B'],
// 이번 달 입금
['amount' => 10000000, 'method' => 'transfer', 'date' => $thisMonth->copy()->addDays(5), 'client' => '(주)테스트고객C'],
['amount' => 7500000, 'method' => 'card', 'date' => $thisMonth->copy()->addDays(10), 'client' => '(주)테스트고객D'],
['amount' => 15000000, 'method' => 'transfer', 'date' => $thisMonth->copy()->addDays(15), 'client' => '(주)테스트고객E'],
['amount' => 8000000, 'method' => 'check', 'date' => $thisMonth->copy()->addDays(20), 'client' => '(주)테스트고객F'],
];
foreach ($deposits as $deposit) {
Deposit::create([
'tenant_id' => $this->tenantId,
'deposit_date' => $deposit['date'],
'amount' => $deposit['amount'],
'payment_method' => $deposit['method'],
'client_name' => $deposit['client'],
'description' => $deposit['client'].' 입금',
'created_by' => $this->userId,
]);
}
$this->command->info(' - 입금 6건 생성');
}
/**
* 채권추심 데이터 생성
*/
private function seedBadDebts(): void
{
// 먼저 테스트 거래처 생성
$clients = $this->ensureTestClients();
$badDebts = [
// 추심중
['client_idx' => 0, 'amount' => 5000000, 'status' => BadDebt::STATUS_COLLECTING, 'days' => 45],
['client_idx' => 1, 'amount' => 3000000, 'status' => BadDebt::STATUS_COLLECTING, 'days' => 60],
// 법적조치
['client_idx' => 2, 'amount' => 8000000, 'status' => BadDebt::STATUS_LEGAL_ACTION, 'days' => 120],
// 회수완료 (올해)
['client_idx' => 3, 'amount' => 2000000, 'status' => BadDebt::STATUS_RECOVERED, 'days' => 30, 'closed' => true],
['client_idx' => 4, 'amount' => 1500000, 'status' => BadDebt::STATUS_RECOVERED, 'days' => 45, 'closed' => true],
// 대손처리
['client_idx' => 5, 'amount' => 10000000, 'status' => BadDebt::STATUS_BAD_DEBT, 'days' => 365, 'closed' => true],
];
foreach ($badDebts as $debt) {
$occurredAt = Carbon::today()->subDays($debt['days']);
BadDebt::create([
'tenant_id' => $this->tenantId,
'client_id' => $clients[$debt['client_idx']]->id ?? null,
'debt_amount' => $debt['amount'],
'status' => $debt['status'],
'overdue_days' => $debt['days'],
'assigned_user_id' => $this->userId,
'occurred_at' => $occurredAt,
'closed_at' => isset($debt['closed']) ? Carbon::today() : null,
'is_active' => ! isset($debt['closed']),
'created_by' => $this->userId,
]);
}
$this->command->info(' - 채권추심 6건 생성');
}
/**
* 테스트 거래처 생성
*/
private function ensureTestClients(): array
{
$clientNames = [
'(주)문제거래처A',
'(주)문제거래처B',
'(주)문제거래처C',
'(주)정상거래처D',
'(주)정상거래처E',
'(주)대손거래처F',
];
$clients = [];
foreach ($clientNames as $i => $name) {
$clients[] = Client::firstOrCreate(
['tenant_id' => $this->tenantId, 'client_code' => 'T'.$this->tenantId.'-'.str_pad($i + 1, 3, '0', STR_PAD_LEFT)],
[
'name' => $name,
'is_active' => true,
'client_type' => 'company',
]
);
}
return $clients;
}
/**
* 거래처 미수금/여신한도 업데이트
*/
private function updateClientBalances(): void
{
// 기존 거래처 중 일부에 미수금/여신한도 설정
$clients = Client::where('tenant_id', $this->tenantId)
->where('is_active', true)
->limit(5)
->get();
$balances = [
['outstanding' => 15000000, 'limit' => 10000000], // 한도 초과
['outstanding' => 8000000, 'limit' => 10000000], // 정상
['outstanding' => 12000000, 'limit' => 10000000], // 한도 초과
['outstanding' => 5000000, 'limit' => 20000000], // 정상
['outstanding' => 25000000, 'limit' => 20000000], // 한도 초과
];
foreach ($clients as $i => $client) {
if (isset($balances[$i])) {
$client->update([
'outstanding_balance' => $balances[$i]['outstanding'],
'credit_limit' => $balances[$i]['limit'],
]);
}
}
$this->command->info(' - 거래처 미수금/여신한도 업데이트 '.min(count($clients), 5).'건');
}
}