{"id":14270,"url":"\/distributions\/14270\/click?bit=1&hash=a51bb85a950ab21cdf691932d23b81e76bd428323f3fda8d1e62b0843a9e5699","title":"\u041b\u044b\u0436\u0438, \u043c\u0443\u0437\u044b\u043a\u0430 \u0438 \u0410\u043b\u044c\u0444\u0430-\u0411\u0430\u043d\u043a \u2014 \u043d\u0430 \u043e\u0434\u043d\u043e\u0439 \u0433\u043e\u0440\u0435","buttonText":"\u041d\u0430 \u043a\u0430\u043a\u043e\u0439?","imageUuid":"f84aced9-2f9d-5a50-9157-8e37d6ce1060"}

MVP маркетплейса в «Google Таблицах»

В статье я расскажу, как можно за час-другой склепать MVP маркетплейса курьеров. Этот прототип подойдёт для службы заказа такси, услуг и прочего. Разумеется, на этой же основе можно сделать много других полезных вещей.

Итак, краткий флоу системы:

  • Курьеры регистрируются на сервисе.
  • Пользователь составляет заказ.
  • Полученный заказ автоматически распределяем на подходящего курьера.
  • Уведомляем курьера о новом заказе.
  • Грабим караваны.
  • Ну и, конечно, хотим завести все это без разработки.

Прием заказов и регистрация курьеров

Приступим. Регистрацию курьеров и прием заказов будем делать на Google-формах. Можно использовать любой другой инструмент, который собирает данные в Google-таблицу. Например, можно сделать лендинг на Tilda и собирать данные через него.

Создать форму: Google Drive → New → More → Forms. Для курьера достаточно ФИО и почты, на которую будут приходить уведомления о новых заказах. Для заказа — сути задачи.

Чтобы привязать форму к таблице, перейдите во вкладку «Responses» и нажмите на иконку «Google Таблиц». Привяжем обе формы к общей Google-таблице. Пример.

Распределение заказов

Распределять заказы будем при помощи магии формул: для каждого заказа определим, какие курьеры на момент обращения свободны, и выберем из них любого.

Не получится нормально использовать формулы на странице с ответами на форму: когда «Google Формы» добавят строку, формулы с этой строки сотрутся. Но есть лайфхак.

Лайфхак: если данные скопировать на отдельный лист формулой "=ARRAYFORMULA('Заказы'!A2:C)", к этим данным формулы будут применяться нормально.

Поэтому делаем отдельную страницу, в первую ячейку вписываем формулу для копирования всех результатов:

​Остальные ячейки на этой странице пустые — они заполняются из выделенной ячейки при помощи ARRAYFORMULA

Чтобы понять, какие курьеры свободны, вычислим, какие курьеры заняты. Для простоты будем считать, что курьеру всегда требуется час на заказ. Поэтому занятые курьеры — это все, кто получил заказ за последний час.

Отдельная проблема: список курьеров — это список, так просто его в одну ячейку не сохранить. Но есть лайфхак.

Лайфхак: сохранить список в ячейку можно, если сделать его строкой. Функция JOIN(",",{1,2,3}) превратит список в строку "1,2,3", а SPLIT("1,2,3", ",") превратит обратно в список.

​Формула занятых курьеров. Вася и Дима получили заказы меньше часа назад, а Миша — больше часа. Поэтому заняты только Вася и Дима

По списку занятых курьеров можно легко получить список свободных курьеров. Важно брать только тех курьеров, которые были зарегистрированы до подачи заказа, иначе вся история перестроится с учетом нового курьера, когда он добавится.

Формула свободных курьеров. Она значит: возьми из всех курьеров тех, у кого непустое имя, кто зарегистрировался до этого заказа и кого нет в списке занятых курьеров

Из свободных берем первого попавшегося.

​Я добавил еще один заказ, чтобы был выбор из двух курьеров

Конечно, нужно скопировать формулы до конца таблицы.

Почему нельзя так просто избавиться от этих списков

Нюанс в том, что формулы не сохраняют состояние — им всегда нужны исходные данные, на которых они считались. Если исходные данные со временем изменятся, то и формулы, которые использовали их, изменятся.

То, что хоть раз попало в расчет, не должно изменяться, иначе разъедется вся история.

Поэтому нельзя хранить свободных курьеров только на текущий момент, нужно хранить свободных курьеров (и другие параметры) на момент заказа для каждого заказа.

Уведомления курьерам о новых заданиях

Когда курьеру приходит новый заказ, сообщим ему об этом. Мы будем отправлять электронное письмо, но таким же образом можно прикрутить отправку SMS, чего угодно еще.

Отправлять сообщения будем с Gmail, а интеграцию сделаем при помощи Zapier.

Логинимся в Zapier, создаем новый zap. Указываем триггер — обновление Google-таблицы.

Указываем таблицу, страницу распределения заказов и колонку имен курьеров. Когда обновим курьера, будет срабатывать триггер.

В действии выбираем Gmail → Send Email.

Теперь заполним шаблон письма. Для этого нужен адрес получателя. Прокинем его в таблицу распределения заказов при помощи index-match.

Теперь в Zapier выберем это поле как адресата.

И сделаем шаблон письма.

