IT-инфраструктура для бизнеса и творчества

Автоматизация отдела доставки с помощью PHP и JavaScript

Данный скрипт легко установить на свой хостинг, поддерживающий PHP, или использовать локально с помощью эмуляторов PHP типа Denwer. Вы сможете при помощи открытого API Яндекс.Карт составлять оптимальный маршрут для своих курьеров, будете знать требуемое время и общий километраж.

На написание данной статьи меня сподвигнул этот стартап:

Вспомнил, что когда то давно, когда у меня были свои водители для доставки по Ростов-на-Дону, сделал тогда себе нехитрый скрипт (php + javascript) для составления оптимального плана доставки, который при необходимости легко разделить на нескольких водителей.

Скачиваете дистрибутив (php + javascript):

И заливаете все содержимое к себе на сайт в отдельную папку, скажем в папку route, далее в адресной строке браузера набираете ваш_сайт.ru/route/, появится такое окно:

Загружаете csv файл c кодировкой utf-8, его в excel можно сделать, нажав "сохранить как" и выбрав там "Текст CSV(.csv)".

В этом списке должно быть всего два поля, полный адрес (включая город) и время стоянки по адресу в минутах. Первой записью должен быть адрес вашего склада, остальные адреса в произвольном порядке. Я например такой список формировал автоматом своей crm.

Нажав кнопку "найти оптимальный маршрут", вы через минуту работы javascript кода получите такой результат:

Ниже будет список оптимальной последовательности адресов:

Можно кликнуть по ссылке "открыть маршрут" и в режиме навигатора начать двигаться по адресам.

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

{ "author_name": "Денис Демидов", "author_type": "self", "tags": ["\u043e\u0442\u043a\u0440\u044b\u0442\u043e\u0435_\u043f\u043e","\u043b\u043e\u0433\u0438\u0441\u0442\u0438\u043a\u0430","\u043a\u0443\u0440\u044c\u0435\u0440\u044b","\u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442_\u043c\u0430\u0433\u0430\u0437\u0438\u043d\u044b","\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044f_\u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438","php","javascript"], "comments": 92, "likes": 82, "favorites": 210, "is_advertisement": false, "subsite_label": "dev", "id": 46186, "is_wide": true, "is_ugc": true, "date": "Thu, 20 Sep 2018 21:22:04 +0300", "is_special": false }
(function () { let cdnUrl = `https://specialsf378ef5-a.akamaihd.net/SelectelBranding/images/` let previousArticleNumber = null let currentArticleNumber = 0 let platform = 'Desktop' let articles = [ // { // name: 'camera', // url: `${cdnUrl}CameraCat`, // text: 'умную камеру для\u00A0наблюдения за\u00A0котиками', // link: '1', // num: 3 // }, { name: 'chill', url: `${cdnUrl}ChillCat`, text: 'трекер, который подскажет, когда пора отдохнуть', link: 'https://vc.ru/promo/288561-eye-tracker', num: 1 }, { name: 'cloud', url: `${cdnUrl}CloudCat`, text: 'котика: даёшь ему «пять», а\u00A0он делает бэкап в облако', link: 'https://vc.ru/dev/294799-maneki-neko', num: 2 } ] let buttonCycle = document.querySelector('.button--cycle') let buttonChoose = document.querySelector('.button--choose') let buttonMobile = document.querySelector('.button--mobile') let textField = document.querySelector('.selectel-footer-subtitle') let imageAgent = document.querySelector('.image--agent') let banner = document.querySelector('.selectel-footer') buttonCycle.addEventListener('click', cycleClick) buttonChoose.addEventListener('click', () => sendEvent(`Promo ${articles[currentArticleNumber].num} Left`, 'Click')) buttonMobile.addEventListener('click', () => sendEvent(`Promo ${articles[currentArticleNumber].num} Left`, 'Click')) let media = window.matchMedia("(max-width: 570px)") media.addEventListener('change', matchMedia) function matchMedia() { if (media.matches) { platform = 'Mobile' } else { platform = 'Desktop' } update() } matchMedia() function cycleClick(event) { sendEvent(`Promo ${articles[currentArticleNumber].num} Right`, 'Click') if (event) { event.preventDefault() event.stopPropagation() } window.open('https://vc.ru/tag/selectelDIY', '_blank') //cycle(event) } function cycle(event) { // incrementArticleNumber() textField.innerHTML = generatedText() imageAgent.src = articles[currentArticleNumber].url + platform + '.svg?3' imageAgent.setAttribute("class", "") imageAgent.classList.add('image--agent', articles[currentArticleNumber].name) banner.href = articles[currentArticleNumber].link } function update() { banner.href = articles[currentArticleNumber].link imageAgent.src = articles[currentArticleNumber].url + platform + '.svg' textField.innerHTML = generatedText() } function incrementArticleNumber() { previousArticleNumber = currentArticleNumber if (currentArticleNumber >= articles.length - 1) { currentArticleNumber = 0 } else { currentArticleNumber++ } } const sendEvent = (label, action = 'Click') => { const value = `SelectelDIY — loc: Footer — ${label} — ${action}`; if (window.dataLayer !== undefined) { window.dataLayer.push({ event: 'data_event', data_description: value, }); } }; function generatedText() { let defaultText if (platform === 'Desktop') { defaultText = `Мы тут собрали %text%. Хотите научим?` } else { defaultText = `Мы тут собрали %text%.` } return defaultText.replace('%text%', articles[currentArticleNumber].text) } function getRandom(min, max) { min = Math.ceil(min) max = Math.floor(max) return Math.floor(Math.random() * (max - min + 1)) + min } (function create() { currentArticleNumber = getRandom(0, articles.length - 1) cycle() let page = document.querySelector('.page--entry') if (page) { function insertAfter() { let parents = page.querySelectorAll('[data-id="7"]') let referenceNode = parents[0] referenceNode.parentNode.insertBefore(banner, referenceNode.nextSibling); loaded() } setTimeout(() => insertAfter(), 0) } }()) function loaded() { banner.classList.add('loaded') } loadImages([ `${cdnUrl}CameraCatDesktop.svg`, `${cdnUrl}ChillCatDesktop.svg`, `${cdnUrl}CloudCatDesktop.svg`, `${cdnUrl}CameraCatMobile.svg`, `${cdnUrl}ChillCatMobile.svg`, `${cdnUrl}CloudCatMobile.svg?3`, ]) function loadImages(urls) { return Promise.all(urls.map(function (url) { return new Promise(function (resolve) { var img = document.createElement('img'); img.onload = resolve; img.onerror = resolve; img.src = url; }); })); } }())
0
92 комментария
Популярные
По порядку
Написать комментарий...

2к18 который мы заслужили:
* Код в зипке
* Denwer
* Инструкция как получить csv в нужной кодировке
---
К автору претензий никаких, понятно что он не разработчик, и что его творение решает бизнес-задачу и это хорошо. Просто забавно :)

44

Не стреляйте в музыканта, играю как умею )))

