feat: [sms] SMS 발송 테스트 메뉴 추가
- SmsController (WEB): 카카오톡 패턴 동일한 HX-Redirect 처리 - BarobillSmsController (API): 발송, 발신번호 조회/확인, 전송상태 조회 - SMS 발송 테스트 블레이드 뷰: 발신번호 목록, 바이트 카운터, 발송 결과 표시 - web.php: barobill/sms/send 라우트 추가 - api.php: barobill/sms API 라우트 4개 추가
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
<?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;
|
||||
|
||||
class BarobillSmsController 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* SMS 발송
|
||||
*/
|
||||
public function sendSms(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'from_number' => 'required|string',
|
||||
'to_name' => 'required|string',
|
||||
'to_number' => 'required|string',
|
||||
'contents' => 'required|string',
|
||||
'send_dt' => 'nullable|string',
|
||||
'ref_key' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$member = $this->resolveMember();
|
||||
if ($member instanceof JsonResponse) {
|
||||
return $member;
|
||||
}
|
||||
|
||||
$result = $this->barobillService->sendSMSMessage(
|
||||
corpNum: $member->biz_no,
|
||||
senderId: $member->barobill_id,
|
||||
fromNumber: $validated['from_number'],
|
||||
toName: $validated['to_name'],
|
||||
toNumber: $validated['to_number'],
|
||||
contents: $validated['contents'],
|
||||
sendDT: $validated['send_dt'] ?? '',
|
||||
refKey: $validated['ref_key'] ?? ''
|
||||
);
|
||||
|
||||
if (! $result['success']) {
|
||||
return response()->json($result, 422);
|
||||
}
|
||||
|
||||
return response()->json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 등록된 발신번호 목록 조회
|
||||
*/
|
||||
public function getFromNumbers(): JsonResponse
|
||||
{
|
||||
$member = $this->resolveMember();
|
||||
if ($member instanceof JsonResponse) {
|
||||
return $member;
|
||||
}
|
||||
|
||||
$result = $this->barobillService->getSMSFromNumbers($member->biz_no);
|
||||
|
||||
if (! $result['success']) {
|
||||
return response()->json($result, 422);
|
||||
}
|
||||
|
||||
return response()->json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 발신번호 등록 여부 확인
|
||||
*/
|
||||
public function checkFromNumber(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'from_number' => 'required|string',
|
||||
]);
|
||||
|
||||
$member = $this->resolveMember();
|
||||
if ($member instanceof JsonResponse) {
|
||||
return $member;
|
||||
}
|
||||
|
||||
$result = $this->barobillService->checkSMSFromNumber(
|
||||
$member->biz_no,
|
||||
$validated['from_number']
|
||||
);
|
||||
|
||||
if (! $result['success']) {
|
||||
return response()->json($result, 422);
|
||||
}
|
||||
|
||||
return response()->json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* SMS 전송 상태 조회
|
||||
*/
|
||||
public function getSendState(string $sendKey): JsonResponse
|
||||
{
|
||||
$member = $this->resolveMember();
|
||||
if ($member instanceof JsonResponse) {
|
||||
return $member;
|
||||
}
|
||||
|
||||
$result = $this->barobillService->getSMSSendState($member->biz_no, $sendKey);
|
||||
|
||||
if (! $result['success']) {
|
||||
return response()->json($result, 422);
|
||||
}
|
||||
|
||||
return response()->json($result);
|
||||
}
|
||||
}
|
||||
29
app/Http/Controllers/Barobill/SmsController.php
Normal file
29
app/Http/Controllers/Barobill/SmsController.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?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 SmsController extends Controller
|
||||
{
|
||||
/**
|
||||
* SMS 발송 테스트
|
||||
*/
|
||||
public function send(Request $request): View|Response
|
||||
{
|
||||
if ($request->header('HX-Request')) {
|
||||
return response('', 200)->header('HX-Redirect', route('barobill.sms.send'));
|
||||
}
|
||||
|
||||
$tenantId = session('selected_tenant_id', 1);
|
||||
$currentTenant = Tenant::find($tenantId);
|
||||
$barobillMember = BarobillMember::where('tenant_id', $tenantId)->first();
|
||||
|
||||
return view('barobill.sms.send.index', compact('currentTenant', 'barobillMember'));
|
||||
}
|
||||
}
|
||||
304
resources/views/barobill/sms/send/index.blade.php
Normal file
304
resources/views/barobill/sms/send/index.blade.php
Normal file
@@ -0,0 +1,304 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'SMS 발송 테스트')
|
||||
|
||||
@section('content')
|
||||
<div class="flex flex-col h-full">
|
||||
<!-- 페이지 헤더 -->
|
||||
<div class="flex flex-col sm:flex-row sm:justify-between sm:items-center gap-4 mb-6 flex-shrink-0">
|
||||
<div>
|
||||
<div class="flex items-center gap-2 text-sm text-gray-500 mb-1">
|
||||
<span>바로빌</span>
|
||||
<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="M9 5l7 7-7 7" /></svg>
|
||||
<span class="text-gray-700">SMS 발송 테스트</span>
|
||||
</div>
|
||||
<h1 class="text-2xl font-bold text-gray-800">SMS 발송 테스트</h1>
|
||||
<p class="text-sm text-gray-500 mt-1">바로빌 SMS 서비스 연동 테스트 (단문 16.5원/건)</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if(!$barobillMember)
|
||||
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-6 text-center">
|
||||
<h3 class="text-lg font-semibold text-yellow-800 mb-1">바로빌 회원사 연동 필요</h3>
|
||||
<p class="text-sm text-yellow-600">SMS 발송을 위해 먼저 바로빌 회원사를 등록해주세요.</p>
|
||||
</div>
|
||||
@else
|
||||
<div class="space-y-6">
|
||||
<!-- 발신번호 상태 카드 -->
|
||||
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h3 class="font-semibold text-gray-800">등록된 발신번호</h3>
|
||||
<button type="button" onclick="loadFromNumbers()" class="text-xs px-3 py-1 bg-gray-100 text-gray-600 rounded-lg hover:bg-gray-200 transition">
|
||||
새로고침
|
||||
</button>
|
||||
</div>
|
||||
<div id="from-numbers-area">
|
||||
<div class="flex items-center gap-2 text-sm text-gray-500">
|
||||
<svg class="w-4 h-4 animate-spin" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path></svg>
|
||||
발신번호 목록 로딩 중...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SMS 발송 폼 -->
|
||||
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
|
||||
<h3 class="font-semibold text-gray-800 mb-4">SMS 발송</h3>
|
||||
<form id="sms-form" class="space-y-4">
|
||||
<!-- 발신번호 -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600 mb-1">발신번호</label>
|
||||
<select name="from_number" id="sms-from-number" class="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:ring-2 focus:ring-blue-500">
|
||||
<option value="">로딩 중...</option>
|
||||
</select>
|
||||
</div>
|
||||
<!-- 수신자 -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600 mb-1">수신자명</label>
|
||||
<input type="text" name="to_name" class="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm" placeholder="홍길동">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600 mb-1">수신번호</label>
|
||||
<input type="tel" name="to_number" class="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm" placeholder="01012345678">
|
||||
</div>
|
||||
</div>
|
||||
<!-- 메시지 내용 -->
|
||||
<div>
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<label class="block text-sm font-medium text-gray-600">메시지 내용</label>
|
||||
<span id="byte-counter" class="text-xs text-gray-400">0 / 90 바이트</span>
|
||||
</div>
|
||||
<textarea name="contents" id="sms-contents" rows="4" class="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm" placeholder="SMS 메시지를 입력하세요 (90바이트 이내)" oninput="updateByteCounter()"></textarea>
|
||||
<p id="lms-warning" class="text-xs text-orange-500 mt-1 hidden">90바이트 초과 시 LMS로 발송되며 요금이 다릅니다.</p>
|
||||
</div>
|
||||
<!-- 예약 발송 -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600 mb-1">예약 발송</label>
|
||||
<input type="datetime-local" name="send_dt" class="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm">
|
||||
<p class="text-xs text-gray-500 mt-1">비워두면 즉시 발송됩니다.</p>
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
<button type="submit" id="sms-submit-btn" class="px-6 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition font-medium flex items-center gap-2">
|
||||
<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="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" /></svg>
|
||||
SMS 발송
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- 발송 결과 -->
|
||||
<div id="send-result-area" class="hidden">
|
||||
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
|
||||
<h3 class="font-semibold text-gray-800 mb-4">발송 결과</h3>
|
||||
<div id="send-result-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
let fromNumberList = [];
|
||||
|
||||
function getByteLength(str) {
|
||||
let byteLen = 0;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const charCode = str.charCodeAt(i);
|
||||
byteLen += (charCode > 127 || charCode === 0xFFFD) ? 2 : 1;
|
||||
}
|
||||
return byteLen;
|
||||
}
|
||||
|
||||
function updateByteCounter() {
|
||||
const textarea = document.getElementById('sms-contents');
|
||||
const counter = document.getElementById('byte-counter');
|
||||
const warning = document.getElementById('lms-warning');
|
||||
const bytes = getByteLength(textarea.value);
|
||||
|
||||
counter.textContent = bytes + ' / 90 바이트';
|
||||
|
||||
if (bytes > 90) {
|
||||
counter.classList.remove('text-gray-400');
|
||||
counter.classList.add('text-orange-500');
|
||||
warning.classList.remove('hidden');
|
||||
} else {
|
||||
counter.classList.remove('text-orange-500');
|
||||
counter.classList.add('text-gray-400');
|
||||
warning.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
function loadFromNumbers() {
|
||||
const area = document.getElementById('from-numbers-area');
|
||||
const select = document.getElementById('sms-from-number');
|
||||
|
||||
area.innerHTML = '<div class="flex items-center gap-2 text-sm text-gray-500"><svg class="w-4 h-4 animate-spin" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path></svg> 발신번호 목록 로딩 중...</div>';
|
||||
|
||||
fetch('/api/admin/barobill/sms/from-numbers', {
|
||||
headers: { 'Accept': 'application/json', 'X-Requested-With': 'XMLHttpRequest' }
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (!data.success) {
|
||||
area.innerHTML = '<div class="text-sm text-red-500">발신번호 조회 실패: ' + (data.error || data.message || '알 수 없는 오류') + '</div>';
|
||||
select.innerHTML = '<option value="">발신번호 조회 실패</option>';
|
||||
return;
|
||||
}
|
||||
|
||||
const raw = data.data;
|
||||
let numbers = [];
|
||||
if (Array.isArray(raw)) {
|
||||
numbers = raw;
|
||||
} else if (raw && raw.SMSFromNumber) {
|
||||
numbers = Array.isArray(raw.SMSFromNumber) ? raw.SMSFromNumber : [raw.SMSFromNumber];
|
||||
} else if (raw && typeof raw === 'string') {
|
||||
numbers = [{ FromNumber: raw }];
|
||||
}
|
||||
|
||||
fromNumberList = numbers;
|
||||
|
||||
if (numbers.length === 0) {
|
||||
area.innerHTML = '<div class="text-sm text-gray-500">등록된 발신번호가 없습니다. 바로빌에서 발신번호를 먼저 등록해주세요.</div>';
|
||||
select.innerHTML = '<option value="">등록된 발신번호 없음</option>';
|
||||
return;
|
||||
}
|
||||
|
||||
// 발신번호 목록 표시
|
||||
let html = '<div class="flex flex-wrap gap-2">';
|
||||
numbers.forEach(num => {
|
||||
const number = num.FromNumber || num;
|
||||
html += '<span class="inline-flex items-center gap-1 px-3 py-1 bg-blue-50 text-blue-700 rounded-full text-sm">';
|
||||
html += '<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" /></svg>';
|
||||
html += number;
|
||||
html += '</span>';
|
||||
});
|
||||
html += '</div>';
|
||||
area.innerHTML = html;
|
||||
|
||||
// 셀렉트 채우기
|
||||
select.innerHTML = '<option value="">-- 발신번호 선택 --</option>';
|
||||
numbers.forEach(num => {
|
||||
const number = num.FromNumber || num;
|
||||
const opt = document.createElement('option');
|
||||
opt.value = number;
|
||||
opt.textContent = number;
|
||||
select.appendChild(opt);
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
area.innerHTML = '<div class="text-sm text-red-500">API 오류: ' + err.message + '</div>';
|
||||
select.innerHTML = '<option value="">API 오류</option>';
|
||||
});
|
||||
}
|
||||
|
||||
function formatReserveDT(datetimeLocal) {
|
||||
if (!datetimeLocal) return '';
|
||||
return datetimeLocal.replace(/[-T:]/g, '').substring(0, 14);
|
||||
}
|
||||
|
||||
function showSendResult(data) {
|
||||
const area = document.getElementById('send-result-area');
|
||||
const content = document.getElementById('send-result-content');
|
||||
area.classList.remove('hidden');
|
||||
|
||||
if (data.success) {
|
||||
const sendKey = data.data || '';
|
||||
content.innerHTML = `
|
||||
<div class="bg-green-50 border border-green-200 rounded-lg p-4">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<svg class="w-5 h-5 text-green-600" 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>
|
||||
<span class="font-semibold text-green-800">발송 성공</span>
|
||||
</div>
|
||||
<p class="text-sm text-green-700 mb-3">전송키: <code class="bg-green-100 px-2 py-0.5 rounded">${sendKey}</code></p>
|
||||
<button type="button" onclick="checkSendState('${sendKey}')" class="text-xs px-3 py-1.5 bg-green-600 text-white rounded-lg hover:bg-green-700 transition">
|
||||
전송 상태 조회
|
||||
</button>
|
||||
<div id="send-state-result" class="mt-3"></div>
|
||||
</div>`;
|
||||
} else {
|
||||
content.innerHTML = `
|
||||
<div class="bg-red-50 border border-red-200 rounded-lg p-4">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<svg class="w-5 h-5 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
|
||||
<span class="font-semibold text-red-800">발송 실패</span>
|
||||
</div>
|
||||
<p class="text-sm text-red-700">${data.error || data.message || '알 수 없는 오류'}</p>
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
function checkSendState(sendKey) {
|
||||
const stateArea = document.getElementById('send-state-result');
|
||||
stateArea.innerHTML = '<div class="text-sm text-gray-500">상태 조회 중...</div>';
|
||||
|
||||
fetch('/api/admin/barobill/sms/send-state/' + encodeURIComponent(sendKey), {
|
||||
headers: { 'Accept': 'application/json', 'X-Requested-With': 'XMLHttpRequest' }
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
const state = data.data;
|
||||
let stateHtml = '<div class="bg-white border rounded-lg p-3 text-sm">';
|
||||
stateHtml += '<p class="font-medium text-gray-700 mb-1">전송 상태 상세:</p>';
|
||||
stateHtml += '<pre class="bg-gray-50 p-2 rounded text-xs overflow-auto">' + JSON.stringify(state, null, 2) + '</pre>';
|
||||
stateHtml += '</div>';
|
||||
stateArea.innerHTML = stateHtml;
|
||||
} else {
|
||||
stateArea.innerHTML = '<div class="text-sm text-red-500">상태 조회 실패: ' + (data.error || data.message) + '</div>';
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
stateArea.innerHTML = '<div class="text-sm text-red-500">API 오류: ' + err.message + '</div>';
|
||||
});
|
||||
}
|
||||
|
||||
// SMS 발송 폼 제출
|
||||
document.getElementById('sms-form')?.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
const fd = new FormData(this);
|
||||
const btn = document.getElementById('sms-submit-btn');
|
||||
|
||||
const body = {
|
||||
from_number: fd.get('from_number'),
|
||||
to_name: fd.get('to_name'),
|
||||
to_number: fd.get('to_number'),
|
||||
contents: fd.get('contents'),
|
||||
send_dt: formatReserveDT(fd.get('send_dt')),
|
||||
};
|
||||
|
||||
if (!body.from_number) { alert('발신번호를 선택해주세요.'); return; }
|
||||
if (!body.to_name) { alert('수신자명을 입력해주세요.'); return; }
|
||||
if (!body.to_number) { alert('수신번호를 입력해주세요.'); return; }
|
||||
if (!body.contents) { alert('메시지 내용을 입력해주세요.'); return; }
|
||||
|
||||
btn.disabled = true;
|
||||
btn.textContent = '발송 중...';
|
||||
|
||||
fetch('/api/admin/barobill/sms/send', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.content
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
btn.disabled = false;
|
||||
btn.innerHTML = '<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="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" /></svg> SMS 발송';
|
||||
showSendResult(data);
|
||||
})
|
||||
.catch(err => {
|
||||
btn.disabled = false;
|
||||
btn.innerHTML = '<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="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" /></svg> SMS 발송';
|
||||
showSendResult({ success: false, error: err.message });
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', loadFromNumbers);
|
||||
</script>
|
||||
@endpush
|
||||
@@ -225,6 +225,14 @@
|
||||
Route::delete('/send/{sendKey}/cancel', [\App\Http\Controllers\Api\Admin\Barobill\BarobillKakaotalkController::class, 'cancelReserved'])->name('send.cancel');
|
||||
});
|
||||
|
||||
// 바로빌 SMS API
|
||||
Route::prefix('barobill/sms')->name('barobill.sms.')->group(function () {
|
||||
Route::post('/send', [\App\Http\Controllers\Api\Admin\Barobill\BarobillSmsController::class, 'sendSms'])->name('send');
|
||||
Route::get('/from-numbers', [\App\Http\Controllers\Api\Admin\Barobill\BarobillSmsController::class, 'getFromNumbers'])->name('from-numbers');
|
||||
Route::post('/check-from-number', [\App\Http\Controllers\Api\Admin\Barobill\BarobillSmsController::class, 'checkFromNumber'])->name('check-from-number');
|
||||
Route::get('/send-state/{sendKey}', [\App\Http\Controllers\Api\Admin\Barobill\BarobillSmsController::class, 'getSendState'])->name('send-state');
|
||||
});
|
||||
|
||||
// 테넌트 관리 API
|
||||
Route::prefix('tenants')->name('tenants.')->group(function () {
|
||||
// 고정 경로는 먼저 정의
|
||||
|
||||
@@ -631,6 +631,11 @@
|
||||
Route::get('/history', [\App\Http\Controllers\Barobill\KakaotalkController::class, 'history'])->name('history');
|
||||
Route::get('/guide', [\App\Http\Controllers\Barobill\KakaotalkController::class, 'guide'])->name('guide');
|
||||
});
|
||||
|
||||
// SMS 발송 테스트
|
||||
Route::prefix('sms')->name('sms.')->group(function () {
|
||||
Route::get('/send', [\App\Http\Controllers\Barobill\SmsController::class, 'send'])->name('send');
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user