312 lines
12 KiB
PHP
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).'건');
|
||
|
|
}
|
||
|
|
}
|