33

Ваш пример очень показателен. Еще много болей в процессах, которые не решены.
Например, я обнаружил что брать билет Самара-Бангкок выгоднее на 7тыс с носа если брать Самара-Внуково, такси, Домодедово-Бангкок. Возможно случайный читатель расскажет мне есть ли сервис, который умеет делать такое автоматом и не только в России, был бы благодарен. А пока приходится перебирать сотни вариантов, чтобы немного сэкономить, когда разница во времени не столь велика и критична.

1

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

0

Конечно надо, тока где лям другой баксов на раскрутку взять :((

2

Авиасейлз пока не может это сделать, это связано с тем, что авиакомпании не могут дать более выгодные варианты (уточню. это про транзитные рейсы, когда маршрут вида А-Б-В дешевле, чем А-Б). А если еще работать с такси/электричками и прочим, то авиасейлз вообще скорее всего не ввяжется в это ближайшее время ред.

1

Не нужно выгодные рейсы от них, нужно просто все рейсы.
Ну то есть курумоч-внуково=шереметьево-бангкок дешевле(а порой и не сильно дольше), чем курумоч-бангкок или курумоч-шереметьево-бангкок. А связка всего в одном переезде между аэро в одном городе, что за два часа можно решить почти всегда даже по земле, не говоря о подземке/аэроэкспрессе.

1

Если это единственная киллер фича то ее отследят и внедрят до того, как ваш проект станет хотя бы минимально конкурентным.

1

* Никак пререквезитов
* Не нужно ставить ноду
* Не нужны тайные знания по запуску
* Просто распаковал и работает

Да эта программа лучше, чем 95% творений сегодняшних "профессиональных программистов"

2

Да и давно это было, дата последней правки 26.06.2013, но работает, тока проверял.

1

Клавиша с 0 на клавиатуре отвалилась?

0

это был сарказм? тогда расскажите как правильно и модно.
1) код в зипке. в чем здесь подвох. я в "облаках" не летаю. и на github не выкладываю.
2) денвер - обычный локальный сервер как и другие. буквально на днях обработал на нем базу ФИАС, а это несколько гигобайт.
3) Это проблема бесконечна. win, koi, utf
Я брал на себя работу по обслуживанию сайтов. это не забавно и это 2к18

