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('{{'); });