feat:전자계약 알림톡 발송 방식 선택 기능 추가
- EsignApiController: send_method/sms_fallback 저장, dispatchNotification/sendAlimtalk 메서드 추가 - EsignPublicController: 완료/다음서명자 알림에 알림톡 지원 추가 - EsignContract 모델: send_method, sms_fallback fillable/casts 추가 - send.blade.php: 발송방식 선택 UI (알림톡/이메일/동시), SMS 대체발송, 연락처 확인 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Mail\EsignRequestMail;
|
||||
use App\Models\Barobill\BarobillMember;
|
||||
use App\Models\ESign\EsignContract;
|
||||
use App\Models\User;
|
||||
use App\Services\ESign\DocxToPdfConverter;
|
||||
@@ -13,6 +14,7 @@
|
||||
use App\Models\ESign\EsignSignField;
|
||||
use App\Models\ESign\EsignAuditLog;
|
||||
use App\Models\Tenants\TenantSetting;
|
||||
use App\Services\Barobill\BarobillService;
|
||||
use App\Services\GoogleCloudStorageService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -692,27 +694,27 @@ public function send(Request $request, int $id): JsonResponse
|
||||
return response()->json(['success' => false, 'message' => '초안 상태에서만 발송할 수 있습니다.'], 422);
|
||||
}
|
||||
|
||||
$sendMethod = $request->input('send_method', 'alimtalk');
|
||||
$smsFallback = $request->boolean('sms_fallback', true);
|
||||
|
||||
$contract->update([
|
||||
'status' => 'pending',
|
||||
'send_method' => $sendMethod,
|
||||
'sms_fallback' => $smsFallback,
|
||||
'updated_by' => auth()->id(),
|
||||
]);
|
||||
|
||||
// 서명 순서 유형에 따라 알림 발송
|
||||
// 발송 대상 서명자 결정
|
||||
if ($contract->sign_order_type === 'parallel') {
|
||||
// 동시 서명: 모든 서명자에게 발송
|
||||
foreach ($contract->signers as $s) {
|
||||
$s->update(['status' => 'notified']);
|
||||
Mail::to($s->email)->send(new EsignRequestMail($contract, $s));
|
||||
}
|
||||
$targetSigners = $contract->signers;
|
||||
} else {
|
||||
// 순차 서명: 첫 번째 서명자에게 발송
|
||||
$firstSigner = $contract->signers()
|
||||
->orderBy('sign_order')
|
||||
->first();
|
||||
if ($firstSigner) {
|
||||
$firstSigner->update(['status' => 'notified']);
|
||||
Mail::to($firstSigner->email)->send(new EsignRequestMail($contract, $firstSigner));
|
||||
}
|
||||
$first = $contract->signers()->orderBy('sign_order')->first();
|
||||
$targetSigners = $first ? collect([$first]) : collect();
|
||||
}
|
||||
|
||||
foreach ($targetSigners as $signer) {
|
||||
$signer->update(['status' => 'notified']);
|
||||
$this->dispatchNotification($contract, $signer, $sendMethod, $smsFallback);
|
||||
}
|
||||
|
||||
EsignAuditLog::create([
|
||||
@@ -721,7 +723,7 @@ public function send(Request $request, int $id): JsonResponse
|
||||
'action' => 'sign_request_sent',
|
||||
'ip_address' => $request->ip(),
|
||||
'user_agent' => $request->userAgent(),
|
||||
'metadata' => ['sent_by' => auth()->id()],
|
||||
'metadata' => ['sent_by' => auth()->id(), 'send_method' => $sendMethod],
|
||||
'created_at' => now(),
|
||||
]);
|
||||
|
||||
@@ -748,7 +750,12 @@ public function remind(Request $request, int $id): JsonResponse
|
||||
|
||||
if ($nextSigner) {
|
||||
$nextSigner->update(['status' => 'notified']);
|
||||
Mail::to($nextSigner->email)->send(new EsignRequestMail($contract, $nextSigner, isReminder: true));
|
||||
$this->dispatchNotification(
|
||||
$contract, $nextSigner,
|
||||
$contract->send_method ?? 'alimtalk',
|
||||
$contract->sms_fallback ?? true,
|
||||
isReminder: true,
|
||||
);
|
||||
}
|
||||
|
||||
EsignAuditLog::create([
|
||||
@@ -772,6 +779,88 @@ public function remind(Request $request, int $id): JsonResponse
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 발송 방식에 따라 알림톡/이메일 분기 발송
|
||||
*/
|
||||
private function dispatchNotification(
|
||||
EsignContract $contract,
|
||||
EsignSigner $signer,
|
||||
string $sendMethod,
|
||||
bool $smsFallback,
|
||||
bool $isReminder = false,
|
||||
): void {
|
||||
// 알림톡 발송
|
||||
if (in_array($sendMethod, ['alimtalk', 'both']) && $signer->phone) {
|
||||
$this->sendAlimtalk($contract, $signer, $smsFallback, $isReminder);
|
||||
}
|
||||
|
||||
// 이메일 발송 (email/both 선택 시, 또는 알림톡인데 번호 없으면 폴백)
|
||||
if (in_array($sendMethod, ['email', 'both']) || ($sendMethod === 'alimtalk' && !$signer->phone)) {
|
||||
if ($signer->email) {
|
||||
Mail::to($signer->email)->send(new EsignRequestMail($contract, $signer, $isReminder));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 알림톡 발송
|
||||
*/
|
||||
private function sendAlimtalk(
|
||||
EsignContract $contract,
|
||||
EsignSigner $signer,
|
||||
bool $smsFallback = true,
|
||||
bool $isReminder = false,
|
||||
): void {
|
||||
try {
|
||||
$member = BarobillMember::where('tenant_id', $contract->tenant_id)->first();
|
||||
if (!$member) {
|
||||
return;
|
||||
}
|
||||
|
||||
$barobill = app(BarobillService::class);
|
||||
$barobill->setServerMode($member->is_test_mode ? 'test' : 'production');
|
||||
|
||||
$signUrl = config('app.url') . '/esign/sign/' . $signer->access_token;
|
||||
$expires = $contract->expires_at?->format('Y-m-d H:i') ?? '없음';
|
||||
|
||||
$templateName = $isReminder ? '전자계약_리마인드' : '전자계약_서명요청';
|
||||
|
||||
$message = $isReminder
|
||||
? "안녕하세요, {$signer->name}님.\n아직 서명이 완료되지 않은 전자계약이 있습니다.\n\n■ 계약명: {$contract->title}\n■ 서명 기한: {$expires}\n\n기한 내에 서명을 완료해 주세요."
|
||||
: "안녕하세요, {$signer->name}님.\n전자계약 서명 요청이 도착했습니다.\n\n■ 계약명: {$contract->title}\n■ 서명 기한: {$expires}\n\n아래 버튼을 눌러 계약서를 확인하고 서명해 주세요.";
|
||||
|
||||
$smsMessage = $smsFallback
|
||||
? "[SAM] {$signer->name}님, 전자계약 서명 요청이 도착했습니다. {$signUrl}"
|
||||
: '';
|
||||
|
||||
$barobill->sendATKakaotalkEx(
|
||||
corpNum: $member->corp_num,
|
||||
certKey: $member->cert_key,
|
||||
senderId: $member->kakaotalk_sender_id ?? '',
|
||||
templateName: $templateName,
|
||||
receiverName: $signer->name,
|
||||
receiverNum: preg_replace('/[^0-9]/', '', $signer->phone),
|
||||
title: $isReminder ? '전자계약 리마인드' : '전자계약 서명 요청',
|
||||
message: $message,
|
||||
buttons: [
|
||||
[
|
||||
'Name' => $isReminder ? '서명하기' : '계약서 확인하기',
|
||||
'ButtonType' => 'WL',
|
||||
'Url1' => $signUrl,
|
||||
'Url2' => $signUrl,
|
||||
],
|
||||
],
|
||||
smsMessage: $smsMessage,
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
\Log::warning('E-Sign 알림톡 발송 실패', [
|
||||
'contract_id' => $contract->id,
|
||||
'signer_id' => $signer->id,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PDF 다운로드
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user