–1

1. Потому что это моветон -- у всех современных пыхеров есть композер и через него стаятся библиотеки и также удаляются -- зачем возиться с зипами? файлами в нем и т.д... инструкции по установке еще искать и разгребать вот это все, мы же не в нулевых...

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

В целом ваши замечания конечно понятны -- зачем делать так, если и так работает...
Но тут много разработчиков из другого поколения, а также много разработчиков из других языков, которые за такие поделки ОБОСНОВАННО думают, что у нас в языке плодится лишай ред.

0

Я ж без притензий.
Я хочу узнать как должен быть выглядить готовый продукт? В рамках топика
Как нужно выкладовать в паблиш, что бы потом тебя не загнобили

0

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

0

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

0

Какашка и в виде вылепленного коня не нужна никому.
Наличие какашки и публичное мнение о том, что какашка = какашка не является поводом для написания чего-либо :)

–1

Denwer ещё жив??? о_О

4

А я каждый раз вспоминаю другого Денвера:

4

OpenServer

14

Спасибо, почитаю

0

Лучше денвера. Давно под виндой именно под ним

1

А чем конкретно лучше? Что там посмотреть в первую очередь?

0

Это уже тяжелая техника для девелоперов )))

3

скорее наоборот) просто чуть лучше надо разбираться чем две кнопки. три-четыре

1

Докер - хорошо, но может напугать, да)

Хотя скачивание правильного образа и запуск - реально пара кликов

0

Спасибо, чем он лучше чем denwer?
Он правда так устарел что нельзя им пользоваться?
У меня вроде справляется, или там нет чего-то сверхудобного?

0

Ну - версии софта поновее, это существенно. Например, на некоторых хостингах нет php5 уже

0

У меня есть проект, где адская смесь из 4.4 и 5.0, на 5.2 уже варнинги сыплятся.

1

Для кода то - да, миграция на старшие версии софта - всегда риск breaking change словить. Я имел ввиду в основном, что если на хостингах свежие версии php, желательно и на них тестировать скрипты.

Но, вроде, php semver не исповедует - там вообще хз как версионирование сделано. Впрочем, я не в курсе!

0

Спасибо, но пока не сталкивался что чего то у денвера не хватает, но все равно попробую.

0

Да не принципиально - использование нового софта - это своеобразный фетиш ИТ индустрии. Часть - просто дань трендам или "ну так же лучше"

0

А еще над женщинами смеемся )))

0

MAMP лёгок в настройке и установке 👌🏻

1

Реально легко и без заморочек - OpenServer, установили закинули проект в папку domains и все работает. А если нужно прямо по феншую то сейчас модно Docker, только на первых порах с ним много мороки - пока разберётесь как он устроен зима наступит))

1

У меня живет )))
Пока справляется, зачем менять?

0

Комментарий удален по просьбе пользователя

2

тут скорее всего придется яндексу заплатить еще
https://tech.yandex.ru/maps/commercial/

3

Как вариант, сделать бесплатным и монетезировать рекламой, вроде лицензия яндекса это позволяет))

0

Я не против))) пилите стартап и выкладывайте отчет))

1

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

Exel- это как excel, но только короче

3

Спасибо)), поправил.

0

Это как facebook и the facebook.

0

Что же вы так сразу исходники на стол, архивчики...
Надо было пилит презу, считать рынок и заявку во фри, пару лямов не лишние! )

2

Непутевый)))
Но вообще такой скрипт напишит любой программист за пару часава, а вот на всякие фри нужно посевные брать вместе с бизнес ангелом.
Вообще удивлен что статья с простым скриптом стала такой популярной, тут с месяц наверное обмозговывал вот эту:
https://vc.ru/future/45632-pochemu-tramp-priblizhaet-bezuslovnyy-bazovyy-dohod-a-putin-otdalyaet-i-prichem-tut-internet-torgovlya
И эффект в разы меньше, а эту вчера за час накатал, включая проверку самого скрипта, так как давно им не пользовался.

