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:
@@ -3,6 +3,7 @@
|
||||
namespace App\Http\Controllers\ESign;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Barobill\BarobillMember;
|
||||
use App\Models\ESign\EsignAuditLog;
|
||||
use App\Models\ESign\EsignContract;
|
||||
use App\Models\ESign\EsignSigner;
|
||||
@@ -12,6 +13,7 @@
|
||||
use App\Mail\EsignRequestMail;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use App\Services\Barobill\BarobillService;
|
||||
use App\Services\ESign\PdfSignatureService;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
@@ -305,25 +307,36 @@ public function submitSignature(Request $request, string $token): JsonResponse
|
||||
'created_at' => now(),
|
||||
]);
|
||||
|
||||
// 모든 서명자에게 완료 이메일 발송
|
||||
// 모든 서명자에게 완료 알림 발송
|
||||
$sendMethod = $contract->send_method ?? 'alimtalk';
|
||||
foreach ($allSigners as $completedSigner) {
|
||||
try {
|
||||
Mail::to($completedSigner->email)->send(
|
||||
new EsignCompletedMail($contract, $completedSigner, $allSigners)
|
||||
);
|
||||
// 이메일 발송
|
||||
if (in_array($sendMethod, ['email', 'both']) || !$completedSigner->phone) {
|
||||
if ($completedSigner->email) {
|
||||
Mail::to($completedSigner->email)->send(
|
||||
new EsignCompletedMail($contract, $completedSigner, $allSigners)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 알림톡 발송
|
||||
if (in_array($sendMethod, ['alimtalk', 'both']) && $completedSigner->phone) {
|
||||
$this->sendCompletionAlimtalk($contract, $completedSigner);
|
||||
}
|
||||
|
||||
EsignAuditLog::create([
|
||||
'tenant_id' => $contract->tenant_id,
|
||||
'contract_id' => $contract->id,
|
||||
'signer_id' => $completedSigner->id,
|
||||
'action' => 'completion_email_sent',
|
||||
'action' => 'completion_notification_sent',
|
||||
'ip_address' => $request->ip(),
|
||||
'user_agent' => $request->userAgent(),
|
||||
'metadata' => ['email' => $completedSigner->email],
|
||||
'metadata' => ['send_method' => $sendMethod],
|
||||
'created_at' => now(),
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('계약 완료 이메일 발송 실패', [
|
||||
Log::error('계약 완료 알림 발송 실패', [
|
||||
'contract_id' => $contract->id,
|
||||
'signer_id' => $completedSigner->id,
|
||||
'error' => $e->getMessage(),
|
||||
@@ -342,7 +355,42 @@ public function submitSignature(Request $request, string $token): JsonResponse
|
||||
|
||||
if ($nextSigner) {
|
||||
$nextSigner->update(['status' => 'notified']);
|
||||
Mail::to($nextSigner->email)->send(new EsignRequestMail($contract, $nextSigner));
|
||||
$nextSendMethod = $contract->send_method ?? 'alimtalk';
|
||||
$nextSmsFallback = $contract->sms_fallback ?? true;
|
||||
|
||||
// 알림톡 발송
|
||||
if (in_array($nextSendMethod, ['alimtalk', 'both']) && $nextSigner->phone) {
|
||||
try {
|
||||
$member = BarobillMember::where('tenant_id', $contract->tenant_id)->first();
|
||||
if ($member) {
|
||||
$barobill = app(BarobillService::class);
|
||||
$barobill->setServerMode($member->is_test_mode ? 'test' : 'production');
|
||||
$nextSignUrl = config('app.url') . '/esign/sign/' . $nextSigner->access_token;
|
||||
$nextExpires = $contract->expires_at?->format('Y-m-d H:i') ?? '없음';
|
||||
$barobill->sendATKakaotalkEx(
|
||||
corpNum: $member->corp_num,
|
||||
certKey: $member->cert_key,
|
||||
senderId: $member->kakaotalk_sender_id ?? '',
|
||||
templateName: '전자계약_서명요청',
|
||||
receiverName: $nextSigner->name,
|
||||
receiverNum: preg_replace('/[^0-9]/', '', $nextSigner->phone),
|
||||
title: '전자계약 서명 요청',
|
||||
message: "안녕하세요, {$nextSigner->name}님.\n전자계약 서명 요청이 도착했습니다.\n\n■ 계약명: {$contract->title}\n■ 서명 기한: {$nextExpires}\n\n아래 버튼을 눌러 계약서를 확인하고 서명해 주세요.",
|
||||
buttons: [['Name' => '계약서 확인하기', 'ButtonType' => 'WL', 'Url1' => $nextSignUrl, 'Url2' => $nextSignUrl]],
|
||||
smsMessage: $nextSmsFallback ? "[SAM] {$nextSigner->name}님, 전자계약 서명 요청이 도착했습니다. {$nextSignUrl}" : '',
|
||||
);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('다음 서명자 알림톡 발송 실패', ['error' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
// 이메일 발송
|
||||
if (in_array($nextSendMethod, ['email', 'both']) || ($nextSendMethod === 'alimtalk' && !$nextSigner->phone)) {
|
||||
if ($nextSigner->email) {
|
||||
Mail::to($nextSigner->email)->send(new EsignRequestMail($contract, $nextSigner));
|
||||
}
|
||||
}
|
||||
|
||||
EsignAuditLog::create([
|
||||
'tenant_id' => $contract->tenant_id,
|
||||
@@ -436,6 +484,50 @@ public function downloadDocument(string $token): StreamedResponse|JsonResponse
|
||||
|
||||
// ─── Private ───
|
||||
|
||||
private function sendCompletionAlimtalk(EsignContract $contract, EsignSigner $signer): 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;
|
||||
$completedAt = $contract->completed_at?->format('Y-m-d H:i') ?? now()->format('Y-m-d H:i');
|
||||
|
||||
$barobill->sendATKakaotalkEx(
|
||||
corpNum: $member->corp_num,
|
||||
certKey: $member->cert_key,
|
||||
senderId: $member->kakaotalk_sender_id ?? '',
|
||||
templateName: '전자계약_완료',
|
||||
receiverName: $signer->name,
|
||||
receiverNum: preg_replace('/[^0-9]/', '', $signer->phone),
|
||||
title: '전자계약 완료',
|
||||
message: "안녕하세요, {$signer->name}님.\n전자계약이 모든 서명자의 서명 완료로 확정되었습니다.\n\n■ 계약명: {$contract->title}\n■ 완료일: {$completedAt}\n\n아래 버튼에서 서명 완료된 계약서를 확인할 수 있습니다.",
|
||||
buttons: [
|
||||
[
|
||||
'Name' => '계약서 확인하기',
|
||||
'ButtonType' => 'WL',
|
||||
'Url1' => $signUrl,
|
||||
'Url2' => $signUrl,
|
||||
],
|
||||
],
|
||||
smsMessage: ($contract->sms_fallback ?? true)
|
||||
? "[SAM] {$signer->name}님, 전자계약이 완료되었습니다. {$signUrl}"
|
||||
: '',
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('E-Sign 완료 알림톡 발송 실패', [
|
||||
'contract_id' => $contract->id,
|
||||
'signer_id' => $signer->id,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function findSigner(string $token): ?EsignSigner
|
||||
{
|
||||
$signer = EsignSigner::withoutGlobalScopes()
|
||||
|
||||
Reference in New Issue
Block a user