Files
sam-manage/app/Http/Controllers/Sales/SalesProspectController.php
2026-02-25 11:45:01 +09:00

259 lines
8.8 KiB
PHP

<?php
namespace App\Http\Controllers\Sales;
use App\Http\Controllers\Controller;
use App\Models\Sales\SalesManager;
use App\Models\Sales\SalesProspect;
use App\Models\Sales\SalesProspectProduct;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;
use Illuminate\View\View;
/**
* 가망고객 관리 컨트롤러
*/
class SalesProspectController extends Controller
{
/**
* 목록 페이지
*/
public function index(Request $request): View|Response
{
if ($request->header('HX-Request')) {
return response('', 200)->header('HX-Redirect', route('sales.prospects.index'));
}
$query = SalesProspect::with(['manager', 'salesManager', 'products']);
// 검색
if ($search = $request->get('search')) {
$query->where(function ($q) use ($search) {
$q->where('company_name', 'like', "%{$search}%")
->orWhere('business_no', 'like', "%{$search}%")
->orWhere('representative', 'like', "%{$search}%")
->orWhere('contact_phone', 'like', "%{$search}%");
});
}
// 상태 필터
if ($status = $request->get('status')) {
$query->where('status', $status);
}
// 담당자 필터
if ($managerId = $request->get('manager_id')) {
$query->where(function ($q) use ($managerId) {
$q->where('manager_id', $managerId)
->orWhere('sales_manager_id', $managerId);
});
}
$prospects = $query->orderByDesc('created_at')->paginate(20);
// 통계
$stats = [
'total' => SalesProspect::count(),
'lead' => SalesProspect::where('status', 'lead')->count(),
'prospect' => SalesProspect::where('status', 'prospect')->count(),
'negotiation' => SalesProspect::where('status', 'negotiation')->count(),
'contracted' => SalesProspect::where('status', 'contracted')->count(),
'total_contract' => SalesProspectProduct::sum('contract_amount'),
'total_commission' => SalesProspectProduct::sum('commission_amount'),
];
$managers = SalesManager::active()->orderBy('name')->get();
return view('sales.prospects.index', compact('prospects', 'stats', 'managers'));
}
/**
* 등록 폼
*/
public function create(): View
{
$managers = SalesManager::active()->orderBy('name')->get();
return view('sales.prospects.create', compact('managers'));
}
/**
* 등록 처리
*/
public function store(Request $request)
{
$validated = $request->validate([
'manager_id' => 'required|exists:sales_managers,id',
'sales_manager_id' => 'nullable|exists:sales_managers,id',
'company_name' => 'required|string|max:200',
'representative' => 'nullable|string|max:100',
'business_no' => 'nullable|string|max:20',
'contact_phone' => 'nullable|string|max:20',
'email' => 'nullable|email|max:100',
'address' => 'nullable|string|max:500',
'status' => 'required|in:lead,prospect,negotiation,contracted,lost',
'business_card_image_data' => 'nullable|string',
'id_card_image_data' => 'nullable|string',
'bankbook_image_data' => 'nullable|string',
]);
// 명함 이미지 저장 (Base64)
if (! empty($validated['business_card_image_data'])) {
$validated['business_card_image'] = $this->saveBase64Image($validated['business_card_image_data'], 'business-cards');
}
unset($validated['business_card_image_data']);
// 신분증 이미지 저장 (Base64)
if (! empty($validated['id_card_image_data'])) {
$validated['id_card_image'] = $this->saveBase64Image($validated['id_card_image_data'], 'id-cards');
}
unset($validated['id_card_image_data']);
// 통장사본 이미지 저장 (Base64)
if (! empty($validated['bankbook_image_data'])) {
$validated['bankbook_image'] = $this->saveBase64Image($validated['bankbook_image_data'], 'bankbooks');
}
unset($validated['bankbook_image_data']);
$prospect = SalesProspect::create($validated);
return redirect()->route('sales.prospects.show', $prospect->id)
->with('success', '가망고객이 등록되었습니다.');
}
/**
* 상세 페이지
*/
public function show(int $id): View
{
$prospect = SalesProspect::with([
'manager',
'salesManager',
'products',
'scenarios',
'consultations.manager',
])->findOrFail($id);
$managers = SalesManager::active()
->whereIn('role', ['sales_admin', 'manager'])
->orderBy('name')
->get();
return view('sales.prospects.show', compact('prospect', 'managers'));
}
/**
* 수정 폼
*/
public function edit(int $id): View
{
$prospect = SalesProspect::findOrFail($id);
$managers = SalesManager::active()->orderBy('name')->get();
return view('sales.prospects.edit', compact('prospect', 'managers'));
}
/**
* 수정 처리
*/
public function update(Request $request, int $id)
{
$prospect = SalesProspect::findOrFail($id);
$validated = $request->validate([
'sales_manager_id' => 'nullable|exists:sales_managers,id',
'company_name' => 'required|string|max:200',
'representative' => 'nullable|string|max:100',
'business_no' => 'nullable|string|max:20',
'contact_phone' => 'nullable|string|max:20',
'email' => 'nullable|email|max:100',
'address' => 'nullable|string|max:500',
'status' => 'required|in:lead,prospect,negotiation,contracted,lost',
'business_card' => 'nullable|image|max:5120',
'id_card' => 'nullable|image|max:5120',
'bankbook' => 'nullable|image|max:5120',
]);
// 명함 이미지 업로드 처리
if ($request->hasFile('business_card')) {
if ($prospect->business_card_image) {
Storage::disk('public')->delete($prospect->business_card_image);
}
$validated['business_card_image'] = $request->file('business_card')
->store('business-cards', 'public');
}
unset($validated['business_card']);
// 신분증 이미지 업로드 처리
if ($request->hasFile('id_card')) {
if ($prospect->id_card_image) {
Storage::disk('public')->delete($prospect->id_card_image);
}
$validated['id_card_image'] = $request->file('id_card')
->store('id-cards', 'public');
}
unset($validated['id_card']);
// 통장사본 이미지 업로드 처리
if ($request->hasFile('bankbook')) {
if ($prospect->bankbook_image) {
Storage::disk('public')->delete($prospect->bankbook_image);
}
$validated['bankbook_image'] = $request->file('bankbook')
->store('bankbooks', 'public');
}
unset($validated['bankbook']);
$prospect->update($validated);
return redirect()->route('sales.prospects.show', $prospect->id)
->with('success', '가망고객 정보가 수정되었습니다.');
}
/**
* 삭제 처리
*/
public function destroy(int $id)
{
$prospect = SalesProspect::findOrFail($id);
// 첨부 이미지 삭제
$imageFields = ['business_card_image', 'id_card_image', 'bankbook_image'];
foreach ($imageFields as $field) {
if ($prospect->$field) {
Storage::disk('public')->delete($prospect->$field);
}
}
$prospect->delete();
return redirect()->route('sales.prospects.index')
->with('success', '가망고객이 삭제되었습니다.');
}
/**
* Base64 이미지 저장
*/
private function saveBase64Image(string $base64Data, string $folder): ?string
{
// data:image/jpeg;base64,... 형식에서 데이터 추출
if (preg_match('/^data:image\/(\w+);base64,/', $base64Data, $matches)) {
$extension = $matches[1];
$base64Data = preg_replace('/^data:image\/\w+;base64,/', '', $base64Data);
} else {
$extension = 'jpg';
}
$imageData = base64_decode($base64Data);
if ($imageData === false) {
return null;
}
$filename = $folder.'/'.date('Ymd').'_'.uniqid().'.'.$extension;
Storage::disk('public')->put($filename, $imageData);
return $filename;
}
}