1

У меня тоже похожее есть.
На досуге создал сервис Доставки dostavka23.ru Но я его счас не использую :)
Пользователь( которому нужно например перевезти плюшки и вкусняшки ) ставит точки откуда и куда вести груз и ставит цену которую готов заплатить. При помощи яндекса рисуется маршрут. Ну а исполнитель (например газелька) выбирает лучшие заказы и перевозит. Все довольны :)

2

что-то пошло не так видимо.

0

Скачал на всякий случай. Какой случай? Не знаю...но автор красава, всё красиво расписал с картинками, объяснил, выложил, просто молодец пацан!

2

Как вариант, посмотреть как javascript работает)))

0

Почему-то никто не сказал про Composer, почему библиотека распространяется вне ракетного менеджера?

0

Видимо потому что человек не является разработчиком и просто бесплатно поделился тем, что делал для себя по-быстрому, а дареному коню в зубы не смотрят.

4

Почему все написали про composer но никто не взял и не сделал как надо)

0

Денис, спасибо за статью!

1

Пожалуйста

2

Эмулятор PHP Deneer, ясно-понятно

1

Denwer! Правильнее конечно было написать локальный сервер (Apache, PHP, MySQL, Perl и т.д.)

1

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

0

Кто сказал что она серьезна? Просто выложил в свободный доступ свой скрипт, без претензий на серьезность.
Не вам про серьезность говорить, вы в своем комменте Denwer назвали Deneer....

3

Не путайте опечатку с телефона с некомпетентностью. А несерьезные статьи тогда лучше на одноклассниках выкладывайте

–5

Ну ты нудный, как тебя бабы терпят?

4

Давайте со всем этим говном все же на одноклассники идите, там ваша ЦА

–8

По моему это дно, ставить минус тому, с кем дискутируешь.

2

Ты удивишься, но плюсы и минусы для тго и существуют.

–6

Ты себя снова сам назвал днищем?

Отрадно. :3

0

мне вот нужно разбить N адресов с временными окнами на несколько машин, а у вас только на одну, Как бы допилить ваш скрипт

VRP with Time Windows, VRPTW
http://rain.ifmo.ru/cat/view.php/theory/unsorted/vrp-2006

Задачи маршрутизации транспорта (VRP) лежат на пересечении двух хорошо изученных задач.
- Задача коммивояжера (Traveling Salesman Problem, TSP)
- Задача об упаковке рюкзака (Bin Packing Problem, BPP)

Пока нашел решение на C (используется алгоритм имитации отжига)
https://github.com/radkasprzak/VRPTW_simulated_annealing

1

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

0

Это конечно всё хорошо, но в доставке реальность много подводных камней. К примеру 80 водителей и все работают только по определенным зонам, в среднем на каждого приходится 12 заказов, так же возможна не только доставка и но забор груза, нужно учитывать грузовую вместительность, так как товар от чайника до ванны. Так же возможны критерии оптимизации как сокращение расхода топлива или пробега и тп. Мы пробовали множество систем, реальный результат показал только SAP...

0

Это к этим ребятам:
https://vc.ru/services/45973-transportnye-kompanii-do-sih-por-planiruyut-marshruty-na-bumage-ili-v-excel-fayle?ref=vc.ru
А если у вас пара-тройка курьеров, то этого скрипта хватит с головой, особенно если его прикрутить напрямую к своей crm, чтоб без всяких csv файлов

1

Хорошая задача для многофакторной процедурной оптимизации!

Вам бы найти людей, кто шарит в таком классе задач, и можно съэкономить на SAP

0

Когда у тебя 80 одновременно работающих водителей, то экономия на SAP выглядит как экономия на спичках.

0

Денис, я прочитал Вашу статью на тему безусловного базового дохода. Меня заинтересовала эта тема. Могу ли я задать Вам пару вопросов в вк? Надеюсь Вы ответите) ред.

0

Я в вк не бываю, тут пишите

0

Я учусь в Кубанском Государственном Технологическом Университете на факультете экономики, управления и бизнеса. У нас временами проходят конференции на которых студенты могут выступать. Поскольку мне понравилась данная тема, я решил выступить с ней на конференции. Вы не будете против, если я возьму часть материала из вашей статьи? Никакого монетизирования информации не будет, так как денежных вознаграждений на конференциях нет.

