Files
sam-manage/app/Http/Controllers/Api/Admin/Barobill/BarobillMemberController.php
pro f60f84670a feat: 바로빌 회원사관리 CRUD 기능 구현
레거시(sam/sales/barobill/registration)를 Laravel 스타일로 마이그레이션

- Migration: barobill_members 테이블 생성
- Model: BarobillMember (상태 라벨, 사업자번호 포맷팅 등)
- API Controller: CRUD + 통계 조회 (HTMX HTML 반환 지원)
- API Routes: /api/admin/barobill/members/*
- Views:
  - index.blade.php (통계 카드, 필터, 테이블, 모달)
  - partials/table.blade.php (HTMX 테이블)
  - partials/stats.blade.php (통계 카드)
  - partials/modal-form.blade.php (등록/수정 폼, 자동완성)

기능:
- 회원사 목록 조회 (검색, 상태 필터)
- 회원사 등록 (사업자번호 중복 체크)
- 회원사 수정 (모달)
- 회원사 삭제 (확인 후)
- 테스트 데이터 자동완성

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 08:49:25 +09:00

231 lines
7.4 KiB
PHP

<?php
namespace App\Http\Controllers\Api\Admin\Barobill;
use App\Http\Controllers\Controller;
use App\Models\Barobill\BarobillMember;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rule;
class BarobillMemberController extends Controller
{
/**
* 회원사 목록 조회
*/
public function index(Request $request): JsonResponse|Response
{
$tenantId = session('selected_tenant_id');
$query = BarobillMember::query()
->when($tenantId, fn($q) => $q->where('tenant_id', $tenantId))
->when($request->search, function ($q, $search) {
$q->where(function ($q) use ($search) {
$q->where('corp_name', 'like', "%{$search}%")
->orWhere('biz_no', 'like', "%{$search}%")
->orWhere('barobill_id', 'like', "%{$search}%")
->orWhere('manager_name', 'like', "%{$search}%");
});
})
->when($request->status, fn($q, $status) => $q->where('status', $status))
->with('tenant:id,company_name')
->orderBy('created_at', 'desc');
$members = $query->paginate($request->integer('per_page', 15));
// HTMX 요청 시 HTML 반환
if ($request->header('HX-Request')) {
return response(
view('barobill.members.partials.table', compact('members'))->render(),
200,
['Content-Type' => 'text/html']
);
}
return response()->json([
'success' => true,
'data' => $members->items(),
'meta' => [
'current_page' => $members->currentPage(),
'last_page' => $members->lastPage(),
'per_page' => $members->perPage(),
'total' => $members->total(),
],
]);
}
/**
* 회원사 등록
*/
public function store(Request $request): JsonResponse
{
$tenantId = session('selected_tenant_id');
if (!$tenantId) {
return response()->json([
'success' => false,
'message' => '테넌트를 선택해주세요.',
], 400);
}
$validated = $request->validate([
'biz_no' => [
'required',
'string',
'max:20',
Rule::unique('barobill_members')->where(function ($query) use ($tenantId) {
return $query->where('tenant_id', $tenantId);
}),
],
'corp_name' => 'required|string|max:100',
'ceo_name' => 'required|string|max:50',
'addr' => 'nullable|string|max:255',
'biz_type' => 'nullable|string|max:50',
'biz_class' => 'nullable|string|max:50',
'barobill_id' => 'required|string|max:50',
'barobill_pwd' => 'required|string|max:255',
'manager_name' => 'nullable|string|max:50',
'manager_email' => 'nullable|email|max:100',
'manager_hp' => 'nullable|string|max:20',
'status' => 'nullable|in:active,inactive,pending',
], [
'biz_no.required' => '사업자번호를 입력해주세요.',
'biz_no.unique' => '이미 등록된 사업자번호입니다.',
'corp_name.required' => '상호명을 입력해주세요.',
'ceo_name.required' => '대표자명을 입력해주세요.',
'barobill_id.required' => '바로빌 아이디를 입력해주세요.',
'barobill_pwd.required' => '비밀번호를 입력해주세요.',
]);
$validated['tenant_id'] = $tenantId;
$validated['barobill_pwd'] = Hash::make($validated['barobill_pwd']);
$validated['status'] = $validated['status'] ?? 'active';
$member = BarobillMember::create($validated);
return response()->json([
'success' => true,
'message' => '회원사가 등록되었습니다.',
'data' => $member,
], 201);
}
/**
* 회원사 상세 조회
*/
public function show(Request $request, int $id): JsonResponse
{
$member = BarobillMember::with('tenant:id,company_name')->find($id);
if (!$member) {
return response()->json([
'success' => false,
'message' => '회원사를 찾을 수 없습니다.',
], 404);
}
// HTMX 요청 시 HTML 반환
if ($request->header('HX-Request')) {
return response()->json([
'html' => view('barobill.members.partials.detail', compact('member'))->render(),
]);
}
return response()->json([
'success' => true,
'data' => $member,
]);
}
/**
* 회원사 수정
*/
public function update(Request $request, int $id): JsonResponse
{
$member = BarobillMember::find($id);
if (!$member) {
return response()->json([
'success' => false,
'message' => '회원사를 찾을 수 없습니다.',
], 404);
}
$validated = $request->validate([
'corp_name' => 'required|string|max:100',
'ceo_name' => 'required|string|max:50',
'addr' => 'nullable|string|max:255',
'biz_type' => 'nullable|string|max:50',
'biz_class' => 'nullable|string|max:50',
'manager_name' => 'nullable|string|max:50',
'manager_email' => 'nullable|email|max:100',
'manager_hp' => 'nullable|string|max:20',
'status' => 'nullable|in:active,inactive,pending',
]);
$member->update($validated);
return response()->json([
'success' => true,
'message' => '회원사 정보가 수정되었습니다.',
'data' => $member->fresh(),
]);
}
/**
* 회원사 삭제
*/
public function destroy(int $id): JsonResponse
{
$member = BarobillMember::find($id);
if (!$member) {
return response()->json([
'success' => false,
'message' => '회원사를 찾을 수 없습니다.',
], 404);
}
$member->delete();
return response()->json([
'success' => true,
'message' => '회원사가 삭제되었습니다.',
]);
}
/**
* 통계 조회
*/
public function stats(Request $request): JsonResponse|Response
{
$tenantId = session('selected_tenant_id');
$query = BarobillMember::query()
->when($tenantId, fn($q) => $q->where('tenant_id', $tenantId));
$stats = [
'total' => (clone $query)->count(),
'active' => (clone $query)->where('status', 'active')->count(),
'inactive' => (clone $query)->where('status', 'inactive')->count(),
'pending' => (clone $query)->where('status', 'pending')->count(),
];
// HTMX 요청 시 HTML 반환
if ($request->header('HX-Request')) {
return response(
view('barobill.members.partials.stats', compact('stats'))->render(),
200,
['Content-Type' => 'text/html']
);
}
return response()->json([
'success' => true,
'data' => $stats,
]);
}
}