47afefbb10
Вопрос владельца: «а цены в нём надо актуализировать руками или он сам тянет?»
Ответ был неприятный: руками. Цифры (300/50 руб, тарифные ступени) стояли текстом
в статьях — поменяли бы цену в админке, бот продолжил бы врать про деньги.
Теперь в статьях стоят метки {{цена_подбора}}, {{цена_изучения}}, {{тарифы}},
а сервис LivePrices подставляет живые значения из system_settings и pricing_tiers
В МОМЕНТ ОТВЕТА — без переиндексации базы знаний. Нет цены в настройках — метка
не протекает клиенту, бот отсылает к экрану, где цена написана всегда.
Из текстов экскурсий цифры цен тоже убраны (фронт не знает БД): шаг подсвечивает
строку с ценой в самом окне — она всегда актуальная.
Проверено живьём: поменял цену в настройках на 450 — бот сразу назвал 450.
Pest 42/42 (3 новых теста), Vitest каталога 8/8.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
78 lines
3.3 KiB
PHP
78 lines
3.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Models\KnowledgeChunk;
|
|
use App\Services\Bot\BotAnswerService;
|
|
use App\Services\Bot\LivePrices;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Http;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
/**
|
|
* Цены в инструкции — метками, а не цифрами (вопрос владельца 12.07.2026:
|
|
* «цены надо актуализировать руками или он сам тянет?»). Поменяли цену в админке —
|
|
* бот обязан назвать новую в ту же секунду, без переиндексации базы знаний.
|
|
*/
|
|
beforeEach(function () {
|
|
config()->set('services.yandexgpt', [
|
|
'api_key' => 'k', 'folder_id' => 'f', 'model' => 'yandexgpt-lite/latest',
|
|
'endpoint' => 'https://llm.api.cloud.yandex.net/foundationModels/v1/completion',
|
|
'timeout_seconds' => 8,
|
|
]);
|
|
});
|
|
|
|
function setPrice(string $key, string $value): void
|
|
{
|
|
DB::table('system_settings')->updateOrInsert(
|
|
['key' => $key],
|
|
['value' => $value, 'type' => 'int', 'updated_at' => now()]
|
|
);
|
|
}
|
|
|
|
it('подставляет живую цену сбора и изучения из настроек', function () {
|
|
setPrice('autopodbor_price_search_rub', '450');
|
|
setPrice('autopodbor_price_study_rub', '70');
|
|
|
|
$prices = app(LivePrices::class);
|
|
|
|
expect($prices->substitute('Подбор — {{цена_подбора}}, изучение — {{цена_изучения}}.'))
|
|
->toBe('Подбор — 450 ₽, изучение — 70 ₽.');
|
|
});
|
|
|
|
it('цена изменилась в админке — бот называет новую без переиндексации', function () {
|
|
setPrice('autopodbor_price_search_rub', '300');
|
|
KnowledgeChunk::create([
|
|
'source_path' => 'help/k.md', 'title' => 'Собрать конкурентов', 'tour' => 'collect-competitors',
|
|
'topics' => 'собрать конкурентов, цена подбора', 'chunk_index' => 0,
|
|
'content' => 'Цена — {{цена_подбора}} за подбор. Деньги спишутся только при результате.',
|
|
]);
|
|
|
|
// владелец поднял цену в админке
|
|
setPrice('autopodbor_price_search_rub', '500');
|
|
|
|
Http::fake(['*' => Http::response([
|
|
'result' => ['alternatives' => [['message' => ['text' => 'Подбор стоит 500 ₽.']]]],
|
|
], 200)]);
|
|
|
|
app(BotAnswerService::class)->answer('сколько стоит собрать конкурентов?');
|
|
|
|
Http::assertSent(function ($request) {
|
|
$system = $request['messages'][0]['text'];
|
|
|
|
// В ИИ уходит живая цена, а не старая и не сама метка.
|
|
return str_contains($system, '500 ₽')
|
|
&& ! str_contains($system, '300 ₽')
|
|
&& ! str_contains($system, '{{');
|
|
});
|
|
});
|
|
|
|
it('цены нет в настройках — метка не протекает клиенту', function () {
|
|
DB::table('system_settings')->where('key', 'autopodbor_price_search_rub')->delete();
|
|
|
|
expect(app(LivePrices::class)->substitute('Цена — {{цена_подбора}}.'))
|
|
->not->toContain('{{');
|
|
});
|