feat(api): 예상비용 동기화 커맨드 및 서비스 개선
- SyncExpectedExpensesCommand 추가 - ExpectedExpenseService 로직 개선 - LOGICAL_RELATIONSHIPS 문서 업데이트 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -312,6 +312,8 @@ public function summary(array $params): array
|
||||
* remaining_balance: float,
|
||||
* item_count: int
|
||||
* },
|
||||
* monthly_trend: array,
|
||||
* vendor_distribution: array,
|
||||
* items: array,
|
||||
* footer_summary: array
|
||||
* }
|
||||
@@ -356,7 +358,13 @@ public function dashboardDetail(?string $transactionType = null): array
|
||||
->where('payment_status', 'pending')
|
||||
->sum('amount');
|
||||
|
||||
// 2. 지출예상 목록 (당월, 지급일 순)
|
||||
// 2. 월별 추이 (최근 7개월)
|
||||
$monthlyTrend = $this->getMonthlyTrend($tenantId, $transactionType);
|
||||
|
||||
// 3. 거래처별 분포 (당월, 상위 5개)
|
||||
$vendorDistribution = $this->getVendorDistribution($tenantId, $transactionType, $currentMonthStart, $currentMonthEnd);
|
||||
|
||||
// 4. 지출예상 목록 (당월, 지급일 순)
|
||||
$itemsQuery = ExpectedExpense::query()
|
||||
->select([
|
||||
'expected_expenses.id',
|
||||
@@ -394,7 +402,7 @@ public function dashboardDetail(?string $transactionType = null): array
|
||||
})
|
||||
->toArray();
|
||||
|
||||
// 3. 푸터 합계
|
||||
// 5. 푸터 합계
|
||||
$footerSummary = [
|
||||
'total_amount' => (float) $currentMonthTotal,
|
||||
'item_count' => count($items),
|
||||
@@ -407,8 +415,111 @@ public function dashboardDetail(?string $transactionType = null): array
|
||||
'change_rate' => $changeRate,
|
||||
'remaining_balance' => (float) $pendingBalance,
|
||||
],
|
||||
'monthly_trend' => $monthlyTrend,
|
||||
'vendor_distribution' => $vendorDistribution,
|
||||
'items' => $items,
|
||||
'footer_summary' => $footerSummary,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 월별 추이 데이터 조회 (최근 7개월)
|
||||
*/
|
||||
private function getMonthlyTrend(int $tenantId, ?string $transactionType = null): array
|
||||
{
|
||||
$months = [];
|
||||
for ($i = 6; $i >= 0; $i--) {
|
||||
$date = now()->subMonths($i);
|
||||
$months[] = [
|
||||
'month' => $date->format('Y-m'),
|
||||
'label' => $date->format('n') . '월',
|
||||
'start' => $date->startOfMonth()->toDateString(),
|
||||
'end' => $date->endOfMonth()->toDateString(),
|
||||
];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
foreach ($months as $month) {
|
||||
$query = ExpectedExpense::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->whereBetween('expected_payment_date', [$month['start'], $month['end']]);
|
||||
|
||||
if ($transactionType) {
|
||||
$query->where('transaction_type', $transactionType);
|
||||
}
|
||||
|
||||
$amount = $query->sum('amount');
|
||||
|
||||
$result[] = [
|
||||
'month' => $month['month'],
|
||||
'label' => $month['label'],
|
||||
'amount' => (float) $amount,
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 거래처별 분포 데이터 조회 (상위 N개 + 기타)
|
||||
*/
|
||||
private function getVendorDistribution(int $tenantId, ?string $transactionType, string $startDate, string $endDate, int $limit = 5): array
|
||||
{
|
||||
$query = ExpectedExpense::query()
|
||||
->select(
|
||||
DB::raw("COALESCE(client_name, '미지정') as vendor_name"),
|
||||
DB::raw('SUM(amount) as total_amount'),
|
||||
DB::raw('COUNT(*) as count')
|
||||
)
|
||||
->where('tenant_id', $tenantId)
|
||||
->whereBetween('expected_payment_date', [$startDate, $endDate])
|
||||
->groupBy('client_name')
|
||||
->orderByDesc('total_amount');
|
||||
|
||||
if ($transactionType) {
|
||||
$query->where('transaction_type', $transactionType);
|
||||
}
|
||||
|
||||
$all = $query->get();
|
||||
|
||||
// 전체 합계
|
||||
$totalSum = $all->sum('total_amount');
|
||||
if ($totalSum <= 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 상위 N개
|
||||
$top = $all->take($limit);
|
||||
$topSum = $top->sum('total_amount');
|
||||
|
||||
// 색상 팔레트
|
||||
$colors = ['#60A5FA', '#34D399', '#FBBF24', '#F87171', '#A78BFA', '#94A3B8'];
|
||||
|
||||
$result = [];
|
||||
foreach ($top as $index => $item) {
|
||||
$percentage = round(($item->total_amount / $totalSum) * 100, 1);
|
||||
$result[] = [
|
||||
'name' => $item->vendor_name,
|
||||
'value' => (float) $item->total_amount,
|
||||
'count' => (int) $item->count,
|
||||
'percentage' => $percentage,
|
||||
'color' => $colors[$index] ?? '#94A3B8',
|
||||
];
|
||||
}
|
||||
|
||||
// 기타 (나머지 합산)
|
||||
$othersSum = $totalSum - $topSum;
|
||||
if ($othersSum > 0 && $all->count() > $limit) {
|
||||
$othersCount = $all->skip($limit)->sum('count');
|
||||
$result[] = [
|
||||
'name' => '기타',
|
||||
'value' => (float) $othersSum,
|
||||
'count' => (int) $othersCount,
|
||||
'percentage' => round(($othersSum / $totalSum) * 100, 1),
|
||||
'color' => '#94A3B8',
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user