feat: [재무] 어음 V8 + 상품권 접대비 연동 + 일반전표/계정과목 API

- Bill 확장 필드 (V8), Loan 상품권 카테고리/접대비 자동 연동
- GeneralJournalEntry CRUD, AccountSubject API
- 접대비/복리후생비 날짜 필터, 매출채권 soft delete 제외
- 바로빌 연동 API 엔드포인트 추가
- 부가세 상세 조회 API

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-07 02:58:55 +09:00
parent 3d12687a2d
commit 1df34b2fa9
36 changed files with 3579 additions and 378 deletions

View File

@@ -304,34 +304,41 @@ public function summary(array $params): array
* 대시보드 상세 조회 (CEO 대시보드 당월 예상 지출내역 모달용)
*
* @param string|null $transactionType 거래유형 필터 (purchase, card, bill, null=전체)
* @return array{
* summary: array{
* total_amount: float,
* previous_month_amount: float,
* change_rate: float,
* remaining_balance: float,
* item_count: int
* },
* monthly_trend: array,
* vendor_distribution: array,
* items: array,
* footer_summary: array
* }
* @param string|null $startDate 조회 시작일 (null이면 당월 1일)
* @param string|null $endDate 조회 종료일 (null이면 당월 말일)
* @param string|null $search 검색어 (거래처명, 적요)
*/
public function dashboardDetail(?string $transactionType = null): array
{
public function dashboardDetail(
?string $transactionType = null,
?string $startDate = null,
?string $endDate = null,
?string $search = null
): array {
$tenantId = $this->tenantId();
$currentMonthStart = now()->startOfMonth()->toDateString();
$currentMonthEnd = now()->endOfMonth()->toDateString();
$previousMonthStart = now()->subMonth()->startOfMonth()->toDateString();
$previousMonthEnd = now()->subMonth()->endOfMonth()->toDateString();
// 기본 쿼리 빌더 (transaction_type 필터 적용)
$baseQuery = function () use ($tenantId, $transactionType) {
// 날짜 범위: 파라미터 우선, 없으면 당월 기본값
$currentMonthStart = $startDate ?? now()->startOfMonth()->toDateString();
$currentMonthEnd = $endDate ?? now()->endOfMonth()->toDateString();
// 전월 대비: 조회 기간과 동일한 길이의 이전 기간 계산
$startCarbon = \Carbon\Carbon::parse($currentMonthStart);
$endCarbon = \Carbon\Carbon::parse($currentMonthEnd);
$daysDiff = $startCarbon->diffInDays($endCarbon) + 1;
$previousMonthStart = $startCarbon->copy()->subDays($daysDiff)->toDateString();
$previousMonthEnd = $startCarbon->copy()->subDay()->toDateString();
// 기본 쿼리 빌더 (transaction_type + search 필터 적용)
$baseQuery = function () use ($tenantId, $transactionType, $search) {
$query = ExpectedExpense::query()->where('tenant_id', $tenantId);
if ($transactionType) {
$query->where('transaction_type', $transactionType);
}
if ($search) {
$query->where(function ($q) use ($search) {
$q->where('client_name', 'like', "%{$search}%")
->orWhere('description', 'like', "%{$search}%");
});
}
return $query;
};
@@ -361,10 +368,10 @@ public function dashboardDetail(?string $transactionType = null): array
// 2. 월별 추이 (최근 7개월)
$monthlyTrend = $this->getMonthlyTrend($tenantId, $transactionType);
// 3. 거래처별 분포 (당월, 상위 5개)
// 3. 거래처별 분포 (조회 기간, 상위 5개)
$vendorDistribution = $this->getVendorDistribution($tenantId, $transactionType, $currentMonthStart, $currentMonthEnd);
// 4. 지출예상 목록 (당월, 지급일 순)
// 4. 지출예상 목록 (조회 기간, 지급일 순)
$itemsQuery = ExpectedExpense::query()
->select([
'expected_expenses.id',
@@ -385,6 +392,13 @@ public function dashboardDetail(?string $transactionType = null): array
$itemsQuery->where('expected_expenses.transaction_type', $transactionType);
}
if ($search) {
$itemsQuery->where(function ($q) use ($search) {
$q->where('expected_expenses.client_name', 'like', "%{$search}%")
->orWhere('expected_expenses.description', 'like', "%{$search}%");
});
}
$items = $itemsQuery
->orderBy('expected_expenses.expected_payment_date', 'asc')
->get()