Локальный магазин продуктов с доставкой по своему району обратился за витриной в Telegram.
Заказ до этого выглядел как список в переписке - покупатель писал позиции текстом, сборщик читал и шёл по залу с телефоном в руке.
Пункты забывали, особенно в длинных списках на десять и больше строк.
Отдельная морока была с весом. Просят полкило сыра, кусок выходит на 620 грамм, дальше сумму пересчитывали руками уже по факту, и на пороге начинался разговор про деньги.
Продавали и то, чего на полке нет, потому что остатки никто не сверял до сборки.
Магазин обещает доставку за пятнадцать минут по району и хотел, чтобы это обещание держалось не на честном слове сборщика.
Витрина открывается из бота, каталог разбит по категориям, сверху поиск по названию.
Весовые товары считаются за килограмм, шаг в карточке - 100 грамм, цена выбранного количества видна сразу.
Под вес заложен допуск. Покупатель заранее помечает, что делать при расхождении - взять ближайший вес или позвонить. После сборки заказ пересчитывается по фактическому весу, разница возвращается на карту.
Замена позиции - если товара нет, сборщик предлагает аналог прямо в боте, покупатель подтверждает или убирает из заказа одной кнопкой.
Слоты доставки - ближайшие пятнадцать минут либо интервал на потом. Лимит заказов в слот привязан к числу курьеров на смене.
Остатки подтягиваются из учётной таблицы магазина раз в несколько минут и лежат в кеше. Ходить в таблицу на каждое открытие витрины нельзя - Google режет по лимитам запросов, и каталог начинает висеть у всех сразу.
Товар с нулевым остатком уходит вниз списка и помечается, то-есть с витрины не пропадает. Иначе постоянные покупатели пишут, что каталог сломался.
Оплата картой и СБП, чек уходит через кассу магазина.
Сборщику - список позиций с указанием стеллажа, собранное отмечается галочкой.
Стек - Python, aiogram 3, Mini App, PostgreSQL, Google Sheets API, VPS.
Список в переписке ушёл, сборка идёт по экрану с галочками.
Забытые позиции почти прекратились - заказ закрывается, только когда отмечены все строки.
Сборка одного заказа занимает около трёх минут против семи, когда список вычитывали из чата.
Пятнадцать минут по району держатся - слот не примет больше заказов, чем курьеры успевают увезти.
Заказ пересчитывается по фактическому весу - разговоры про деньги на пороге кончились, покупатель видит финальную сумму до приезда курьера.
У магазина остались исходники, админка с категориями и товарами, инструкция по таблице остатков.
После сдачи прикрутили избранное - у продуктов состав заказа повторяется почти неделя в неделю, так его собирают в пару нажатий.