diff --git a/plugins/_bundled/sirsoft-pay_kginicis/CHANGELOG.md b/plugins/_bundled/sirsoft-pay_kginicis/CHANGELOG.md index 81201e91..960e770b 100644 --- a/plugins/_bundled/sirsoft-pay_kginicis/CHANGELOG.md +++ b/plugins/_bundled/sirsoft-pay_kginicis/CHANGELOG.md @@ -23,6 +23,7 @@ ### Fixed - 일본 편의점결제(CVS) 관련 안내 메시지가 번역되지 않고 내부 코드 그대로 표시되던 문제를 수정했습니다. 주문을 찾을 수 없거나 입금 통보 테스트·입금기한 만료 처리를 할 때 정상적인 한국어(영어) 안내가 표시됩니다. +- 일본(CBT) 설정을 운영 모드로 전환할 때 상점 정보나 서명키가 비어 있어도 저장되던 문제를 수정했습니다. 필수값이 비었거나 샘플값이 그대로면 저장이 중단되고 안내 메시지가 표시됩니다. - 이 플러그인이 설치된 사이트에서 관리자 주문 목록의 '일부취소' 표시와 적립예정 포인트·마일리지 사용 금액, 주문상품의 추가옵션 요약이 보이지 않던 문제를 수정했습니다. 결제 정보 칸에 테스트결제 표시를 덧붙이는 과정에서 목록 표 구성 전체를 옛 버전으로 되돌려 놓고 있었습니다. - 관리자 결제수단 설정에서 가상계좌·계좌이체·휴대폰결제에 PG사를 지정할 수 없던 문제를 수정했습니다. 해당 결제수단의 PG사 목록이 항상 비어 있어 기본 PG사만 사용할 수 있었고, 결제수단별로 다른 PG사를 지정하는 설정이 화면에서 불가능했습니다. - 카드결제를 거치지 않은 주문(무통장입금 등)의 완료 화면에서도 영수증 조회를 시도해 불필요한 요청이 나가던 문제를 수정했습니다. 화면에는 영향이 없었으나 이제 카드결제 주문에서만 조회합니다. (#81 @jiwonpapa 님께서 제보해주셨습니다.) diff --git a/plugins/_bundled/sirsoft-pay_kginicis/src/Listeners/ValidateCbtSettingsListener.php b/plugins/_bundled/sirsoft-pay_kginicis/src/Listeners/ValidateCbtSettingsListener.php index 67b49b40..d20a950e 100644 --- a/plugins/_bundled/sirsoft-pay_kginicis/src/Listeners/ValidateCbtSettingsListener.php +++ b/plugins/_bundled/sirsoft-pay_kginicis/src/Listeners/ValidateCbtSettingsListener.php @@ -38,19 +38,39 @@ class ValidateCbtSettingsListener implements HookListenerInterface private const SAMPLE_VALUE_ERROR_FIELD = 'japan_contract_info'; + /** + * 구독할 훅 매핑 반환. + * + * @return array> + */ public static function getSubscribedHooks(): array { return [ 'core.plugin_settings.before_save' => [ 'method' => 'validateBeforeSave', 'priority' => 10, + // 저장을 차단하는 인라인 가드 — Action 훅 기본값(큐 디스패치)이면 ValidationException 이 + // 워커 안에서 죽고 PluginSettingsService::save() 가 저장을 그대로 진행한다. 'sync' => true, ], ]; } + /** + * 기본 핸들러 (미사용). + * + * @param mixed ...$args + */ public function handle(...$args): void {} + /** + * 설정 저장 전 CBT(일본) 필수값 검증. 위반 시 ValidationException 으로 422 응답을 유도한다. + * + * @param string $identifier 저장 대상 플러그인 식별자 + * @param array $settings 저장 요청 설정값 + * + * @throws ValidationException 라이브 모드 필수값이 비었거나 샘플값이 그대로일 때 + */ public function validateBeforeSave(string $identifier, array $settings): void { if ($identifier !== self::PLUGIN_IDENTIFIER) { diff --git a/plugins/_bundled/sirsoft-pay_kginicis/tests/Unit/Listeners/ValidateCbtSettingsListenerTest.php b/plugins/_bundled/sirsoft-pay_kginicis/tests/Unit/Listeners/ValidateCbtSettingsListenerTest.php index 69fd4d4f..e39c5334 100644 --- a/plugins/_bundled/sirsoft-pay_kginicis/tests/Unit/Listeners/ValidateCbtSettingsListenerTest.php +++ b/plugins/_bundled/sirsoft-pay_kginicis/tests/Unit/Listeners/ValidateCbtSettingsListenerTest.php @@ -2,7 +2,10 @@ namespace Plugins\Sirsoft\PayKginicis\Tests\Unit\Listeners; +use App\Extension\HookListenerRegistrar; +use App\Extension\HookManager; use App\Services\PluginSettingsService; +use Illuminate\Support\Facades\Queue; use Illuminate\Validation\ValidationException; use Plugins\Sirsoft\PayKginicis\Listeners\ValidateCbtSettingsListener; use Plugins\Sirsoft\PayKginicis\Plugin; @@ -100,6 +103,36 @@ class ValidateCbtSettingsListenerTest extends PluginTestCase ]); } + /** + * 훅 디스패치 경로를 실제로 통과시켜 예외가 저장 호출자에게 전파되는지 검증한다. + * + * 리스너 메서드를 직접 호출하는 테스트는 이 결함을 잡지 못한다 — Action 훅의 기본값은 + * 큐 디스패치이고, 'sync' => true 가 없으면 ValidationException 이 워커 안에서 죽어 + * PluginSettingsService::save() 가 doAction 직후 저장을 그대로 진행한다. + * + * phpunit.xml 은 QUEUE_CONNECTION=sync 라 큐 경로도 즉시 실행되어 결함이 가려진다. + * Queue::fake() 로 운영(database 드라이버)과 같은 비동기 상황을 만들어야 가드가 성립한다. + */ + public function test_validation_exception_propagates_through_the_hook_chain(): void + { + Queue::fake(); + + $this->mockCurrentSettings([]); + + HookManager::clearAction('core.plugin_settings.before_save'); + HookListenerRegistrar::clear(); + HookListenerRegistrar::register(ValidateCbtSettingsListener::class, 'test'); + + $this->expectException(ValidationException::class); + + HookManager::doAction('core.plugin_settings.before_save', 'sirsoft-pay_kginicis', [ + 'japan_enabled' => true, + 'is_test_mode' => false, + 'live_japan_mid' => '', + 'live_japan_sign_key' => '', + ]); + } + public function test_backend_settings_validation_messages_are_localized(): void { $this->mockCurrentSettings([]); diff --git a/plugins/_bundled/sirsoft-tosspayments/src/Listeners/ValidateTossSettingsListener.php b/plugins/_bundled/sirsoft-tosspayments/src/Listeners/ValidateTossSettingsListener.php index cb95ca42..bea39fb7 100644 --- a/plugins/_bundled/sirsoft-tosspayments/src/Listeners/ValidateTossSettingsListener.php +++ b/plugins/_bundled/sirsoft-tosspayments/src/Listeners/ValidateTossSettingsListener.php @@ -40,6 +40,9 @@ class ValidateTossSettingsListener implements HookListenerInterface 'core.plugin_settings.before_save' => [ 'method' => 'validateBeforeSave', 'priority' => 10, + // 저장을 차단하는 인라인 가드 — Action 훅 기본값(큐 디스패치)이면 ValidationException 이 + // 워커 안에서 죽고 PluginSettingsService::save() 가 저장을 그대로 진행한다. + 'sync' => true, ], ]; } diff --git a/plugins/_bundled/sirsoft-tosspayments/tests/Unit/Listeners/ValidateTossSettingsListenerTest.php b/plugins/_bundled/sirsoft-tosspayments/tests/Unit/Listeners/ValidateTossSettingsListenerTest.php index 56394bd7..b03a67fe 100644 --- a/plugins/_bundled/sirsoft-tosspayments/tests/Unit/Listeners/ValidateTossSettingsListenerTest.php +++ b/plugins/_bundled/sirsoft-tosspayments/tests/Unit/Listeners/ValidateTossSettingsListenerTest.php @@ -4,6 +4,9 @@ declare(strict_types=1); namespace Plugins\Sirsoft\Tosspayments\Tests\Unit\Listeners; +use App\Extension\HookListenerRegistrar; +use App\Extension\HookManager; +use Illuminate\Support\Facades\Queue; use Illuminate\Validation\ValidationException; use Plugins\Sirsoft\Tosspayments\Listeners\ValidateTossSettingsListener; use Plugins\Sirsoft\Tosspayments\Plugin; @@ -40,6 +43,33 @@ class ValidateTossSettingsListenerTest extends PluginTestCase $this->addToAssertionCount(1); } + /** + * 훅 디스패치 경로를 실제로 통과시켜 예외가 저장 호출자에게 전파되는지 검증한다. + * + * 리스너 메서드를 직접 호출하는 테스트는 이 결함을 잡지 못한다 — Action 훅의 기본값은 + * 큐 디스패치이고, 'sync' => true 가 없으면 ValidationException 이 워커 안에서 죽어 + * PluginSettingsService::save() 가 doAction 직후 저장을 그대로 진행한다. + * + * phpunit.xml 은 QUEUE_CONNECTION=sync 라 큐 경로도 즉시 실행되어 결함이 가려진다. + * Queue::fake() 로 운영(database 드라이버)과 같은 비동기 상황을 만들어야 가드가 성립한다. + */ + public function test_validation_exception_propagates_through_the_hook_chain(): void + { + Queue::fake(); + + HookManager::clearAction('core.plugin_settings.before_save'); + HookListenerRegistrar::clear(); + HookListenerRegistrar::register(ValidateTossSettingsListener::class, 'test'); + + $this->expectException(ValidationException::class); + + HookManager::doAction( + 'core.plugin_settings.before_save', + 'sirsoft-tosspayments', + ['vbank_valid_hours' => 9999], + ); + } + /** * @return array */