feat:바로빌 설정 페이지에 서비스 이용 옵션 체크박스 추가
- 4가지 서비스 옵션 체크박스 추가 (전자세금계산서, 계좌조회, 카드사용내역, 홈텍스매입/매출) - BarobillSetting 모델 및 BarobillSettingController 생성 - 설정 API 라우트 추가 (/api/admin/barobill/settings) - 담당자 정보 입력 필드 추가 (이름, 연락처, 이메일) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin\Barobill;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Barobill\BarobillSetting;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class BarobillSettingController extends Controller
|
||||
{
|
||||
/**
|
||||
* 현재 테넌트의 바로빌 설정 조회
|
||||
*/
|
||||
public function show(): JsonResponse
|
||||
{
|
||||
$tenantId = session('tenant_id', 1);
|
||||
|
||||
$setting = BarobillSetting::where('tenant_id', $tenantId)->first();
|
||||
|
||||
if (!$setting) {
|
||||
// 설정이 없으면 기본값 반환
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'use_tax_invoice' => false,
|
||||
'use_bank_account' => false,
|
||||
'use_card_usage' => false,
|
||||
'use_hometax' => false,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => $setting,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 바로빌 설정 저장/수정
|
||||
*/
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$tenantId = session('tenant_id', 1);
|
||||
|
||||
$validated = $request->validate([
|
||||
'use_tax_invoice' => 'nullable|boolean',
|
||||
'use_bank_account' => 'nullable|boolean',
|
||||
'use_card_usage' => 'nullable|boolean',
|
||||
'use_hometax' => 'nullable|boolean',
|
||||
'contact_name' => 'nullable|string|max:50',
|
||||
'contact_tel' => 'nullable|string|max:20',
|
||||
'contact_id' => 'nullable|email|max:100',
|
||||
]);
|
||||
|
||||
try {
|
||||
$setting = BarobillSetting::updateOrCreate(
|
||||
['tenant_id' => $tenantId],
|
||||
array_merge($validated, [
|
||||
'corp_name' => $validated['corp_name'] ?? '미설정',
|
||||
'ceo_name' => $validated['ceo_name'] ?? '미설정',
|
||||
'corp_num' => $validated['corp_num'] ?? '0000000000',
|
||||
])
|
||||
);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => '설정이 저장되었습니다.',
|
||||
'data' => $setting,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
Log::error('바로빌 설정 저장 실패', ['error' => $e->getMessage()]);
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => '설정 저장에 실패했습니다.',
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 서비스 이용 여부 확인 (다른 메뉴에서 참조용)
|
||||
*/
|
||||
public function checkService(string $service): JsonResponse
|
||||
{
|
||||
$tenantId = session('tenant_id', 1);
|
||||
|
||||
$setting = BarobillSetting::where('tenant_id', $tenantId)->first();
|
||||
|
||||
if (!$setting) {
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'enabled' => false,
|
||||
'message' => '바로빌 설정이 없습니다.',
|
||||
]);
|
||||
}
|
||||
|
||||
$enabled = match ($service) {
|
||||
'tax_invoice', 'tax-invoice' => $setting->use_tax_invoice,
|
||||
'bank_account', 'bank-account' => $setting->use_bank_account,
|
||||
'card_usage', 'card-usage' => $setting->use_card_usage,
|
||||
'hometax' => $setting->use_hometax,
|
||||
default => false,
|
||||
};
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'enabled' => $enabled,
|
||||
'service' => $service,
|
||||
]);
|
||||
}
|
||||
}
|
||||
69
app/Models/Barobill/BarobillSetting.php
Normal file
69
app/Models/Barobill/BarobillSetting.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Barobill;
|
||||
|
||||
use App\Models\Tenants\Tenant;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class BarobillSetting extends Model
|
||||
{
|
||||
protected $table = 'barobill_settings';
|
||||
|
||||
protected $fillable = [
|
||||
'tenant_id',
|
||||
'corp_num',
|
||||
'cert_key',
|
||||
'barobill_id',
|
||||
'corp_name',
|
||||
'ceo_name',
|
||||
'addr',
|
||||
'biz_type',
|
||||
'biz_class',
|
||||
'contact_id',
|
||||
'contact_name',
|
||||
'contact_tel',
|
||||
'is_active',
|
||||
'auto_issue',
|
||||
'use_tax_invoice',
|
||||
'use_bank_account',
|
||||
'use_card_usage',
|
||||
'use_hometax',
|
||||
'verified_at',
|
||||
'created_by',
|
||||
'updated_by',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'is_active' => 'boolean',
|
||||
'auto_issue' => 'boolean',
|
||||
'use_tax_invoice' => 'boolean',
|
||||
'use_bank_account' => 'boolean',
|
||||
'use_card_usage' => 'boolean',
|
||||
'use_hometax' => 'boolean',
|
||||
'verified_at' => 'datetime',
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
];
|
||||
|
||||
/**
|
||||
* 테넌트 관계
|
||||
*/
|
||||
public function tenant(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Tenant::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 활성화된 서비스 목록 반환
|
||||
*/
|
||||
public function getActiveServicesAttribute(): array
|
||||
{
|
||||
$services = [];
|
||||
if ($this->use_tax_invoice) $services[] = 'tax_invoice';
|
||||
if ($this->use_bank_account) $services[] = 'bank_account';
|
||||
if ($this->use_card_usage) $services[] = 'card_usage';
|
||||
if ($this->use_hometax) $services[] = 'hometax';
|
||||
return $services;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('barobill_settings', function (Blueprint $table) {
|
||||
// 서비스 이용 옵션
|
||||
$table->boolean('use_tax_invoice')->default(false)->after('auto_issue')->comment('전자세금계산서 이용');
|
||||
$table->boolean('use_bank_account')->default(false)->after('use_tax_invoice')->comment('계좌조회 이용');
|
||||
$table->boolean('use_card_usage')->default(false)->after('use_bank_account')->comment('카드사용내역 이용');
|
||||
$table->boolean('use_hometax')->default(false)->after('use_card_usage')->comment('홈텍스매입/매출 이용');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('barobill_settings', function (Blueprint $table) {
|
||||
$table->dropColumn(['use_tax_invoice', 'use_bank_account', 'use_card_usage', 'use_hometax']);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -13,136 +13,273 @@
|
||||
</div>
|
||||
|
||||
<!-- 설정 카드 -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<!-- 이메일 설정 -->
|
||||
<div class="bg-white rounded-lg shadow-sm p-6">
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<div class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center">
|
||||
<svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-semibold text-gray-800">이메일 설정</h3>
|
||||
<p class="text-xs text-gray-500">세금계산서 발송 이메일 설정</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600 mb-1">발신 이메일 주소</label>
|
||||
<input type="email" class="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="noreply@company.com">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600 mb-1">담당자 이메일</label>
|
||||
<input type="email" class="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="manager@company.com">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 동기화 설정 -->
|
||||
<div class="bg-white rounded-lg shadow-sm p-6">
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<div class="w-10 h-10 bg-green-100 rounded-lg flex items-center justify-center">
|
||||
<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="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-semibold text-gray-800">데이터 동기화</h3>
|
||||
<p class="text-xs text-gray-500">바로빌 데이터 동기화 설정</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-4">
|
||||
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
|
||||
<div>
|
||||
<p class="text-sm font-medium text-gray-700">자동 동기화</p>
|
||||
<p class="text-xs text-gray-500">매일 자정 자동 동기화</p>
|
||||
<form id="settings-form" class="space-y-6">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<!-- 서비스 이용 설정 -->
|
||||
<div class="bg-white rounded-lg shadow-sm p-6 lg:col-span-2">
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<div class="w-10 h-10 bg-indigo-100 rounded-lg flex items-center justify-center">
|
||||
<svg class="w-5 h-5 text-indigo-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>
|
||||
</div>
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" class="sr-only peer">
|
||||
<div class="w-11 h-6 bg-gray-200 peer-focus:ring-2 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
|
||||
<div>
|
||||
<h3 class="font-semibold text-gray-800">서비스 이용 설정</h3>
|
||||
<p class="text-xs text-gray-500">이용할 바로빌 서비스를 선택하세요</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<!-- 전자세금계산서 -->
|
||||
<label class="flex items-start gap-3 p-4 bg-gray-50 rounded-lg cursor-pointer hover:bg-gray-100 transition border-2 border-transparent has-[:checked]:border-blue-500 has-[:checked]:bg-blue-50">
|
||||
<input type="checkbox" name="use_tax_invoice" id="use_tax_invoice" class="mt-1 w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500">
|
||||
<div>
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
||||
</svg>
|
||||
<span class="font-medium text-gray-800">전자세금계산서</span>
|
||||
</div>
|
||||
<p class="text-xs text-gray-500 mt-1">세금계산서 발행/수신 서비스</p>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<!-- 계좌조회 -->
|
||||
<label class="flex items-start gap-3 p-4 bg-gray-50 rounded-lg cursor-pointer hover:bg-gray-100 transition border-2 border-transparent has-[:checked]:border-green-500 has-[:checked]:bg-green-50">
|
||||
<input type="checkbox" name="use_bank_account" id="use_bank_account" class="mt-1 w-4 h-4 text-green-600 bg-gray-100 border-gray-300 rounded focus:ring-green-500">
|
||||
<div>
|
||||
<div class="flex items-center gap-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="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" />
|
||||
</svg>
|
||||
<span class="font-medium text-gray-800">계좌조회</span>
|
||||
</div>
|
||||
<p class="text-xs text-gray-500 mt-1">은행 계좌 거래내역 조회</p>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<!-- 카드사용내역 -->
|
||||
<label class="flex items-start gap-3 p-4 bg-gray-50 rounded-lg cursor-pointer hover:bg-gray-100 transition border-2 border-transparent has-[:checked]:border-purple-500 has-[:checked]:bg-purple-50">
|
||||
<input type="checkbox" name="use_card_usage" id="use_card_usage" class="mt-1 w-4 h-4 text-purple-600 bg-gray-100 border-gray-300 rounded focus:ring-purple-500">
|
||||
<div>
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="w-5 h-5 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" />
|
||||
</svg>
|
||||
<span class="font-medium text-gray-800">카드사용내역</span>
|
||||
</div>
|
||||
<p class="text-xs text-gray-500 mt-1">카드 결제내역 조회</p>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<!-- 홈텍스매입/매출 -->
|
||||
<label class="flex items-start gap-3 p-4 bg-gray-50 rounded-lg cursor-pointer hover:bg-gray-100 transition border-2 border-transparent has-[:checked]:border-orange-500 has-[:checked]:bg-orange-50">
|
||||
<input type="checkbox" name="use_hometax" id="use_hometax" class="mt-1 w-4 h-4 text-orange-600 bg-gray-100 border-gray-300 rounded focus:ring-orange-500">
|
||||
<div>
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="w-5 h-5 text-orange-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 7h6m0 10v-3m-3 3h.01M9 17h.01M9 14h.01M12 14h.01M15 11h.01M12 11h.01M9 11h.01M7 21h10a2 2 0 002-2V5a2 2 0 00-2-2H7a2 2 0 00-2 2v14a2 2 0 002 2z" />
|
||||
</svg>
|
||||
<span class="font-medium text-gray-800">홈텍스매입/매출</span>
|
||||
</div>
|
||||
<p class="text-xs text-gray-500 mt-1">홈텍스 매입/매출 자료 조회</p>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
<button type="button" class="w-full px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition flex items-center justify-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="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
||||
</svg>
|
||||
지금 동기화
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- API 설정 -->
|
||||
<div class="bg-white rounded-lg shadow-sm p-6">
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<div class="w-10 h-10 bg-purple-100 rounded-lg flex items-center justify-center">
|
||||
<svg class="w-5 h-5 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" />
|
||||
</svg>
|
||||
<!-- 담당자 정보 -->
|
||||
<div class="bg-white rounded-lg shadow-sm p-6">
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<div class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center">
|
||||
<svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-semibold text-gray-800">담당자 정보</h3>
|
||||
<p class="text-xs text-gray-500">세금계산서 담당자 정보</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-semibold text-gray-800">API 설정</h3>
|
||||
<p class="text-xs text-gray-500">바로빌 API 연동 설정</p>
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600 mb-1">담당자명</label>
|
||||
<input type="text" name="contact_name" id="contact_name" class="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="홍길동">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600 mb-1">연락처</label>
|
||||
<input type="tel" name="contact_tel" id="contact_tel" class="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="02-1234-5678">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600 mb-1">담당자 이메일</label>
|
||||
<input type="email" name="contact_id" id="contact_id" class="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="manager@company.com">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600 mb-1">API CERT KEY</label>
|
||||
<input type="password" class="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="**********************">
|
||||
|
||||
<!-- 동기화 설정 -->
|
||||
<div class="bg-white rounded-lg shadow-sm p-6">
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<div class="w-10 h-10 bg-green-100 rounded-lg flex items-center justify-center">
|
||||
<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="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-semibold text-gray-800">데이터 동기화</h3>
|
||||
<p class="text-xs text-gray-500">바로빌 데이터 동기화 설정</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 p-3 bg-green-50 rounded-lg border border-green-200">
|
||||
<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="text-sm text-green-700">API 연결 상태: 정상</span>
|
||||
<div class="space-y-4">
|
||||
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
|
||||
<div>
|
||||
<p class="text-sm font-medium text-gray-700">자동 동기화</p>
|
||||
<p class="text-xs text-gray-500">매일 자정 자동 동기화</p>
|
||||
</div>
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" class="sr-only peer">
|
||||
<div class="w-11 h-6 bg-gray-200 peer-focus:ring-2 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
|
||||
</label>
|
||||
</div>
|
||||
<button type="button" class="w-full px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition flex items-center justify-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="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
||||
</svg>
|
||||
지금 동기화
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 알림 설정 -->
|
||||
<div class="bg-white rounded-lg shadow-sm p-6">
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<div class="w-10 h-10 bg-yellow-100 rounded-lg flex items-center justify-center">
|
||||
<svg class="w-5 h-5 text-yellow-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-semibold text-gray-800">알림 설정</h3>
|
||||
<p class="text-xs text-gray-500">세금계산서 관련 알림</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
|
||||
<span class="text-sm text-gray-700">발행 완료 알림</span>
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" checked class="sr-only peer">
|
||||
<div class="w-11 h-6 bg-gray-200 peer-focus:ring-2 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
|
||||
<span class="text-sm text-gray-700">수신 알림</span>
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" checked class="sr-only peer">
|
||||
<div class="w-11 h-6 bg-gray-200 peer-focus:ring-2 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
|
||||
<span class="text-sm text-gray-700">만료 예정 알림</span>
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" class="sr-only peer">
|
||||
<div class="w-11 h-6 bg-gray-200 peer-focus:ring-2 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 저장 버튼 -->
|
||||
<div class="flex justify-end gap-3">
|
||||
<button type="button" id="btn-reset" class="px-6 py-2.5 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition font-medium">
|
||||
초기화
|
||||
</button>
|
||||
<button type="submit" id="btn-save" class="px-6 py-2.5 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition font-medium flex items-center gap-2">
|
||||
<svg class="w-4 h-4 hidden animate-spin" id="save-spinner" fill="none" stroke="currentColor" 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 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
설정 저장
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- 저장 버튼 -->
|
||||
<div class="mt-6 flex justify-end">
|
||||
<button type="button" class="px-6 py-2.5 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition font-medium">
|
||||
설정 저장
|
||||
</button>
|
||||
</div>
|
||||
<!-- 토스트 메시지 -->
|
||||
<div id="toast" class="fixed bottom-4 right-4 px-4 py-3 rounded-lg shadow-lg transform translate-y-full opacity-0 transition-all duration-300 z-50"></div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const form = document.getElementById('settings-form');
|
||||
const toast = document.getElementById('toast');
|
||||
const saveSpinner = document.getElementById('save-spinner');
|
||||
const btnSave = document.getElementById('btn-save');
|
||||
const btnReset = document.getElementById('btn-reset');
|
||||
|
||||
// 토스트 표시
|
||||
function showToast(message, type = 'success') {
|
||||
toast.textContent = message;
|
||||
toast.className = 'fixed bottom-4 right-4 px-4 py-3 rounded-lg shadow-lg transform transition-all duration-300 z-50';
|
||||
if (type === 'success') {
|
||||
toast.classList.add('bg-green-600', 'text-white');
|
||||
} else {
|
||||
toast.classList.add('bg-red-600', 'text-white');
|
||||
}
|
||||
toast.classList.remove('translate-y-full', 'opacity-0');
|
||||
|
||||
setTimeout(() => {
|
||||
toast.classList.add('translate-y-full', 'opacity-0');
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// 설정 로드
|
||||
async function loadSettings() {
|
||||
try {
|
||||
const response = await fetch('/api/admin/barobill/settings');
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success && result.data) {
|
||||
const data = result.data;
|
||||
|
||||
// 서비스 이용 설정
|
||||
document.getElementById('use_tax_invoice').checked = data.use_tax_invoice || false;
|
||||
document.getElementById('use_bank_account').checked = data.use_bank_account || false;
|
||||
document.getElementById('use_card_usage').checked = data.use_card_usage || false;
|
||||
document.getElementById('use_hometax').checked = data.use_hometax || false;
|
||||
|
||||
// 담당자 정보
|
||||
document.getElementById('contact_name').value = data.contact_name || '';
|
||||
document.getElementById('contact_tel').value = data.contact_tel || '';
|
||||
document.getElementById('contact_id').value = data.contact_id || '';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('설정 로드 실패:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 설정 저장
|
||||
async function saveSettings(e) {
|
||||
e.preventDefault();
|
||||
|
||||
saveSpinner.classList.remove('hidden');
|
||||
btnSave.disabled = true;
|
||||
|
||||
const formData = {
|
||||
use_tax_invoice: document.getElementById('use_tax_invoice').checked,
|
||||
use_bank_account: document.getElementById('use_bank_account').checked,
|
||||
use_card_usage: document.getElementById('use_card_usage').checked,
|
||||
use_hometax: document.getElementById('use_hometax').checked,
|
||||
contact_name: document.getElementById('contact_name').value,
|
||||
contact_tel: document.getElementById('contact_tel').value,
|
||||
contact_id: document.getElementById('contact_id').value,
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/admin/barobill/settings', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
|
||||
},
|
||||
body: JSON.stringify(formData),
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showToast(result.message || '설정이 저장되었습니다.', 'success');
|
||||
} else {
|
||||
showToast(result.message || '설정 저장에 실패했습니다.', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('설정 저장 실패:', error);
|
||||
showToast('설정 저장 중 오류가 발생했습니다.', 'error');
|
||||
} finally {
|
||||
saveSpinner.classList.add('hidden');
|
||||
btnSave.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 초기화 버튼
|
||||
btnReset.addEventListener('click', function() {
|
||||
document.getElementById('use_tax_invoice').checked = false;
|
||||
document.getElementById('use_bank_account').checked = false;
|
||||
document.getElementById('use_card_usage').checked = false;
|
||||
document.getElementById('use_hometax').checked = false;
|
||||
document.getElementById('contact_name').value = '';
|
||||
document.getElementById('contact_tel').value = '';
|
||||
document.getElementById('contact_id').value = '';
|
||||
showToast('설정이 초기화되었습니다.', 'success');
|
||||
});
|
||||
|
||||
// 이벤트 리스너
|
||||
form.addEventListener('submit', saveSettings);
|
||||
|
||||
// 초기 로드
|
||||
loadSettings();
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
@@ -100,6 +100,13 @@
|
||||
Route::post('/sync', [\App\Http\Controllers\Api\Admin\Barobill\BarobillConfigController::class, 'syncCompanies'])->name('sync');
|
||||
});
|
||||
|
||||
// 바로빌 설정 API (회원사용)
|
||||
Route::prefix('barobill/settings')->name('barobill.settings.')->group(function () {
|
||||
Route::get('/', [\App\Http\Controllers\Api\Admin\Barobill\BarobillSettingController::class, 'show'])->name('show');
|
||||
Route::post('/', [\App\Http\Controllers\Api\Admin\Barobill\BarobillSettingController::class, 'store'])->name('store');
|
||||
Route::get('/check/{service}', [\App\Http\Controllers\Api\Admin\Barobill\BarobillSettingController::class, 'checkService'])->name('check');
|
||||
});
|
||||
|
||||
// 바로빌 회원사 관리 API
|
||||
Route::prefix('barobill/members')->name('barobill.members.')->group(function () {
|
||||
// 통계
|
||||
|
||||
Reference in New Issue
Block a user