관리자 환경설정에서 미입금 자동취소 기한을 저장하면 HTML number 입력의 문자열이 그대로 영속되고, Carbon 3.13 의 strict 타입 경계에서 TypeError 가 발생해 무통장입금·가상계좌 주문이 전면 실패했다(공개 제보). 한 곳만 막으면 다른 저장 경로가 남으므로 저장·조회·소비·모델 네 계층에 각각 방어를 두고, 저장소 전역에서 같은 형태가 더 없음을 audit 룰로 확정했다. 같은 계획서 수행 중 드러난 인접 결함도 함께 해소했다. - 쿠폰 수정 경로로 (발급일 기준, 일수 NULL) 조합이 저장되어 발급 즉시 만료된 쿠폰이 조용히 나가던 문제 — 저장·발급 양쪽에서 차단 - 리뷰 작성 기한을 화면과 저장 판정이 서로 다른 기준으로 계산하던 문제 - 결제 플러그인이 PaymentMethodEnum 과 다른 어휘로 지원 결제수단을 선언해 가상계좌·계좌이체·휴대폰결제에 PG사를 지정할 수 없던 문제 엔진에서는 `_localInit` 적용 여부를 전역 해시로만 판정해 인스턴스별 저장소가 리셋되지 않던 결함(engine-v1.54.5)과, 제거 대상이 없어도 상태 갱신·캐시 무효화가 상시 발생하던 판정 결함(engine-v1.54.6)을 고쳤다. Playwright MCP 정밀 점검(T1~T11)에서 설정이 빈 문자열로 남은 사이트의 주문서 입금기한 안내가 미치환 플레이스홀더를 노출하는 것을 실측해, 화면 폴백을 서버와 같은 규칙으로 맞췄다.
126 lines
5.0 KiB
PHP
126 lines
5.0 KiB
PHP
<?php
|
|
|
|
namespace Modules\Sirsoft\Ecommerce\Tests\Unit\Services;
|
|
|
|
use Modules\Sirsoft\Ecommerce\Enums\PaymentMethodEnum;
|
|
use Modules\Sirsoft\Ecommerce\Tests\ModuleTestCase;
|
|
|
|
/**
|
|
* PG 플러그인이 선언하는 supported_methods 어휘 정합 테스트
|
|
*
|
|
* 관리자 결제수단 설정의 PG사 드롭다운은 `supported_methods.includes($method.id)` 로
|
|
* 후보를 거른다. 즉 PG 플러그인이 선언하는 값은 반드시 **결제수단 id 어휘**여야 한다.
|
|
* 다른 어휘(예: 'virtual_account')로 선언하면 교집합이 비어 드롭다운이 영구히 `---` 만
|
|
* 노출되고, 그 결제수단은 기본 PG사 상속 외에는 PG를 지정할 수 없게 된다.
|
|
* 백엔드는 결제수단별 pg_provider 를 실제로 사용하므로(OrderProcessingService 의
|
|
* `$methodConfig['pg_provider'] ?? default_pg_provider`) 이는 기능 손실이다.
|
|
*
|
|
* 어휘 목록을 손으로 열거하면 플러그인이 늘어날 때 누락되므로, 저장소의 PG 플러그인
|
|
* 선언을 전수 스캔해 검증한다.
|
|
*
|
|
* @effects pg_supported_methods_use_payment_method_vocabulary
|
|
*/
|
|
class PgProviderSupportedMethodsVocabularyTest extends ModuleTestCase
|
|
{
|
|
/**
|
|
* 저장소의 모든 PG 플러그인에서 supported_methods 선언을 수집합니다.
|
|
*
|
|
* @return array<string, array<int, string>> 파일 경로 => 선언된 결제수단 값 목록
|
|
*/
|
|
private function collectDeclarations(): array
|
|
{
|
|
$roots = [base_path('plugins/_bundled'), base_path('plugins')];
|
|
$found = [];
|
|
|
|
foreach ($roots as $root) {
|
|
if (! is_dir($root)) {
|
|
continue;
|
|
}
|
|
|
|
$it = new \RecursiveIteratorIterator(
|
|
new \RecursiveDirectoryIterator($root, \FilesystemIterator::SKIP_DOTS)
|
|
);
|
|
|
|
foreach ($it as $file) {
|
|
if (! $file->isFile() || $file->getExtension() !== 'php') {
|
|
continue;
|
|
}
|
|
|
|
$contents = file_get_contents($file->getPathname());
|
|
if ($contents === false || ! str_contains($contents, 'supported_methods')) {
|
|
continue;
|
|
}
|
|
|
|
if (! preg_match("/'supported_methods'\s*=>\s*\[(.*?)\]/s", $contents, $m)) {
|
|
continue;
|
|
}
|
|
|
|
preg_match_all("/'([^']+)'/", $m[1], $values);
|
|
if ($values[1] !== []) {
|
|
// 활성 디렉토리와 _bundled 중복 수집을 피하기 위해 상대 경로 키를 정규화한다.
|
|
$key = str_replace('\\', '/', $file->getPathname());
|
|
$found[$key] = $values[1];
|
|
}
|
|
}
|
|
}
|
|
|
|
return $found;
|
|
}
|
|
|
|
public function test_declared_supported_methods_use_payment_method_ids(): void
|
|
{
|
|
$declarations = $this->collectDeclarations();
|
|
|
|
$this->assertNotEmpty(
|
|
$declarations,
|
|
'PG 플러그인의 supported_methods 선언을 하나도 찾지 못했습니다 (테스트 전제 붕괴 — 스캔 경로/패턴 확인 필요).'
|
|
);
|
|
|
|
$known = array_map(
|
|
static fn (PaymentMethodEnum $case): string => $case->value,
|
|
PaymentMethodEnum::cases()
|
|
);
|
|
|
|
$violations = [];
|
|
foreach ($declarations as $path => $methods) {
|
|
foreach ($methods as $method) {
|
|
if (! in_array($method, $known, true)) {
|
|
$violations[] = sprintf('%s → %s', $path, $method);
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->assertSame(
|
|
[],
|
|
$violations,
|
|
"PG 플러그인이 결제수단 id 가 아닌 어휘를 선언했습니다.\n".
|
|
"이 값은 관리자 PG 드롭다운 필터(`supported_methods.includes(method.id)`)와 직접 대조되므로,\n".
|
|
"어휘가 어긋나면 해당 결제수단은 PG를 지정할 수 없습니다.\n".
|
|
'허용 어휘: '.implode(', ', $known)."\n위반:\n ".implode("\n ", $violations)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* PG 가 필요한 결제수단이 최소 한 곳의 PG 플러그인에서 지원 선언되어야,
|
|
* 관리자 화면에서 그 결제수단에 PG를 지정할 수 있다.
|
|
*/
|
|
public function test_pg_requiring_builtin_methods_are_covered_by_some_provider(): void
|
|
{
|
|
$declared = [];
|
|
foreach ($this->collectDeclarations() as $methods) {
|
|
foreach ($methods as $m) {
|
|
$declared[$m] = true;
|
|
}
|
|
}
|
|
|
|
// 무통장입금(dbank)·포인트·예치금·무료는 PG 불필요라 대상이 아니다.
|
|
foreach ([PaymentMethodEnum::CARD, PaymentMethodEnum::VBANK, PaymentMethodEnum::BANK, PaymentMethodEnum::PHONE] as $case) {
|
|
$this->assertArrayHasKey(
|
|
$case->value,
|
|
$declared,
|
|
"결제수단 '{$case->value}' 를 지원한다고 선언한 PG 플러그인이 없습니다 → 관리자 화면에서 PG 지정 불가."
|
|
);
|
|
}
|
|
}
|
|
}
|