Files
sam-manage/app/Http/Controllers/Finance/SettlementController.php
김보곤 7bc412d9a1 feat:통합 정산관리 페이지 구현 (5개 탭 기반)
- SettlementController 신규 생성 (통합 정산관리 메인 + 탭별 HTMX)
- 5개 탭: 수당정산, 파트너별현황(NEW), 컨설팅비용, 고객사정산, 구독관리
- 수당정산 탭: 기존 영업수수료정산 이관 + 유치수당 컬럼/수당유형 필터 추가
- 파트너별 현황 탭: SalesPartner 수당 집계 + 필터/페이지네이션
- 컨설팅/고객사/구독 탭: React → Blade+Alpine.js 전환 (기존 API 재사용)
- 통합 통계카드 (미지급수당/승인대기/이번달예정/누적지급)
- 기존 4개 URL → 통합 페이지 리다이렉트
- SalesPartner 모델에 commissions 관계 추가
- SalesCommissionService에 commission_type 필터 + referrerPartner eager load 추가

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:53:13 +09:00

223 lines
7.3 KiB
PHP

<?php
namespace App\Http\Controllers\Finance;
use App\Http\Controllers\Controller;
use App\Models\Sales\SalesCommission;
use App\Models\Sales\SalesPartner;
use App\Services\SalesCommissionService;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\View\View;
class SettlementController extends Controller
{
public function __construct(
private SalesCommissionService $service
) {}
/**
* 통합 정산관리 메인 페이지
*/
public function index(Request $request): View|Response
{
if ($request->header('HX-Request') && !$request->header('HX-Boosted')) {
return response('', 200)->header('HX-Redirect', route('finance.settlement'));
}
$initialTab = $request->input('tab', 'commission');
// 수당 정산 탭 데이터 (기본 탭이므로 즉시 로드)
$year = $request->input('year', now()->year);
$month = $request->input('month', now()->month);
$filters = [
'scheduled_year' => $year,
'scheduled_month' => $month,
'status' => $request->input('status'),
'payment_type' => $request->input('payment_type'),
'partner_id' => $request->input('partner_id'),
'commission_type' => $request->input('commission_type'),
'search' => $request->input('search'),
];
$commissions = $this->service->getCommissions($filters);
$stats = $this->service->getSettlementStats($year, $month);
$partners = SalesPartner::with('user')
->active()
->orderBy('partner_code')
->get();
$pendingTenants = $this->service->getPendingPaymentTenants();
// 통합 통계 (페이지 상단)
$summaryStats = $this->getSummaryStats();
return view('finance.settlement.index', compact(
'initialTab',
'commissions',
'stats',
'partners',
'pendingTenants',
'year',
'month',
'filters',
'summaryStats'
));
}
/**
* 수당 통계카드 HTMX 갱신
*/
public function commissionStats(Request $request): View
{
$year = $request->input('year', now()->year);
$month = $request->input('month', now()->month);
$stats = $this->service->getSettlementStats($year, $month);
return view('finance.settlement.partials.commission.stats-cards', compact('stats', 'year', 'month'));
}
/**
* 수당 테이블 HTMX 갱신
*/
public function commissionTable(Request $request): View
{
$year = $request->input('year', now()->year);
$month = $request->input('month', now()->month);
$filters = [
'scheduled_year' => $year,
'scheduled_month' => $month,
'status' => $request->input('status'),
'payment_type' => $request->input('payment_type'),
'partner_id' => $request->input('partner_id'),
'commission_type' => $request->input('commission_type'),
'search' => $request->input('search'),
];
$commissions = $this->service->getCommissions($filters);
return view('finance.settlement.partials.commission.table', compact('commissions'));
}
/**
* 파트너별 현황 탭
*/
public function partnerSummary(Request $request): View
{
$query = SalesPartner::with('user');
// 검색
if ($search = $request->input('search')) {
$query->where(function ($q) use ($search) {
$q->where('partner_code', 'like', "%{$search}%")
->orWhereHas('user', function ($uq) use ($search) {
$uq->where('name', 'like', "%{$search}%");
});
});
}
// 유형 필터
if ($type = $request->input('type')) {
if ($type === 'individual') {
$query->where('partner_type', '!=', 'corporate');
} elseif ($type === 'corporate') {
$query->where('partner_type', 'corporate');
}
}
// 상태 필터
if ($request->input('status', 'active') === 'active') {
$query->active();
}
$partners = $query->orderBy('partner_code')->paginate(20);
// 각 파트너별 수당 집계
$partnerIds = $partners->pluck('id')->toArray();
if (!empty($partnerIds)) {
$commissionStats = SalesCommission::selectRaw('
partner_id,
SUM(CASE WHEN status = "paid" THEN partner_commission ELSE 0 END) as paid_total,
SUM(CASE WHEN status IN ("pending", "approved") THEN partner_commission ELSE 0 END) as unpaid_total,
COUNT(*) as total_count,
MAX(CASE WHEN status = "paid" THEN actual_payment_date ELSE NULL END) as last_paid_date
')
->whereIn('partner_id', $partnerIds)
->groupBy('partner_id')
->get()
->keyBy('partner_id');
} else {
$commissionStats = collect();
}
return view('finance.settlement.partials.partner-summary', compact('partners', 'commissionStats'));
}
/**
* 컨설팅비용 탭
*/
public function consultingTab(Request $request): View
{
return view('finance.settlement.partials.consulting-tab');
}
/**
* 고객사정산 탭
*/
public function customerTab(Request $request): View
{
return view('finance.settlement.partials.customer-tab');
}
/**
* 구독관리 탭
*/
public function subscriptionTab(Request $request): View
{
return view('finance.settlement.partials.subscription-tab');
}
/**
* 통합 통계 데이터
*/
private function getSummaryStats(): array
{
$now = now();
// 미지급 수당 (pending + approved)
$unpaidAmount = SalesCommission::whereIn('status', [
SalesCommission::STATUS_PENDING,
SalesCommission::STATUS_APPROVED,
])->selectRaw('SUM(partner_commission + manager_commission + COALESCE(referrer_commission, 0)) as total')
->value('total') ?? 0;
// 승인 대기 건수
$pendingCount = SalesCommission::where('status', SalesCommission::STATUS_PENDING)->count();
// 이번달 지급예정
$thisMonthScheduled = SalesCommission::whereIn('status', [
SalesCommission::STATUS_PENDING,
SalesCommission::STATUS_APPROVED,
])
->whereYear('scheduled_payment_date', $now->year)
->whereMonth('scheduled_payment_date', $now->month)
->selectRaw('SUM(partner_commission + manager_commission + COALESCE(referrer_commission, 0)) as total')
->value('total') ?? 0;
// 누적 지급완료
$totalPaid = SalesCommission::where('status', SalesCommission::STATUS_PAID)
->selectRaw('SUM(partner_commission + manager_commission + COALESCE(referrer_commission, 0)) as total')
->value('total') ?? 0;
return [
'unpaid_amount' => $unpaidAmount,
'pending_count' => $pendingCount,
'this_month_scheduled' => $thisMonthScheduled,
'total_paid' => $totalPaid,
];
}
}