Files
sam-manage/resources/views/barobill/billing/partials/subscription-table.blade.php
pro 39161d1203 feat:바로빌 과금관리 시스템 구현
- 모델: BarobillSubscription, BarobillBillingRecord, BarobillMonthlySummary
- 서비스: BarobillBillingService (구독/과금 처리 로직)
- API 컨트롤러: BarobillBillingController (구독/과금 CRUD)
- 뷰: 과금 현황 탭, 구독 관리 탭, 통계 카드, 상세 모달
- 라우트: 웹/API 라우트 추가

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-27 15:03:44 +09:00

138 lines
7.7 KiB
PHP

@if($subscriptions->isEmpty())
<div class="p-12 text-center">
<svg class="mx-auto h-12 w-12 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<h3 class="mt-2 text-sm font-medium text-gray-900">등록된 구독이 없습니다</h3>
<p class="mt-1 text-sm text-gray-500">회원사에 월정액 서비스 구독을 등록해주세요.</p>
</div>
@else
<div class="flex-1 overflow-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50 sticky top-0 z-10">
<tr>
@if($allTenants ?? false)
<th scope="col" class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider w-16">
T-ID
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
테넌트
</th>
@endif
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
회원사
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
서비스
</th>
<th scope="col" class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">
월정액
</th>
<th scope="col" class="px-6 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">
시작일
</th>
<th scope="col" class="px-6 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">
종료일
</th>
<th scope="col" class="px-6 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">
상태
</th>
<th scope="col" class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider w-20">
관리
</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
@foreach($subscriptions as $subscription)
<tr class="hover:bg-gray-50 transition-colors group">
@if($allTenants ?? false)
<td class="px-4 py-4 whitespace-nowrap text-center">
<span class="inline-flex items-center justify-center w-8 h-8 rounded-full text-xs font-bold bg-indigo-100 text-indigo-700">
{{ $subscription->member->tenant_id ?? '-' }}
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-indigo-100 text-indigo-800">
{{ $subscription->member->tenant->company_name ?? '-' }}
</span>
</td>
@endif
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm font-medium text-gray-900">{{ $subscription->member->corp_name ?? '-' }}</div>
<div class="text-xs text-gray-400">{{ $subscription->member->formatted_biz_no ?? '' }}</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
@php
$serviceColors = [
'bank_account' => 'bg-green-100 text-green-800',
'card' => 'bg-blue-100 text-blue-800',
'hometax' => 'bg-orange-100 text-orange-800',
];
@endphp
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium {{ $serviceColors[$subscription->service_type] ?? 'bg-gray-100 text-gray-800' }}">
{{ $subscription->service_type_label }}
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-right">
<span class="text-sm font-medium text-gray-900">{{ number_format($subscription->monthly_fee) }}</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-center">
<span class="text-sm text-gray-600">{{ $subscription->started_at?->format('Y-m-d') ?? '-' }}</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-center">
<span class="text-sm text-gray-600">{{ $subscription->ended_at?->format('Y-m-d') ?? '-' }}</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-center">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full {{ $subscription->status_color }}">
{{ $subscription->status_label }}
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-right">
<div class="flex justify-end gap-1 opacity-30 group-hover:opacity-100 transition-opacity">
@if($subscription->is_active && !$subscription->ended_at)
<button
type="button"
onclick="cancelSubscription({{ $subscription->id }}, '{{ addslashes($subscription->member->corp_name ?? '') }}', '{{ $subscription->service_type_label }}')"
class="p-2 text-red-600 hover:bg-red-50 rounded-lg"
title="구독 해지"
>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
@endif
</div>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endif
<script>
async function cancelSubscription(id, memberName, serviceName) {
if (!confirm(`${memberName}의 ${serviceName} 구독을 해지하시겠습니까?`)) return;
try {
const res = await fetch(`/api/admin/barobill/billing/subscriptions/${id}`, {
method: 'DELETE',
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
},
});
const result = await res.json();
if (result.success) {
showToast(result.message, 'success');
htmx.trigger(document.body, 'subscriptionUpdated');
} else {
showToast(result.message || '처리 실패', 'error');
}
} catch (error) {
showToast('오류가 발생했습니다.', 'error');
}
}
</script>