feat:바로빌 카카오톡(알림톡/친구톡) 서비스 구현
- BarobillService에 KAKAOTALK SOAP 클라이언트 추가 - 채널/템플릿 관리, 알림톡/친구톡 발송, 전송조회/예약취소 API - BarobillKakaotalkController (API) 생성: 15개 엔드포인트 - KakaotalkController (페이지) 생성: 5개 페이지 - 라우트 등록 (web.php, api.php) - Blade 뷰 5개 생성: 대시보드, 채널관리, 템플릿관리, 발송, 전송내역 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,435 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin\Barobill;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Barobill\BarobillMember;
|
||||
use App\Services\Barobill\BarobillService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class BarobillKakaotalkController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
protected BarobillService $barobillService
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 회원사 조회 및 서버 모드 전환 헬퍼
|
||||
*/
|
||||
private function resolveMember(): BarobillMember|JsonResponse
|
||||
{
|
||||
$tenantId = session('selected_tenant_id', 1);
|
||||
$member = BarobillMember::where('tenant_id', $tenantId)->first();
|
||||
|
||||
if (!$member) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => '바로빌 회원사가 등록되어 있지 않습니다.',
|
||||
], 404);
|
||||
}
|
||||
|
||||
$this->barobillService->setServerMode($member->server_mode ?? 'test');
|
||||
|
||||
return $member;
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 채널 관리
|
||||
// ==========================================
|
||||
|
||||
/**
|
||||
* 카카오톡 채널 목록 조회
|
||||
*/
|
||||
public function getChannels(): JsonResponse
|
||||
{
|
||||
$member = $this->resolveMember();
|
||||
if ($member instanceof JsonResponse) return $member;
|
||||
|
||||
$result = $this->barobillService->getKakaotalkChannels($member->biz_no);
|
||||
|
||||
if (!$result['success']) {
|
||||
return response()->json($result, 422);
|
||||
}
|
||||
|
||||
return response()->json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 카카오톡 채널 관리 URL 조회
|
||||
*/
|
||||
public function getChannelManagementUrl(): JsonResponse
|
||||
{
|
||||
$member = $this->resolveMember();
|
||||
if ($member instanceof JsonResponse) return $member;
|
||||
|
||||
$result = $this->barobillService->getKakaotalkChannelManagementUrl(
|
||||
$member->biz_no,
|
||||
$member->barobill_id
|
||||
);
|
||||
|
||||
if (!$result['success']) {
|
||||
return response()->json($result, 422);
|
||||
}
|
||||
|
||||
return response()->json($result);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 템플릿 관리
|
||||
// ==========================================
|
||||
|
||||
/**
|
||||
* 카카오톡 템플릿 목록 조회
|
||||
*/
|
||||
public function getTemplates(Request $request): JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
'channel_id' => 'required|string',
|
||||
]);
|
||||
|
||||
$member = $this->resolveMember();
|
||||
if ($member instanceof JsonResponse) return $member;
|
||||
|
||||
$result = $this->barobillService->getKakaotalkTemplates(
|
||||
$member->biz_no,
|
||||
$request->input('channel_id')
|
||||
);
|
||||
|
||||
if (!$result['success']) {
|
||||
return response()->json($result, 422);
|
||||
}
|
||||
|
||||
return response()->json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 카카오톡 템플릿 관리 URL 조회
|
||||
*/
|
||||
public function getTemplateManagementUrl(): JsonResponse
|
||||
{
|
||||
$member = $this->resolveMember();
|
||||
if ($member instanceof JsonResponse) return $member;
|
||||
|
||||
$result = $this->barobillService->getKakaotalkTemplateManagementUrl(
|
||||
$member->biz_no,
|
||||
$member->barobill_id
|
||||
);
|
||||
|
||||
if (!$result['success']) {
|
||||
return response()->json($result, 422);
|
||||
}
|
||||
|
||||
return response()->json($result);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 알림톡 발송
|
||||
// ==========================================
|
||||
|
||||
/**
|
||||
* 알림톡 단건 발송
|
||||
*/
|
||||
public function sendAlimtalk(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'sender_id' => 'required|string',
|
||||
'template_name' => 'required|string',
|
||||
'receiver_name' => 'required|string',
|
||||
'receiver_num' => 'required|string',
|
||||
'title' => 'nullable|string',
|
||||
'message' => 'required|string',
|
||||
'buttons' => 'nullable|array',
|
||||
'buttons.*.Name' => 'required_with:buttons|string',
|
||||
'buttons.*.ButtonType' => 'required_with:buttons|string',
|
||||
'buttons.*.Url1' => 'nullable|string',
|
||||
'buttons.*.Url2' => 'nullable|string',
|
||||
'sms_message' => 'nullable|string',
|
||||
'sms_subject' => 'nullable|string',
|
||||
'reserve_dt' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$member = $this->resolveMember();
|
||||
if ($member instanceof JsonResponse) return $member;
|
||||
|
||||
$buttons = $validated['buttons'] ?? [];
|
||||
|
||||
// 버튼이 있으면 Ex 버전 사용
|
||||
if (!empty($buttons)) {
|
||||
$result = $this->barobillService->sendATKakaotalkEx(
|
||||
$member->biz_no,
|
||||
$validated['sender_id'],
|
||||
$validated['template_name'],
|
||||
$validated['receiver_name'],
|
||||
$validated['receiver_num'],
|
||||
$validated['title'] ?? '',
|
||||
$validated['message'],
|
||||
$buttons,
|
||||
$validated['sms_message'] ?? '',
|
||||
$validated['sms_subject'] ?? '',
|
||||
$validated['reserve_dt'] ?? ''
|
||||
);
|
||||
} else {
|
||||
$result = $this->barobillService->sendATKakaotalk(
|
||||
$member->biz_no,
|
||||
$validated['sender_id'],
|
||||
$validated['template_name'],
|
||||
$validated['receiver_name'],
|
||||
$validated['receiver_num'],
|
||||
$validated['title'] ?? '',
|
||||
$validated['message'],
|
||||
$validated['sms_message'] ?? '',
|
||||
$validated['sms_subject'] ?? '',
|
||||
$validated['reserve_dt'] ?? ''
|
||||
);
|
||||
}
|
||||
|
||||
if (!$result['success']) {
|
||||
return response()->json($result, 422);
|
||||
}
|
||||
|
||||
return response()->json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 알림톡 대량 발송
|
||||
*/
|
||||
public function sendAlimtalkBulk(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'sender_id' => 'required|string',
|
||||
'template_name' => 'required|string',
|
||||
'messages' => 'required|array|min:1',
|
||||
'messages.*.ReceiverName' => 'required|string',
|
||||
'messages.*.ReceiverNum' => 'required|string',
|
||||
'messages.*.Title' => 'nullable|string',
|
||||
'messages.*.Message' => 'required|string',
|
||||
'messages.*.SmsMessage' => 'nullable|string',
|
||||
'messages.*.SmsSubject' => 'nullable|string',
|
||||
'reserve_dt' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$member = $this->resolveMember();
|
||||
if ($member instanceof JsonResponse) return $member;
|
||||
|
||||
$result = $this->barobillService->sendATKakaotalks(
|
||||
$member->biz_no,
|
||||
$validated['sender_id'],
|
||||
$validated['template_name'],
|
||||
$validated['messages'],
|
||||
$validated['reserve_dt'] ?? ''
|
||||
);
|
||||
|
||||
if (!$result['success']) {
|
||||
return response()->json($result, 422);
|
||||
}
|
||||
|
||||
return response()->json($result);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 친구톡 발송
|
||||
// ==========================================
|
||||
|
||||
/**
|
||||
* 친구톡 텍스트 발송
|
||||
*/
|
||||
public function sendFriendtalk(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'sender_id' => 'required|string',
|
||||
'channel_id' => 'required|string',
|
||||
'receiver_name' => 'required|string',
|
||||
'receiver_num' => 'required|string',
|
||||
'message' => 'required|string',
|
||||
'buttons' => 'nullable|array',
|
||||
'buttons.*.Name' => 'required_with:buttons|string',
|
||||
'buttons.*.ButtonType' => 'required_with:buttons|string',
|
||||
'buttons.*.Url1' => 'nullable|string',
|
||||
'buttons.*.Url2' => 'nullable|string',
|
||||
'sms_message' => 'nullable|string',
|
||||
'sms_subject' => 'nullable|string',
|
||||
'ad_yn' => 'nullable|boolean',
|
||||
'reserve_dt' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$member = $this->resolveMember();
|
||||
if ($member instanceof JsonResponse) return $member;
|
||||
|
||||
$result = $this->barobillService->sendFTKakaotalk(
|
||||
$member->biz_no,
|
||||
$validated['sender_id'],
|
||||
$validated['channel_id'],
|
||||
$validated['receiver_name'],
|
||||
$validated['receiver_num'],
|
||||
$validated['message'],
|
||||
$validated['buttons'] ?? [],
|
||||
$validated['sms_message'] ?? '',
|
||||
$validated['sms_subject'] ?? '',
|
||||
$validated['ad_yn'] ?? false,
|
||||
$validated['reserve_dt'] ?? ''
|
||||
);
|
||||
|
||||
if (!$result['success']) {
|
||||
return response()->json($result, 422);
|
||||
}
|
||||
|
||||
return response()->json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 친구톡 이미지 발송
|
||||
*/
|
||||
public function sendFriendtalkImage(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'sender_id' => 'required|string',
|
||||
'channel_id' => 'required|string',
|
||||
'receiver_name' => 'required|string',
|
||||
'receiver_num' => 'required|string',
|
||||
'message' => 'required|string',
|
||||
'image_url' => 'required|string|url',
|
||||
'buttons' => 'nullable|array',
|
||||
'sms_message' => 'nullable|string',
|
||||
'sms_subject' => 'nullable|string',
|
||||
'ad_yn' => 'nullable|boolean',
|
||||
'reserve_dt' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$member = $this->resolveMember();
|
||||
if ($member instanceof JsonResponse) return $member;
|
||||
|
||||
$result = $this->barobillService->sendFIKakaotalk(
|
||||
$member->biz_no,
|
||||
$validated['sender_id'],
|
||||
$validated['channel_id'],
|
||||
$validated['receiver_name'],
|
||||
$validated['receiver_num'],
|
||||
$validated['message'],
|
||||
$validated['image_url'],
|
||||
$validated['buttons'] ?? [],
|
||||
$validated['sms_message'] ?? '',
|
||||
$validated['sms_subject'] ?? '',
|
||||
$validated['ad_yn'] ?? false,
|
||||
$validated['reserve_dt'] ?? ''
|
||||
);
|
||||
|
||||
if (!$result['success']) {
|
||||
return response()->json($result, 422);
|
||||
}
|
||||
|
||||
return response()->json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 친구톡 와이드 이미지 발송
|
||||
*/
|
||||
public function sendFriendtalkWide(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'sender_id' => 'required|string',
|
||||
'channel_id' => 'required|string',
|
||||
'receiver_name' => 'required|string',
|
||||
'receiver_num' => 'required|string',
|
||||
'message' => 'required|string',
|
||||
'image_url' => 'required|string|url',
|
||||
'buttons' => 'nullable|array',
|
||||
'sms_message' => 'nullable|string',
|
||||
'sms_subject' => 'nullable|string',
|
||||
'ad_yn' => 'nullable|boolean',
|
||||
'reserve_dt' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$member = $this->resolveMember();
|
||||
if ($member instanceof JsonResponse) return $member;
|
||||
|
||||
$result = $this->barobillService->sendFWKakaotalk(
|
||||
$member->biz_no,
|
||||
$validated['sender_id'],
|
||||
$validated['channel_id'],
|
||||
$validated['receiver_name'],
|
||||
$validated['receiver_num'],
|
||||
$validated['message'],
|
||||
$validated['image_url'],
|
||||
$validated['buttons'] ?? [],
|
||||
$validated['sms_message'] ?? '',
|
||||
$validated['sms_subject'] ?? '',
|
||||
$validated['ad_yn'] ?? false,
|
||||
$validated['reserve_dt'] ?? ''
|
||||
);
|
||||
|
||||
if (!$result['success']) {
|
||||
return response()->json($result, 422);
|
||||
}
|
||||
|
||||
return response()->json($result);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 전송 결과 조회
|
||||
// ==========================================
|
||||
|
||||
/**
|
||||
* 전송 결과 조회 (단건)
|
||||
*/
|
||||
public function getSendResult(string $sendKey): JsonResponse
|
||||
{
|
||||
$member = $this->resolveMember();
|
||||
if ($member instanceof JsonResponse) return $member;
|
||||
|
||||
$result = $this->barobillService->getSendKakaotalk($member->biz_no, $sendKey);
|
||||
|
||||
if (!$result['success']) {
|
||||
return response()->json($result, 422);
|
||||
}
|
||||
|
||||
return response()->json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 전송 결과 조회 (다건)
|
||||
*/
|
||||
public function getSendResults(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'send_keys' => 'required|array|min:1',
|
||||
'send_keys.*' => 'required|string',
|
||||
]);
|
||||
|
||||
$member = $this->resolveMember();
|
||||
if ($member instanceof JsonResponse) return $member;
|
||||
|
||||
$result = $this->barobillService->getSendKakaotalks(
|
||||
$member->biz_no,
|
||||
$validated['send_keys']
|
||||
);
|
||||
|
||||
if (!$result['success']) {
|
||||
return response()->json($result, 422);
|
||||
}
|
||||
|
||||
return response()->json($result);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 예약 취소
|
||||
// ==========================================
|
||||
|
||||
/**
|
||||
* 예약 전송 취소
|
||||
*/
|
||||
public function cancelReserved(string $sendKey): JsonResponse
|
||||
{
|
||||
$member = $this->resolveMember();
|
||||
if ($member instanceof JsonResponse) return $member;
|
||||
|
||||
$result = $this->barobillService->cancelReservedKakaotalk($member->biz_no, $sendKey);
|
||||
|
||||
if (!$result['success']) {
|
||||
return response()->json($result, 422);
|
||||
}
|
||||
|
||||
return response()->json($result);
|
||||
}
|
||||
}
|
||||
93
app/Http/Controllers/Barobill/KakaotalkController.php
Normal file
93
app/Http/Controllers/Barobill/KakaotalkController.php
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Barobill;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Barobill\BarobillMember;
|
||||
use App\Models\Tenants\Tenant;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class KakaotalkController extends Controller
|
||||
{
|
||||
/**
|
||||
* 카카오톡 메인 (대시보드)
|
||||
*/
|
||||
public function index(Request $request): View|Response
|
||||
{
|
||||
if ($request->header('HX-Request')) {
|
||||
return response('', 200)->header('HX-Redirect', route('barobill.kakaotalk.index'));
|
||||
}
|
||||
|
||||
$tenantId = session('selected_tenant_id', 1);
|
||||
$currentTenant = Tenant::find($tenantId);
|
||||
$barobillMember = BarobillMember::where('tenant_id', $tenantId)->first();
|
||||
|
||||
return view('barobill.kakaotalk.index', compact('currentTenant', 'barobillMember'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 채널 관리
|
||||
*/
|
||||
public function channels(Request $request): View|Response
|
||||
{
|
||||
if ($request->header('HX-Request')) {
|
||||
return response('', 200)->header('HX-Redirect', route('barobill.kakaotalk.channels'));
|
||||
}
|
||||
|
||||
$tenantId = session('selected_tenant_id', 1);
|
||||
$currentTenant = Tenant::find($tenantId);
|
||||
$barobillMember = BarobillMember::where('tenant_id', $tenantId)->first();
|
||||
|
||||
return view('barobill.kakaotalk.channels.index', compact('currentTenant', 'barobillMember'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿 관리
|
||||
*/
|
||||
public function templates(Request $request): View|Response
|
||||
{
|
||||
if ($request->header('HX-Request')) {
|
||||
return response('', 200)->header('HX-Redirect', route('barobill.kakaotalk.templates'));
|
||||
}
|
||||
|
||||
$tenantId = session('selected_tenant_id', 1);
|
||||
$currentTenant = Tenant::find($tenantId);
|
||||
$barobillMember = BarobillMember::where('tenant_id', $tenantId)->first();
|
||||
|
||||
return view('barobill.kakaotalk.templates.index', compact('currentTenant', 'barobillMember'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 발송 (알림톡/친구톡)
|
||||
*/
|
||||
public function send(Request $request): View|Response
|
||||
{
|
||||
if ($request->header('HX-Request')) {
|
||||
return response('', 200)->header('HX-Redirect', route('barobill.kakaotalk.send'));
|
||||
}
|
||||
|
||||
$tenantId = session('selected_tenant_id', 1);
|
||||
$currentTenant = Tenant::find($tenantId);
|
||||
$barobillMember = BarobillMember::where('tenant_id', $tenantId)->first();
|
||||
|
||||
return view('barobill.kakaotalk.send.index', compact('currentTenant', 'barobillMember'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 전송내역 조회
|
||||
*/
|
||||
public function history(Request $request): View|Response
|
||||
{
|
||||
if ($request->header('HX-Request')) {
|
||||
return response('', 200)->header('HX-Redirect', route('barobill.kakaotalk.history'));
|
||||
}
|
||||
|
||||
$tenantId = session('selected_tenant_id', 1);
|
||||
$currentTenant = Tenant::find($tenantId);
|
||||
$barobillMember = BarobillMember::where('tenant_id', $tenantId)->first();
|
||||
|
||||
return view('barobill.kakaotalk.history.index', compact('currentTenant', 'barobillMember'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user