fix:E-Sign 알림톡 certKey 버그 수정 및 발송 상태 추적 기능 추가
- sendATKakaotalkEx() 호출 시 존재하지 않는 certKey 파라미터 제거 (TypeError 버그) - sendAlimtalk/dispatchNotification 결과 반환 (void → array) - send/remind 응답에 notification_results 포함 - 감사 로그 metadata에 서명자별 알림 발송 결과 저장 - EsignPublicController 다음 서명자/완료 알림에도 동일 수정 적용 - detail.blade.php: 발송 방식 배지, 서명자 연락처, 알림 오류 배너, 활동 로그 발송 결과 표시 - send.blade.php: 발송 후 알림 실패 시 경고 메시지 표시 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -712,9 +712,15 @@ public function send(Request $request, int $id): JsonResponse
|
||||
$targetSigners = $first ? collect([$first]) : collect();
|
||||
}
|
||||
|
||||
$notificationResults = [];
|
||||
foreach ($targetSigners as $signer) {
|
||||
$signer->update(['status' => 'notified']);
|
||||
$this->dispatchNotification($contract, $signer, $sendMethod, $smsFallback);
|
||||
$results = $this->dispatchNotification($contract, $signer, $sendMethod, $smsFallback);
|
||||
$notificationResults[] = [
|
||||
'signer_id' => $signer->id,
|
||||
'signer_name' => $signer->name,
|
||||
'results' => $results,
|
||||
];
|
||||
}
|
||||
|
||||
EsignAuditLog::create([
|
||||
@@ -723,11 +729,34 @@ 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(), 'send_method' => $sendMethod],
|
||||
'metadata' => [
|
||||
'sent_by' => auth()->id(),
|
||||
'send_method' => $sendMethod,
|
||||
'notification_results' => $notificationResults,
|
||||
],
|
||||
'created_at' => now(),
|
||||
]);
|
||||
|
||||
return response()->json(['success' => true, 'message' => '서명 요청이 발송되었습니다.']);
|
||||
// 실패한 알림 확인
|
||||
$failures = [];
|
||||
foreach ($notificationResults as $nr) {
|
||||
foreach ($nr['results'] as $r) {
|
||||
if (!$r['success']) {
|
||||
$failures[] = "{$nr['signer_name']}: {$r['channel']} 실패 ({$r['error']})";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$message = '서명 요청이 발송되었습니다.';
|
||||
if (!empty($failures)) {
|
||||
$message .= ' (일부 알림 실패: ' . implode(', ', $failures) . ')';
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => $message,
|
||||
'notification_results' => $notificationResults,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -748,14 +777,20 @@ public function remind(Request $request, int $id): JsonResponse
|
||||
->orderBy('sign_order')
|
||||
->first();
|
||||
|
||||
$notificationResults = [];
|
||||
if ($nextSigner) {
|
||||
$nextSigner->update(['status' => 'notified']);
|
||||
$this->dispatchNotification(
|
||||
$results = $this->dispatchNotification(
|
||||
$contract, $nextSigner,
|
||||
$contract->send_method ?? 'alimtalk',
|
||||
$contract->sms_fallback ?? true,
|
||||
isReminder: true,
|
||||
);
|
||||
$notificationResults[] = [
|
||||
'signer_id' => $nextSigner->id,
|
||||
'signer_name' => $nextSigner->name,
|
||||
'results' => $results,
|
||||
];
|
||||
}
|
||||
|
||||
EsignAuditLog::create([
|
||||
@@ -767,15 +802,32 @@ public function remind(Request $request, int $id): JsonResponse
|
||||
'metadata' => [
|
||||
'reminded_by' => auth()->id(),
|
||||
'target_signer_id' => $nextSigner?->id,
|
||||
'notification_results' => $notificationResults,
|
||||
],
|
||||
'created_at' => now(),
|
||||
]);
|
||||
|
||||
// 실패 확인
|
||||
$failures = [];
|
||||
foreach ($notificationResults as $nr) {
|
||||
foreach ($nr['results'] as $r) {
|
||||
if (!$r['success']) {
|
||||
$failures[] = "{$r['channel']} 실패 ({$r['error']})";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$message = $nextSigner
|
||||
? "{$nextSigner->name}에게 리마인더가 발송되었습니다."
|
||||
: '리마인더가 기록되었습니다.';
|
||||
if (!empty($failures)) {
|
||||
$message .= ' (일부 알림 실패: ' . implode(', ', $failures) . ')';
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => $nextSigner
|
||||
? "{$nextSigner->name}에게 리마인더가 발송되었습니다."
|
||||
: '리마인더가 기록되었습니다.',
|
||||
'message' => $message,
|
||||
'notification_results' => $notificationResults,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -788,18 +840,32 @@ private function dispatchNotification(
|
||||
string $sendMethod,
|
||||
bool $smsFallback,
|
||||
bool $isReminder = false,
|
||||
): void {
|
||||
): array {
|
||||
$results = [];
|
||||
|
||||
// 알림톡 발송
|
||||
if (in_array($sendMethod, ['alimtalk', 'both']) && $signer->phone) {
|
||||
$this->sendAlimtalk($contract, $signer, $smsFallback, $isReminder);
|
||||
$results[] = $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));
|
||||
try {
|
||||
Mail::to($signer->email)->send(new EsignRequestMail($contract, $signer, $isReminder));
|
||||
$results[] = ['success' => true, 'channel' => 'email', 'error' => null];
|
||||
} catch (\Throwable $e) {
|
||||
\Log::warning('E-Sign 이메일 발송 실패', [
|
||||
'contract_id' => $contract->id,
|
||||
'signer_id' => $signer->id,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
$results[] = ['success' => false, 'channel' => 'email', 'error' => $e->getMessage()];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -810,11 +876,11 @@ private function sendAlimtalk(
|
||||
EsignSigner $signer,
|
||||
bool $smsFallback = true,
|
||||
bool $isReminder = false,
|
||||
): void {
|
||||
): array {
|
||||
try {
|
||||
$member = BarobillMember::where('tenant_id', $contract->tenant_id)->first();
|
||||
if (!$member) {
|
||||
return;
|
||||
return ['success' => false, 'channel' => 'alimtalk', 'error' => '바로빌 회원 미등록'];
|
||||
}
|
||||
|
||||
$barobill = app(BarobillService::class);
|
||||
@@ -833,9 +899,8 @@ private function sendAlimtalk(
|
||||
? "[SAM] {$signer->name}님, 전자계약 서명 요청이 도착했습니다. {$signUrl}"
|
||||
: '';
|
||||
|
||||
$barobill->sendATKakaotalkEx(
|
||||
$result = $barobill->sendATKakaotalkEx(
|
||||
corpNum: $member->corp_num,
|
||||
certKey: $member->cert_key,
|
||||
senderId: $member->kakaotalk_sender_id ?? '',
|
||||
templateName: $templateName,
|
||||
receiverName: $signer->name,
|
||||
@@ -852,12 +917,24 @@ private function sendAlimtalk(
|
||||
],
|
||||
smsMessage: $smsMessage,
|
||||
);
|
||||
|
||||
if (!($result['success'] ?? false)) {
|
||||
\Log::warning('E-Sign 알림톡 발송 실패', [
|
||||
'contract_id' => $contract->id,
|
||||
'signer_id' => $signer->id,
|
||||
'error' => $result['error'] ?? 'Unknown error',
|
||||
]);
|
||||
return ['success' => false, 'channel' => 'alimtalk', 'error' => $result['error'] ?? 'API 호출 실패'];
|
||||
}
|
||||
|
||||
return ['success' => true, 'channel' => 'alimtalk', 'error' => null];
|
||||
} catch (\Throwable $e) {
|
||||
\Log::warning('E-Sign 알림톡 발송 실패', [
|
||||
'contract_id' => $contract->id,
|
||||
'signer_id' => $signer->id,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
return ['success' => false, 'channel' => 'alimtalk', 'error' => $e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user