1

Без проблем, если сможете монетизировать то я буду только рад за вас)))

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

1

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

0

Хорошо) Спасибо большое)

0

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

0

Сегодня вообще походу трабла с яндекс картами, у меня сейчас на сайте не работает даже определение города через их api, так что все норм, починят и будет работать

0

будем ждать яндекс))))))

0

С основного домена у меня так и не заработало, загрузил этот же скрипт на другой домен и все работает без проблем!
Яндекс выборочно отключает запросы с сайтов которые ему не подходят.

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

1

ага, может после статьи у них там что-то поломалось )))
У меня на https://avtogsm.ru/ даже вывод телефона в шапке в зависимости от города не работает, тоже через api яндекс карт сделано.

0

Вчера проверял работает, много адресов загружаете? Пишите их как указано в примере?
На всякий случай еще и в яндексе авторизуйтесь, все таки через их API работа основная идет.

0

Сколько адресов пробовали? Чем больше адресов, тем больше javascript работает на вашей машине перебирая разные варианты. Интернет нормальный еще нужен. Также попробуйте браузер другой, хотя я вчера даже на эксплорере 11 пробовал, на нем если что работает то потом 100% и на других будет работать.

0

Скриншоты которые в статье, именно вчера и сделал в ходе тестирования.

0

Сейчас еще раз сам проверил и правда, не работает, яндекс данные не отдает, может у них там что-то ремонтируют, думаю поправят и он заработает, так как использует открытый API яндекс.карт

0

Денис, а подобная автоматизация с Гуглом может работать? не пробовали?

0

Даже не знаю, не разбирался с API гугловских карт

0

Вопрос хоть и не мне, попробую ответить. У Google есть Directions API. (https://developers.google.com/maps/documentation/directions/intro#DirectionsRequests) Через него можно прокладывать маршруты между точками, в т.ч. и оптимальные (при указании optimize:true). Это относится к автомобильным, пешеходным и прочим. Из ограничений: количество запросов в сутки на ключ ограничено (при бесплатном использовании). Из плюшек: есть либы для работы под все основные ЯП.

Когда девушка работала по этой теме, запилил решение на Django + bootstrap/jQuery. Интересовали пешие сотрудники (полевые), поэтому тогда остановился именно на API от Google. Расчет маршрутов по дням (в разные дни - разные маршруты), вывод времени перемещения между точками и расстояние). Расчет как от заданной (первой) начальной точки, так и автоперебор для определения стартовых точек (с привязкой к ближайшим станциям метро).

Можно посмотреть: http://mroute.pythonanywhere.com, логопасс: tanya:tanya (если при расчете будет падать - не пугаться, проблемы с адресами - есть нюансы).

Репо открыто: https://github.com/grybakov/MerchRoutes, по аналогии можно запилить под свое.

0
Читать все 92 комментария
Лекарство или яд: самые интересные исследования про алкоголь Статьи редакции

Материал издания Reminder.

Реклама? Нет, TikTok - двигатель торговли

Как ретейл в США поднимает продажи? Рецепт прост: дополни привычный ассортимент товарами, популярными в TikTok

«Российский рынок акций был и остаётся одним из самых привлекательных в мире»

Виталий Исаков, директор по инвестициям УК «Открытие» («Открытие Инвестиции»).

Когда устал вечером в Додо

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

Вулкан Клуб ⚡️ онлайн: официальный сайт Club Vulkan... клуб с азартными онлайн играми!

Игровой клуб Вулкан — Игровой Вулкан клуб с азартными онлайн играми! Игровой клуб Вулкан; Играть на деньги в автоматы Вулкан — выгодно; Бонусы без депозита для всех новых игроков

Дефицит цифровых кадров в России и их подготовка

Весь мир переходит в цифровую среду. Пока в ежегодном глобальном рейтинге конкурентоспособности Россия занимает 43-е место, но задерживаться на нем не намерена. Для этого правительство запустило программу «Цифровая экономика РФ», которая будет поддерживать цифровую экономику в стране и подготовку необходимых кадров.

Onboarding как отражение продукта
«Spotify: История продукта». Как мы разработали алгоритмы музыкальных рекомендаций

Из онлайн-библиотеки — в сервис персонализированных рекомендаций.

Объявлены победители Finlanding
Будущее наступит во вторник на OneRetailConf
null