241 lines
14 KiB
PHP
241 lines
14 KiB
PHP
{{-- 고객사정산 탭 (실 테넌트 데이터 기반) --}}
|
|
<div class="space-y-6">
|
|
{{-- 통계 카드 --}}
|
|
<div class="grid grid-cols-1 md:grid-cols-5 gap-4">
|
|
<div class="bg-white rounded-lg shadow-sm p-4 border-l-4 border-indigo-500">
|
|
<p class="text-sm text-gray-500">총 개발비</p>
|
|
<p class="text-xl font-bold text-indigo-600">{{ number_format($customerStats['total_fee']) }}원</p>
|
|
<p class="text-xs text-gray-400 mt-1">{{ $customerStats['total_count'] }}건</p>
|
|
</div>
|
|
<div class="bg-white rounded-lg shadow-sm p-4 border-l-4 border-green-500">
|
|
<p class="text-sm text-gray-500">수금완료</p>
|
|
<p class="text-xl font-bold text-green-600">{{ number_format($customerStats['collected_amount']) }}원</p>
|
|
</div>
|
|
<div class="bg-white rounded-lg shadow-sm p-4 border-l-4 border-red-500">
|
|
<p class="text-sm text-gray-500">미수금</p>
|
|
<p class="text-xl font-bold text-red-600">{{ number_format($customerStats['uncollected_amount']) }}원</p>
|
|
</div>
|
|
<div class="bg-white rounded-lg shadow-sm p-4 border-l-4 border-blue-500">
|
|
<p class="text-sm text-gray-500">개발 진행 중</p>
|
|
<p class="text-xl font-bold text-blue-600">{{ $customerStats['in_progress_count'] }}건</p>
|
|
</div>
|
|
<div class="bg-white rounded-lg shadow-sm p-4 border-l-4 border-emerald-500">
|
|
<p class="text-sm text-gray-500">구독 전환</p>
|
|
<p class="text-xl font-bold text-emerald-600">{{ $customerStats['subscription_count'] }}건</p>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- 필터 --}}
|
|
<div class="bg-white rounded-lg shadow-sm p-4">
|
|
<form hx-get="{{ route('finance.settlement.customer') }}"
|
|
hx-target="#customer-content"
|
|
hx-trigger="submit"
|
|
class="flex flex-wrap items-end gap-3">
|
|
<div class="w-[calc(50%-6px)] sm:w-auto sm:min-w-[160px]">
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">검색</label>
|
|
<input type="text" name="search" placeholder="고객사명"
|
|
value="{{ request('search') }}"
|
|
class="w-full rounded-lg border-gray-300 text-sm focus:border-indigo-500 focus:ring-indigo-500">
|
|
</div>
|
|
<div class="w-[calc(50%-6px)] sm:w-auto sm:min-w-[120px]">
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">개발 상태</label>
|
|
<select name="hq_status" class="w-full rounded-lg border-gray-300 text-sm focus:border-indigo-500 focus:ring-indigo-500">
|
|
<option value="">전체</option>
|
|
@foreach ($hqStatusLabels as $value => $label)
|
|
<option value="{{ $value }}" {{ request('hq_status') == $value ? 'selected' : '' }}>{{ $label }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
<div class="w-[calc(50%-6px)] sm:w-auto sm:min-w-[120px]">
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">수금 상태</label>
|
|
<select name="payment_status" class="w-full rounded-lg border-gray-300 text-sm focus:border-indigo-500 focus:ring-indigo-500">
|
|
<option value="">전체</option>
|
|
<option value="fully_paid" {{ request('payment_status') == 'fully_paid' ? 'selected' : '' }}>수금완료</option>
|
|
<option value="partial" {{ request('payment_status') == 'partial' ? 'selected' : '' }}>부분수금</option>
|
|
<option value="unpaid" {{ request('payment_status') == 'unpaid' ? 'selected' : '' }}>미수금</option>
|
|
</select>
|
|
</div>
|
|
<div class="w-[calc(50%-6px)] sm:w-auto sm:min-w-[120px]">
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">담당 파트너</label>
|
|
<select name="partner_id" class="w-full rounded-lg border-gray-300 text-sm focus:border-indigo-500 focus:ring-indigo-500">
|
|
<option value="">전체</option>
|
|
@foreach ($partners as $partner)
|
|
<option value="{{ $partner->id }}" {{ request('partner_id') == $partner->id ? 'selected' : '' }}>
|
|
{{ $partner->user?->name ?? $partner->partner_code }}
|
|
</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
<div class="flex items-end gap-1 w-full sm:w-auto">
|
|
<button type="submit" class="flex-1 sm:flex-none px-4 py-2 bg-indigo-600 hover:bg-indigo-700 text-white text-sm rounded-lg transition-colors">
|
|
조회
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
{{-- 테이블 --}}
|
|
<div class="bg-white rounded-lg shadow-sm overflow-hidden">
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full divide-y divide-gray-200">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">고객사</th>
|
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">담당파트너</th>
|
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">담당매니저</th>
|
|
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">개발비 총액</th>
|
|
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">1차(계약금)</th>
|
|
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">2차(잔금)</th>
|
|
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">구독료</th>
|
|
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">개발상태</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="bg-white divide-y divide-gray-200">
|
|
@forelse ($managements as $mgmt)
|
|
@php
|
|
$companyName = $mgmt->tenant?->company_name ?? $mgmt->tenantProspect?->company_name ?? '-';
|
|
$tenantActive = $mgmt->tenant && !$mgmt->tenant->trashed();
|
|
|
|
// 개발비 총액 (management 직접 값 → contractProducts 합산)
|
|
$totalFee = $mgmt->total_registration_fee > 0
|
|
? $mgmt->total_registration_fee
|
|
: ($mgmt->contractProducts?->sum('registration_fee') ?? 0);
|
|
|
|
// 계약금/잔금 기본값 (총개발비의 50%)
|
|
$calcBase = $totalFee / 2;
|
|
|
|
// 계약금
|
|
$depositAmount = $mgmt->deposit_amount > 0
|
|
? $mgmt->deposit_amount
|
|
: ($totalFee > 0 ? $calcBase : 0);
|
|
|
|
// 잔금
|
|
$balanceAmount = $mgmt->balance_amount > 0
|
|
? $mgmt->balance_amount
|
|
: ($totalFee > 0 ? $calcBase : 0);
|
|
|
|
// 구독료 (tenant 기반 조회 → contractProducts fallback)
|
|
$monthlyFee = $subscriptionFees[$mgmt->tenant_id] ?? 0;
|
|
if ($monthlyFee <= 0) {
|
|
$monthlyFee = $mgmt->contractProducts?->sum('subscription_fee') ?? 0;
|
|
}
|
|
|
|
// 담당파트너 (salesPartner → tenantProspect.registeredBy)
|
|
$partnerName = $mgmt->salesPartner?->user?->name
|
|
?? $mgmt->tenantProspect?->registeredBy?->name
|
|
?? '-';
|
|
|
|
// 담당매니저
|
|
$managerName = $mgmt->manager?->name ?? '-';
|
|
|
|
$firstSubscriptionAt = $mgmt->commissions->first()?->first_subscription_at;
|
|
@endphp
|
|
<tr class="hover:bg-gray-50">
|
|
{{-- 고객사 --}}
|
|
<td class="px-4 py-3">
|
|
<div class="text-sm font-medium text-gray-900">{{ $companyName }}</div>
|
|
</td>
|
|
|
|
{{-- 담당파트너 --}}
|
|
<td class="px-4 py-3 text-sm text-gray-900">
|
|
{{ $partnerName }}
|
|
</td>
|
|
|
|
{{-- 담당매니저 --}}
|
|
<td class="px-4 py-3 text-sm text-gray-900">
|
|
{{ $managerName }}
|
|
</td>
|
|
|
|
{{-- 개발비 총액 --}}
|
|
<td class="px-4 py-3 text-sm text-right font-medium text-gray-900">
|
|
@if ($totalFee > 0)
|
|
{{ number_format($totalFee) }}원
|
|
@else
|
|
<span class="text-gray-400">-</span>
|
|
@endif
|
|
</td>
|
|
|
|
{{-- 1차(계약금) --}}
|
|
<td class="px-4 py-3 text-sm text-right">
|
|
@if ($depositAmount > 0)
|
|
<div class="font-medium text-gray-900">{{ number_format($depositAmount) }}원</div>
|
|
@if ($mgmt->deposit_status === 'paid')
|
|
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-green-100 text-green-700">완료</span>
|
|
@else
|
|
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-yellow-100 text-yellow-700">대기</span>
|
|
@endif
|
|
@if ($mgmt->deposit_paid_date)
|
|
<div class="text-xs text-gray-400 mt-0.5">{{ $mgmt->deposit_paid_date->format('Y-m-d') }}</div>
|
|
@endif
|
|
@else
|
|
<span class="text-gray-400">-</span>
|
|
@endif
|
|
</td>
|
|
|
|
{{-- 2차(잔금) --}}
|
|
<td class="px-4 py-3 text-sm text-right">
|
|
@if ($balanceAmount > 0)
|
|
<div class="font-medium text-gray-900">{{ number_format($balanceAmount) }}원</div>
|
|
@if ($mgmt->balance_status === 'paid')
|
|
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-green-100 text-green-700">완료</span>
|
|
@else
|
|
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-yellow-100 text-yellow-700">대기</span>
|
|
@endif
|
|
@if ($mgmt->balance_paid_date)
|
|
<div class="text-xs text-gray-400 mt-0.5">{{ $mgmt->balance_paid_date->format('Y-m-d') }}</div>
|
|
@endif
|
|
@else
|
|
<span class="text-gray-400">-</span>
|
|
@endif
|
|
</td>
|
|
|
|
{{-- 구독료 --}}
|
|
<td class="px-4 py-3 text-sm text-right">
|
|
@if ($monthlyFee > 0)
|
|
<div class="font-medium text-gray-900">월 {{ number_format($monthlyFee) }}원</div>
|
|
@if ($firstSubscriptionAt)
|
|
<div class="text-xs text-gray-400 mt-0.5">첫입금 {{ \Carbon\Carbon::parse($firstSubscriptionAt)->format('Y-m-d') }}</div>
|
|
@endif
|
|
@else
|
|
<span class="text-gray-400">-</span>
|
|
@endif
|
|
</td>
|
|
|
|
{{-- 개발상태 --}}
|
|
<td class="px-4 py-3 text-center">
|
|
@php
|
|
$statusColor = match ($mgmt->hq_status) {
|
|
'review' => 'bg-purple-100 text-purple-700',
|
|
'planning' => 'bg-blue-100 text-blue-700',
|
|
'coding' => 'bg-indigo-100 text-indigo-700',
|
|
'dev_test' => 'bg-cyan-100 text-cyan-700',
|
|
'dev_done' => 'bg-teal-100 text-teal-700',
|
|
'int_test' => 'bg-amber-100 text-amber-700',
|
|
'handover' => 'bg-green-100 text-green-700',
|
|
default => 'bg-gray-100 text-gray-700',
|
|
};
|
|
@endphp
|
|
<span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium {{ $statusColor }}">
|
|
{{ $mgmt->hq_status_label }}
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
@empty
|
|
<tr>
|
|
<td colspan="8" class="px-4 py-8 text-center text-gray-500">
|
|
개발이 시작된 고객사가 없습니다.
|
|
</td>
|
|
</tr>
|
|
@endforelse
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
@if ($managements->hasPages())
|
|
<div class="px-4 py-3 border-t border-gray-200">
|
|
{{ $managements->links() }}
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|