startOfDay(); $endDate = $startDate->copy()->endOfMonth(); // 현장 현황 $activeSites = DB::connection('mysql') ->table('sites') ->where('tenant_id', $tenantId) ->where('status', 'active') ->whereNull('deleted_at') ->count(); $completedSites = DB::connection('mysql') ->table('sites') ->where('tenant_id', $tenantId) ->where('status', 'completed') ->whereNull('deleted_at') ->count(); // 계약 현황 (해당 월 신규 계약) $contractStats = DB::connection('mysql') ->table('contracts') ->where('tenant_id', $tenantId) ->whereBetween('created_at', [$startDate, $endDate]) ->whereNull('deleted_at') ->selectRaw(' COUNT(*) as new_count, COALESCE(SUM(contract_amount), 0) as total_amount ') ->first(); // 지출예상 (해당 월) $expenseStats = DB::connection('mysql') ->table('expected_expenses') ->where('tenant_id', $tenantId) ->whereYear('expected_payment_date', $year) ->whereMonth('expected_payment_date', $month) ->whereNull('deleted_at') ->selectRaw(' COALESCE(SUM(amount), 0) as expected_total, COALESCE(SUM(CASE WHEN payment_status = \'paid\' THEN amount ELSE 0 END), 0) as actual_total ') ->first(); // 수익률 계산 $contractTotal = (float) ($contractStats->total_amount ?? 0); $actualExpense = (float) ($expenseStats->actual_total ?? 0); $grossProfit = $contractTotal - $actualExpense; $grossProfitRate = $contractTotal > 0 ? ($grossProfit / $contractTotal) * 100 : 0; StatProjectMonthly::updateOrCreate( [ 'tenant_id' => $tenantId, 'stat_year' => $year, 'stat_month' => $month, ], [ 'active_site_count' => $activeSites, 'completed_site_count' => $completedSites, 'new_contract_count' => $contractStats->new_count ?? 0, 'contract_total_amount' => $contractTotal, 'expected_expense_total' => $expenseStats->expected_total ?? 0, 'actual_expense_total' => $actualExpense, 'labor_cost_total' => 0, 'material_cost_total' => 0, 'gross_profit' => $grossProfit, 'gross_profit_rate' => $grossProfitRate, 'handover_report_count' => 0, 'structure_review_count' => 0, ] ); return 1; } }