feat: Коммерческий аукцион (#179) + бейджи пользователей#199
Merged
Conversation
Аддитивные миграции и поля моделей для двухэтапной процедуры «Коммерческий аукцион». Стандартные RFQ/аукционы не затрагиваются (procedure='standard' по умолчанию, все новые колонки nullable). - rfqs: procedure, trading_start/end, step_*, max_deadline/advance, linked_auction_id. - auctions: procedure, rfq_id, weight_*, step_*, max_*, best_bid_id. - auction_bids: deadline, advance_percent, score_*, total_score, is_base, became_best_at; type расширен значением 'offer' (pgsql — пересоздание CHECK, sqlite — перестройка колонки). - Модели: isCommercial(), linkedAuction()/rfq()/bestBid()/offerBids()/ baseBids()/bestOfferHistory(), isOffer(), fillable/casts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CommercialAuctionScoringService — фиксированная линейная нормировка от максимумов-референсов (единая для цены/срока/аванса, 0..100), взвешенный итог, проверка «строго лучше» (непрерывное лидерство), пер-критерий анализ с зелёной «Лучший критерий» и замкнутым порогом «Уменьшите до X». 9 юнит-тестов (без БД): нормировка, ручной расчёт баллов, wouldBeat, инверсия порога (подстановка даёт цель), зелёная метка, дефицит. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ce 3) - StoreRfqRequest: procedure + поля этапа 2 (trading_start/end, step_*, max_deadline/advance) обязательны при procedure=commercial. - RfqController::store: сохраняет параметры этапа 2; storeBid на этапе 1 коммерческого RFQ валидирует и хранит только цену (срок/аванс = null). - Миграция: rfq_bids.deadline/advance_percent → nullable. - rfqs/create: переключатель «Запрос цен / Коммерческий аукцион» + секция параметров этапа 2 (Alpine x-show). - rfqs/show: форма заявки этапа 1 скрывает срок/аванс для commercial. - 4 feature-теста (создание, обязательность полей, standard без этапа 2, заявка «только цена»). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- CommercialAuctionLauncherService: по закрытию этапа 1 создаёт связанный аукцион (НМЦ = макс. цена этапа 1, перенос весов/шагов/референсов, приглашает всех участников, статус trading). Идемпотентно; без участников — процедура несостоялась. - CloseRfqJob: для commercial пропускает скоринг/победителя/протокол, вызывает launcher и закрывает этап 1. - AuctionWinnerService::determineWinner: для commercial победитель = лучшее предложение (best_bid_id). - UpdateAuctionStatuses: commercial стартует сразу в trading (исключён из active→trading и idle-правил); закрывается по trading_end. - 4 feature-теста. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- StoreCommercialOfferRequest + AuctionController::storeOffer: подача предложения (3 критерия) с lockForUpdate, проверкой строгого превосходства, is_base, обновлением best_bid_id/last_bid_at. Отклонение с дефицитом баллов; проверки участника/верификации/пределов. - getState: расширенное состояние commercial (веса, референсы, шаги, лучшее предложение, история, время до окончания). - Route auctions.offers.store. - Партиал commercial-trading: «Настройка предложения» (ввод+слайдер+ диапазон+подсказки на 3 критерия, зеркало скоринга в Alpine, long-poll 5с, гейтинг кнопки), карточка лучшего предложения, история. - 7 feature-тестов (приём/отклонение/смена лидера/участник/пределы/ рендер/getState). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- CommercialAuctionProtocolService + pdfs/commercial-auction-protocol: организатор, победитель (наименование+ИНН), итоговые цена/срок/аванс, рейтинг, история лучших предложений (код+ИНН+значения+время). - CloseAuctionJob: для commercial использует коммерческий шаблон протокола (в ту же коллекцию 'protocol' — переиспользуется скачивание/гейтинг). - Feature-тест генерации протокола при закрытии. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Записан отчёт по бейджам (ачивкам) в CHANGELOG_CLAUDE.md, добавлена строка про модель UserBadge в CLAUDE.md (реализация вошла в 73d58a2). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Ветка объединяет две линии работы (готовились слайсами и вошли в общие коммиты):
Коммерческий аукцион (#179), слайсы 1–6:
Бейджи (ачивки) пользователей:
user_badges, модельUserBadge, связьUser::badges().addBadge/removeBadge/assignBadge).Docs: обновлён
CHANGELOG_CLAUDE.md, добавлена строка проUserBadgeвCLAUDE.md.Relates to #179
Test plan
🤖 Generated with Claude Code