feat:법인도장 대시보드 등록 + 새 계약 자동 적용

- 대시보드 설정 탭 추가 (법인도장 등록/미리보기/삭제 UI)
- tenant_settings 테이블에 esign/company_stamp 키로 저장
- 새 계약 생성 시 등록된 도장 자동 적용 (creator signer)
- 계약 생성 페이지에서 개별 도장 업로드 UI 제거

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
김보곤
2026-02-13 16:26:28 +09:00
parent 24c6927b56
commit e8d494a081
4 changed files with 245 additions and 48 deletions

View File

@@ -11,6 +11,7 @@
use App\Models\ESign\EsignSigner;
use App\Models\ESign\EsignSignField;
use App\Models\ESign\EsignAuditLog;
use App\Models\Tenants\TenantSetting;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
@@ -20,6 +21,101 @@
class EsignApiController extends Controller
{
/**
* 법인도장 조회
*/
public function getStamp(): JsonResponse
{
$tenantId = session('selected_tenant_id', 1);
$setting = TenantSetting::where('tenant_id', $tenantId)
->where('setting_group', 'esign')
->where('setting_key', 'company_stamp')
->first();
if (!$setting || empty($setting->setting_value['image_path'])) {
return response()->json(['success' => true, 'data' => null]);
}
$path = $setting->setting_value['image_path'];
$exists = Storage::disk('local')->exists($path);
return response()->json([
'success' => true,
'data' => $exists ? [
'image_path' => $path,
'image_url' => '/storage/' . $path,
] : null,
]);
}
/**
* 법인도장 업로드
*/
public function uploadStamp(Request $request): JsonResponse
{
$request->validate([
'stamp_image' => 'required|image|max:5120',
]);
$tenantId = session('selected_tenant_id', 1);
$file = $request->file('stamp_image');
$path = "esign/{$tenantId}/stamps/company_stamp.png";
// 기존 파일이 있으면 삭제
if (Storage::disk('local')->exists($path)) {
Storage::disk('local')->delete($path);
}
Storage::disk('local')->put($path, file_get_contents($file->getRealPath()));
TenantSetting::updateOrCreate(
[
'tenant_id' => $tenantId,
'setting_group' => 'esign',
'setting_key' => 'company_stamp',
],
[
'setting_value' => ['image_path' => $path],
'updated_by' => auth()->id(),
]
);
return response()->json([
'success' => true,
'message' => '법인도장이 등록되었습니다.',
'data' => [
'image_path' => $path,
'image_url' => '/storage/' . $path,
],
]);
}
/**
* 법인도장 삭제
*/
public function deleteStamp(): JsonResponse
{
$tenantId = session('selected_tenant_id', 1);
$setting = TenantSetting::where('tenant_id', $tenantId)
->where('setting_group', 'esign')
->where('setting_key', 'company_stamp')
->first();
if ($setting) {
$path = $setting->setting_value['image_path'] ?? null;
if ($path && Storage::disk('local')->exists($path)) {
Storage::disk('local')->delete($path);
}
$setting->delete();
}
return response()->json([
'success' => true,
'message' => '법인도장이 삭제되었습니다.',
]);
}
/**
* 상태별 통계
*/
@@ -99,7 +195,6 @@ public function store(Request $request): JsonResponse
'metadata' => 'nullable|array',
'metadata.*' => 'nullable|string|max:500',
'file' => 'nullable|file|mimes:pdf,doc,docx|max:20480',
'creator_stamp_image' => 'nullable|string',
]);
$tenantId = session('selected_tenant_id', 1);
@@ -179,18 +274,22 @@ public function store(Request $request): JsonResponse
]);
}
// 법인도장 이미지 처리
if ($request->input('creator_stamp_image')) {
// 법인도장 자동 적용: tenant_settings에 등록된 도장이 있으면 creator signer에 설정
$stampSetting = TenantSetting::where('tenant_id', $tenantId)
->where('setting_group', 'esign')
->where('setting_key', 'company_stamp')
->first();
if ($stampSetting && !empty($stampSetting->setting_value['image_path'])) {
$creatorSigner = EsignSigner::withoutGlobalScopes()
->where('contract_id', $contract->id)
->where('role', 'creator')
->first();
if ($creatorSigner) {
$imageData = base64_decode($request->input('creator_stamp_image'));
$imagePath = "esign/{$tenantId}/signatures/{$contract->id}_{$creatorSigner->id}_stamp.png";
Storage::disk('local')->put($imagePath, $imageData);
$creatorSigner->update(['signature_image_path' => $imagePath]);
$creatorSigner->update([
'signature_image_path' => $stampSetting->setting_value['image_path'],
]);
}
}