Отлично. При попытке тестирования оно выдаст ошибку. Это связано с тем, что Zapier почему-то использует пустую строку из таблицы. Этап тестирования можно пропустить.

После скипа тестирования включим Zap.

Пробуем

Зарядим какой-нибудь заказ через форму, и вуаля — на почту, указанную при регистрации курьера, прилетает письмо.

Улучшения

Приведенный прототип развалится, если не будет доступных курьеров. Чтобы решить эту проблему, нужно изменить способ выбора курьера — выбирать не свободных, а тех, кому раньше ушел последний заказ. Сюда можно прикрутить еще много полезной логики.

Например, помимо адреса можно собирать с заказчиков район и выбирать курьера из ближайшего, даже если он позже освободится.

Можно сделать еще одну форму, курьер будет ее заполнять, когда завершит заказ. По этим данным его можно будет сразу направлять на новый заказ.

Можно приделать SMS-уведомления заказчику, динамическое ценообразование, что угодно еще.

Получается довольно гибкая штука, адаптируйте под что угодно.

Стартуйте и растите быстро.

0
25 комментариев
Написать комментарий...
Alex E

Ну и геморой)))) Быстрее Api сделать и приложение накидать.

Ответить
Развернуть ветку
Ринат Г.

И потом осознать что проебал год своей жизни на api, приложухи для декстопа и мобайла, разворачивание собственных инстансов osrm/osm/graphhopper, настройку всего этого говна в k8s с ci/cd. А сосед тем временем продал свой стартап амазону и уехал на кипр, а также красавица жена чудесным образом исчезла, и вот хз, связаны ли две эти вещи или нет.

Ответить
Развернуть ветку
Vladislav Proshinsky

и не поспоришь с тобой....

Ответить
Развернуть ветку
Отображаемое имя

А вот и нет. Благодаря автору этот шаблон под свой бизнес можно немного подпилить. Очень интересное решение

Ответить
Развернуть ветку
Avdotii Pedishnii

Мне вот тоже такая штука нужна была, но я дальше API не прошел))) Что по приложениям посоветуете, я пока пытаюсь освоить RN

Ответить
Развернуть ветку
Alex E

Бек и  API есть готовые пакеты Laravel, остальное можно взять Datr+ Flutter на все платформы и WEB

Ответить
Развернуть ветку
Martin Zubovskiy

*Dart)

Ответить
Развернуть ветку
Alex E

))) ну все поняли я думаю

Ответить
Развернуть ветку
Away Trent
Ответить
Развернуть ветку
Eduard Mirchev

Я считаю, это искусство и шедевр! Браво!

Ответить
Развернуть ветку
Евгений Пронягин

Хуяк-хуяк и в продакшн 👍🏻😂

Ответить
Развернуть ветку
Denis Tsarkov

Четенько!

Ответить
Развернуть ветку
Император Всероссийский

Клиентскую часть для заказчиков надо делать всегда нормальной. Такой колхоз не покажет реальных метрик.

Ответить
Развернуть ветку
Игорь Алексеев

1 Колхоз?

2 Здесь клиентский UI только форма куда заказ добавляется. Можно купить красивый шаблон лендинга, который будет (сейчас будут космические технологии из 3000 года) ОТПРАВЛЯТЬ ФОРМУ В ГУГЛ ДОКС!

Ответить
Развернуть ветку
Император Всероссийский

Иииии... что?

Ответить
Развернуть ветку
Alexey Remizov

как только на форме заказа нужно выводить остатки товара - чего делать?

Ответить
Развернуть ветку
Вилен Базиян

Ну для мвп норм, но только пешие.

Ответить
Развернуть ветку
Mike Khabarov

когда думаешь, что дно пробито, а снизу постучали

Ответить
Развернуть ветку
Gasanov Ramil

Хммм, действительно, средствами Google Sheets вроде как нельзя зафиксировать стейт ячейки в соседнюю. Скорее всего можно только через API.

Ответить
Развернуть ветку
Alexander Peshkov

Для этого есть retailCRM)

Ответить
Развернуть ветку
Pavel Sharonov

прелестно.

Ответить
Развернуть ветку
Gasanov Ramil

Спасибо за статью! 

В Вашем примере основная сложность, на мой взгляд, заключается в определении свободного курьера. Кроме предложенного Вами способа можно в реальном времени рассчитывать статус курьеров при помощи функции NOW. Формула будет похожа на: 

=IF( (TIMEVALUE(now())-TIMEVALUE(order_timestamp)) * 24 < 1, "Занят", "Свободен" ) 

Ответить
Развернуть ветку
Georgy Borisenko
Автор

Насколько я вас понимаю, вы предлагаете хранить статус занятости курьера только на текущий момент. В параграфе "Почему нельзя так просто избавиться от этих списков" я подробно описал, почему по моему мнению такой способ работать не будет.

Если я вас не правильно понял или ошибаюсь в том, что недостаточно хранить статус на текущий момент, поправьте меня.

Ответить
Развернуть ветку

Комментарий удален модератором

Развернуть ветку
Император Всероссийский

Заказать у фрилансера скрипт который будет парсить таблицу)

Ответить
Развернуть ветку
Timofey Kravtcoff

"Берем любого свободного курьера" - :))

А если он на другом конце света? Тоже его берем?

Ответить
Развернуть ветку
22 комментария
Раскрывать всегда