b6a15c5bbf7bbdcad9b25682a45f7784b0bbbd81
2 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
6704054a80 |
fix(смс-клиент): приёмка Этапа 3 — служебная роль получила права, экран перестал врать
Этап 3 «Время и цена», Task 8 — приёмка. Строка листа Н.2 (проверка разграничения доступа), итоговая таблица этапа заполнена. 🔴 Блокер выката, найден проверяющим по доступу и подтверждён лично. Команда добора `client-sms:resume-waiting` (появилась в этом этапе, стоит в расписании каждые 15 минут) ходит в базу под служебной ролью `crm_supplier_worker`: она обходит рассылки ВСЕХ клиентов и потому не может работать под клиентской ролью. Прав этой роли на три таблицы, которые она читает и правит, выдано не было — миграции модуля выдавали права рабочей роли, а служебной только на имя отправителя и правило авто-СМС. Локально этого не видно: dev и тесты ходят суперпользователем. На бою команда падала бы с «нет доступа» каждые 15 минут, и камчатская часть рассылок не дошлалась бы НИКОГДА. Тот же класс, что блокер прав на счётчики 27.07. Добавочная миграция (прежние прод не перезапускает), гард на существование роли, запись схемы v9.15. Сторож прав расширен: он спрашивал базу только про то, что модуль обещал, а обещание было неполным — теперь спрашивает и про эти три таблицы. Две неправды на экране, найденные живым прогоном на НЕудобных данных. · Текст в 2325 символов: сервер отказал (потолок 1000), сметы нет, а строчка под текстом пишет «Умещается в 1 СМС за номер». В коде стояло `preview?.segments ?? 1` — на месте «не знаю» подставлялась единица и утверждалась как факт. Теперь без ответа сервера число СМС не называется вовсе: молчание честнее. Дыра не этого этапа (код от 26.07). · Сам отказ был написан по-программистски: «Количество символов в поле body не может превышать 1000». Стало: «Текст длиннее 1000 символов — сократите его.» Вырезами проверено четыре раза: опечатка в имени роли ВНУТРИ гарда (та самая, что ошибки не даёт и права молча не выдаёт) — сторож краснеет; опечатка в цели GRANT — краснеет; убрал человеческий текст отказа — краснеет; вернул подстановку единицы — краснеет. Всё возвращено. Живой прогон строк 3.1–3.15 подряд (29.07, 06:45–07:00 МСК, песочница, локальная база): камчатский номер ушёл сразу, московский стал ждать 10:00, без региона — ждёт уточнения; экран сказал «Отправлено 1 из 3, 1 ждут утра в своих регионах, ещё 1 — уточняем регион»; команда добора до утра дала 0, после наступления срока 1 и номер ушёл, повторный запуск снова 0; ДаДата (ЗАГЛУШКА, боевой ключ не трогали) спрошена ровно один раз — про тот номер, у которого пояса не было; авто-СМС на московский лид отложена ровно на 10:00, при открытом окне три запуска дали одно сообщение; цена прошла 9.00 → 8.50 → 8.00 по накоплению, у отправленной рассылки осталась 9.00; счётчик сложил 500 из рассылки и 500 из авто-СМС; песочные отправки в счётчик не пошли. Стенд возвращён ровно в исходное: окно 10–20, 0 контактов, 0 сообщений, 0 рассылок, 0 снимков, 5 демо-сделок, кошелёк 1000.00 / заморожено 0.00. Прогоны: СМС 240/240 (11 пачек, все с первой попытки), приём лидов 17/17, фронт 1676 зелёных + 3 пропущенных, phpstan 2 чужие давние, vue-tsc 8 чужих давних (проверено git blame), pint чисто. 🪤 Урок приёмки: мой собственный скрипт прогона отрапортовал «красных пачек нет» и НОЛЬ зелёных — разбирал ответ не в том формате. Ноль почти всегда сбой, а не правда о мире. Теперь скрипт считает зелёным только ответ, где прошедших БОЛЬШЕ НУЛЯ. 🔴 При выкате ветки порядок обязателен: миграции → db/03_service_bypass_policies.sql → контрольный подсчёт политик srv_bypass (должно стать на 8 больше). Эта миграция его НЕ заменяет: без srv_bypass команда добора увидит тихий ноль даже с выданными правами. |
||
|
|
5fd18c35b1 |
feat(смс-клиент): экран объясняет цену и говорит, во сколько рассылка начнётся
Этап 3 «Время и цена», Task 7. Строки листа 3.11, 3.12, 3.13, 3.15. Клиент видел одну цифру — цену за штуку — и не понимал, откуда она взялась и почему завтра будет другой. Теперь смета проговаривает всё вслух: сколько СМС ушло в этом месяце, какая ступень была бы без этого заказа, какая выходит с ним, и что 1-го числа счётчик обнулится. У первой рассылки месяца формулировка другая: сказать новому клиенту «вы были на 9.00 ₽» — неправда, он ни на чём не был (В-115). Отдельно — предупреждение до нажатия кнопки (решение владельца В-86): «Сейчас 21:30 по Москве — рассылка начнётся завтра в 01:00 по Москве». Оба часа приходят С СЕРВЕРА: на компьютере клиента может стоять что угодно, а решение об окне принимает сервер. И всегда сказано, ЧЬЁ это время (В-117): окно 10–20 у получателя местное, и камчатское утро — это час ночи в Москве. Берётся самое раннее утро среди получателей. Про тех, у кого регион ещё не выяснен, экран говорит отдельно: момента начала у них нет вовсе, мы не знаем, когда узнаем регион (В-116). Промолчать было нельзя — человек ждал бы отправки, которой сегодня не будет. Правило часов осталось в одном доме (SmsQuietHours::earliestOpening), формула цены — в своём (ClientSmsPricing::explainFor, счётчик месяца спрашивается один раз на все три числа). Экран по-прежнему ничего не считает сам — ни денег, ни часов. 🔴 Две неправды, которых не видел ни один тест. · Самопроверка diff'а: цена за СМС стояла на экране дважды (В-119). Разойтись эти цифры не могли, но человек читает две одинаковые цены рядом как две разные. Оставил одну — в смете, там, где рядом объяснено, откуда она взялась. · Живой прогон с ДЛИННЫМ текстом вскрыл давнюю, с Этапа 1, нестыковку (В-120): смета писала «Уйдёт 43 СМС — 1462.00 ₽», хотя 43 — это НОМЕРА, а СМС выходило 172. Цифра и сумма в одной строке не сходились между собой, и ни один тест этого не ловил: все брали короткий текст, где числа случайно совпадают. Теперь «Уйдёт на 43 номера — это 172 СМС, 1462.00 ₽», число СМС считает сервер. Починено и в окне подтверждения. Прогоны: СМС 239/239 (пачками по 3–4 файла, В-112), приём лидов 17/17, фронт 1674 зелёных, phpstan 0 своих, pint чисто, проверка типов — 8 чужих давних. Вырезами проверено пять раз: убрал ступень «без заказа» из ответа — покраснел тест 3.12; убрал «окно открыто — значит сразу» — покраснел контрольный «днём начала нет»; взял первое утро вместо самого раннего — покраснел камчатский тест; сделал фразу всегда «вы были» — покраснел тест первой рассылки месяца; показал сноску всегда — покраснел контрольный. Живьём (21:30 МСК, песочница, локальная база): три номера — Москва, Камчатка и один без региона, 99 отправленных СМС в журнале. Экран показал разом все шесть строк. Парные проверки: расширил окно до 23:00 — фраза про час исчезла; обнулил накопленное — цена вернулась к 9.00, фразы про удешевление и сноски не стало; заказ на 172 СМС без накопленного — вторая формулировка про удешевление. Стенд возвращён: окно 10–20, 0 контактов, 0 сообщений, 0 рассылок, 0 снимков. 🪤 Урок про стенд: тестовую базу чинить ТОЛЬКО `migrate:fresh` с чистого листа. `db:wipe --drop-types` + ручной `migrate` оставляют её полумёртвой — чужая миграция чата ломается на недочищенной базе, и дальше все прогоны врут «таблицы не существует». |