refactor:고객사정산 탭 재설계 (실 테넌트 데이터 기반)
- customerTab() 메서드: SalesTenantManagement 기반 쿼리로 재작성 - getCustomerStats() private 메서드 추가 (총개발비/수금완료/미수금/개발진행/구독전환) - customer-tab.blade.php: Alpine.js CRUD → 순수 Blade 테이블로 전체 교체 - index.blade.php: 미사용 customerSettlementManager() Alpine 함수 제거 - 필터: 검색/개발상태/수금상태/담당파트너 4종 - 테이블: 고객사/파트너/매니저/개발비/1차/2차/구독료/개발상태 8열 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,9 @@
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Sales\SalesCommission;
|
||||
use App\Models\Sales\SalesContractProduct;
|
||||
use App\Models\Sales\SalesPartner;
|
||||
use App\Models\Sales\SalesTenantManagement;
|
||||
use App\Services\SalesCommissionService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
@@ -169,7 +171,91 @@ public function consultingTab(Request $request): View
|
||||
*/
|
||||
public function customerTab(Request $request): View
|
||||
{
|
||||
return view('finance.settlement.partials.customer-tab');
|
||||
$query = SalesTenantManagement::with([
|
||||
'tenant',
|
||||
'tenantProspect',
|
||||
'salesPartner.user',
|
||||
'manager',
|
||||
'commissions',
|
||||
])->where('hq_status', '!=', SalesTenantManagement::HQ_STATUS_PENDING);
|
||||
|
||||
// 필터: 검색 (회사명)
|
||||
if ($search = $request->input('search')) {
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->whereHas('tenant', fn ($tq) => $tq->where('company_name', 'like', "%{$search}%"))
|
||||
->orWhereHas('tenantProspect', fn ($pq) => $pq->where('company_name', 'like', "%{$search}%"));
|
||||
});
|
||||
}
|
||||
|
||||
// 필터: 개발 상태
|
||||
if ($hqStatus = $request->input('hq_status')) {
|
||||
$query->where('hq_status', $hqStatus);
|
||||
}
|
||||
|
||||
// 필터: 담당 파트너
|
||||
if ($partnerId = $request->input('partner_id')) {
|
||||
$query->where('sales_partner_id', $partnerId);
|
||||
}
|
||||
|
||||
// 필터: 수금 상태
|
||||
$paymentStatus = $request->input('payment_status');
|
||||
|
||||
$managements = $query->orderByDesc('id')->paginate(20)->withQueryString();
|
||||
|
||||
// 수금 상태 필터 (컬렉션 레벨)
|
||||
if ($paymentStatus) {
|
||||
$managements->setCollection(
|
||||
$managements->getCollection()->filter(function ($mgmt) use ($paymentStatus) {
|
||||
$depositPaid = $mgmt->deposit_status === 'paid';
|
||||
$balancePaid = $mgmt->balance_status === 'paid';
|
||||
return match ($paymentStatus) {
|
||||
'fully_paid' => $depositPaid && $balancePaid,
|
||||
'partial' => ($depositPaid || $balancePaid) && !($depositPaid && $balancePaid),
|
||||
'unpaid' => !$depositPaid && !$balancePaid,
|
||||
default => true,
|
||||
};
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// 구독료 일괄 조회 (N+1 방지)
|
||||
$tenantIds = $managements->getCollection()
|
||||
->pluck('tenant_id')
|
||||
->filter()
|
||||
->unique()
|
||||
->values()
|
||||
->toArray();
|
||||
|
||||
$subscriptionFees = [];
|
||||
if (!empty($tenantIds)) {
|
||||
$subscriptionFees = SalesContractProduct::whereIn('tenant_id', $tenantIds)
|
||||
->selectRaw('tenant_id, SUM(subscription_fee) as total_subscription_fee')
|
||||
->groupBy('tenant_id')
|
||||
->pluck('total_subscription_fee', 'tenant_id')
|
||||
->toArray();
|
||||
}
|
||||
|
||||
// 파트너 목록 (필터용)
|
||||
$partners = SalesPartner::with('user')
|
||||
->active()
|
||||
->orderBy('partner_code')
|
||||
->get();
|
||||
|
||||
// hqStatusLabels에서 pending 제외
|
||||
$hqStatusLabels = collect(SalesTenantManagement::$hqStatusLabels)
|
||||
->except(SalesTenantManagement::HQ_STATUS_PENDING)
|
||||
->toArray();
|
||||
|
||||
// 통계 카드
|
||||
$customerStats = $this->getCustomerStats();
|
||||
|
||||
return view('finance.settlement.partials.customer-tab', compact(
|
||||
'managements',
|
||||
'subscriptionFees',
|
||||
'partners',
|
||||
'hqStatusLabels',
|
||||
'customerStats',
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -317,6 +403,48 @@ public function paymentStats(Request $request): View|Response
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 고객사정산 통계 데이터
|
||||
*/
|
||||
private function getCustomerStats(): array
|
||||
{
|
||||
$baseQuery = SalesTenantManagement::where('hq_status', '!=', SalesTenantManagement::HQ_STATUS_PENDING);
|
||||
|
||||
// 총 개발비
|
||||
$totalFee = (clone $baseQuery)->sum('total_registration_fee');
|
||||
$totalCount = (clone $baseQuery)->count();
|
||||
|
||||
// 수금완료 (deposit + balance 모두 paid인 건의 합계)
|
||||
$collectedAmount = (clone $baseQuery)
|
||||
->where('deposit_status', 'paid')
|
||||
->sum('deposit_amount')
|
||||
+ (clone $baseQuery)
|
||||
->where('balance_status', 'paid')
|
||||
->sum('balance_amount');
|
||||
|
||||
// 미수금
|
||||
$uncollectedAmount = $totalFee - $collectedAmount;
|
||||
|
||||
// 개발 진행 중 (handover 제외)
|
||||
$inProgressCount = (clone $baseQuery)
|
||||
->where('hq_status', '!=', SalesTenantManagement::HQ_STATUS_HANDOVER)
|
||||
->count();
|
||||
|
||||
// 구독 전환 (handover + tenant active)
|
||||
$subscriptionCount = SalesTenantManagement::where('hq_status', SalesTenantManagement::HQ_STATUS_HANDOVER)
|
||||
->whereHas('tenant', fn ($q) => $q->whereNull('deleted_at'))
|
||||
->count();
|
||||
|
||||
return [
|
||||
'total_fee' => $totalFee,
|
||||
'total_count' => $totalCount,
|
||||
'collected_amount' => $collectedAmount,
|
||||
'uncollected_amount' => max(0, $uncollectedAmount),
|
||||
'in_progress_count' => $inProgressCount,
|
||||
'subscription_count' => $subscriptionCount,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 통합 통계 데이터
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user