Дмитрий
643e1a5dcf
fix(supplier): refresh-session.js — устранена гонка Promise.all/click
...
Логин-страница уже в состоянии networkidle → waitForLoadState резолвился
мгновенно (до пост-логин редиректа), скрипт хватал PHPSESSID
неаутентифицированной логин-страницы. CSV-сверка 11:00 (19.05) упала
"load-reports returned non-array response" — портал отдал HTTP 200
+ HTML логин-страницы вместо JSON-массива отчётов.
После клика submit:
- waitForFunction опрашивает исчезновение #loginform-username из DOM
(переживает навигацию);
- guard exit 1, если форма осталась — отклонённый логин больше не
маскируется под «успех» (exit 0).
Verified: 2× RefreshSupplierSessionJob → валидная сессия (load-reports
JSON-массив из 39 отчётов); CsvReconcileJob id=7 status=ok.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-19 15:26:39 +03:00
Дмитрий
0f6f38a70e
@
...
fix(supplier): реальные endpoint'ы отчёта «Запрос номеров» (discovery T3)
Discovery T3 на живом supplier-портале crm.bp-gr.ru (Playwright MCP)
вскрыл фактические endpoint'ы вместо placeholder'ов из spec §4.3:
- POST /admin/report/save-report (JSON body, selectType=49 + reportFilter)
— возвращает строку "OK", не JSON с id;
- GET /admin/report/load-reports — массив отчётов, id извлекается
title-match'ем «Запрос номеров с {from} по {to}»;
- GET /admin/report/getfile?id=N — 302 redirect на отдельный
download-host (oki.needcallbuy.ru), Laravel HTTP follows redirect.
SupplierPortalClient: requestNumbersReport/waitReportReady/downloadReport
переписаны под реальный контракт; request() +параметр asJson;
connectTimeout(30)+timeout(60) против flaky DNS resolve.
refresh-session.js: селекторы login-формы Yii2 — placeholder
input[name=login] → реальные #loginform-username/-password.
Тесты SupplierPortalClientReportTest + CsvReconcileJobTest адаптированы
под новый внутренний контракт. Pest 15/15, Larastan 0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
@
2026-05-19 07:42:12 +03:00
Дмитрий
f298984055
feat(supplier): Plan 3 Task 5 — RefreshSupplierSessionJob + PlaywrightBridge
...
Компоненты:
- app/playwright/{package.json, refresh-session.js} — изолированный Node.js
+ Playwright chromium subprocess для headless логина
- PlaywrightProcessHandle interface + SymfonyPlaywrightProcessHandle (prod) +
StubPlaywrightProcessHandle (test) для DI без extending Symfony Process
- ProcessFactory + SymfonyProcessFactory
- PlaywrightBridge: PHP-обёртка, timeout 75s, JSON contract, exit code
→ SupplierAuthException
- RefreshSupplierSessionJob: stub → real (tries=3, backoff [2m/10m/30m],
Cache::lock concurrent guard, Redis TTL 6h)
- supplier:session:refresh Console command
- AppServiceProvider binds ProcessFactory → SymfonyProcessFactory
+7 tests (4 PlaywrightBridge + 2 Job + 1 Command).
NOTE: DOM-селекторы placeholder — финализация после Task 1 discovery.
NOTE: app/playwright/node_modules в .gitignore.
Quirks resolved:
- Mockery::mock(Process::class) + laravel/pao = stream_filter_remove fatal.
Решение: handle interface, pure-PHP test stub без extends Process.
- PHPStan Mockery union types — baseline entries (known Mockery+PHPStan compat).
KNOWN LIMITATION: на этой Windows машине pao stream filter conflict при
serial run SupplierPortalClient+RefreshSupplierSessionJob combo.
Tests pass individually + парами. Production Linux CI не affected.
2026-05-11 06:46:13 +03:00