Свой обработчик доставки (стоимость доставки по яндекс картам, готовое решение)
Доброейшего вечера/дня/ночи/утра!
Я продолжаю свой пусть, я продолжаю покорять minishop2
Забегая вперед, то что я пишу, больше для меня самого, но если вдруг, кому-то будет полезно, то я буду несказанно счастлив!
Небольшое вступление: и так, стояла задача, научить минишоп рассчитывать стоимость доставки, в зависимости от удаленности.
Т.е. к примеру, клиенту нужно сделать доставку. Удаленность от физического магазина 15 км. Очень хочется, что бы доставка рассчитывалась не руками — менеджером, а автоматически. Собственно до сегодняшнего дня так и было.
И так, мне нужно через яндекс карты построить маршрут, высчитать расстояние, рассчитать стоимость доставки и передать все это дело в минишоп. Звучит просто, если ты понимаешь в программировании. Но это не мой случай! Слава богу, что есть ИИ.
Важно, весь код, который будет здесь описан сгенерировал ИИ.
И так, перво наперво, нужно получить АПИ ключи от яндекса.
Сделать это можно здесь.
https://developer.tech.yandex.ru
Для дальнейшей работы требуется JavaScript API и HTTP Геокодер и API Геосаджеста.
Теперь подрубаем скрипты от яндекса. У меня это сделано в чанке tpl.msOrder
теперь, в этом же чанке я разместил вот такой вот яваскрипт
Это нужно, если вы хотите дополнительно клиенту обозначить стоимость доставки, либо если произошла ошибка расчета. Т.е. это я к тому, что можно и не добавлять эту строчку.
И, так, на стороне клиента все готово, теперь переходим к серверу.
И если, этот яваскрипт на пару с дипсиком (ИИ), мы написали буквально за пару минут, то дальнейшие манипуляции отняли несколько дней.
https://docs.modx.pro/components/minishop2/development/services/connection
Вот ссылка на, насколько я понимаю, официальную документацию Минишоп2. Но, увы, это устаревшая документация, и об этом ни где ничего не сказано. Увы!
Ну да, обо всем по порядку.
Нужно подрубить свой собственный обработчик доставки.
Если сделать, все как описано в инструкции, то при заходе в настройки доставки, т.е. там где нужно выбрать свой обработчик, получаем ошибку 500, модикс так и пишет: «ошибка 500».
Собственно на устранение ошибки ушел целый рабочий день.
А вся проблема в том, что
в примере из руководства, собственный обработчик начинается с
а в это версии, и я думаю, что и относительно свежих предыдущих версиях, этот файл лежит в другом месте, а именно:
core/components/minishop2/custom/delivery/my_msdeliveryhandler.class.php
Я делал это из консоли (уж не знаю, как другие, а для меня это было открытием. Консоль — это доп пакет, который можно установить из магазина приложений модикса).
В консоли нужно выполнить следующий код:
Тадаааан! =)))
Вроде ничего не забыл!=)
Всех с наступающим!
0
Я продолжаю свой пусть, я продолжаю покорять minishop2
Забегая вперед, то что я пишу, больше для меня самого, но если вдруг, кому-то будет полезно, то я буду несказанно счастлив!
Небольшое вступление: и так, стояла задача, научить минишоп рассчитывать стоимость доставки, в зависимости от удаленности.
Т.е. к примеру, клиенту нужно сделать доставку. Удаленность от физического магазина 15 км. Очень хочется, что бы доставка рассчитывалась не руками — менеджером, а автоматически. Собственно до сегодняшнего дня так и было.
И так, мне нужно через яндекс карты построить маршрут, высчитать расстояние, рассчитать стоимость доставки и передать все это дело в минишоп. Звучит просто, если ты понимаешь в программировании. Но это не мой случай! Слава богу, что есть ИИ.
И так, перво наперво, нужно получить АПИ ключи от яндекса.
Сделать это можно здесь.
https://developer.tech.yandex.ru
Для дальнейшей работы требуется JavaScript API и HTTP Геокодер и API Геосаджеста.
Теперь подрубаем скрипты от яндекса. У меня это сделано в чанке tpl.msOrder
теперь, в этом же чанке я разместил вот такой вот яваскрипт
<script>
ymaps.ready(function ()
{
// 1. НАХОДИМ ЭЛЕМЕНТ ПО ID
var addressInput = document.getElementById('text_address');
// 2. Координаты магазина (ЗАМЕНИ НА СВОИ!)
const SHOP_COORDS = [55.104969, 37.027842];
// 3. Тарифы доставки
function calculatePrice(km) {
if (km <= 3) return 200;
if (km <= 5) return 350;
if (km <= 10) return 450;
if (km <= 20) return 550;
if (km <= 40) return 1100;
return 1100 + (Math.ceil(km) - 40) * 30;
}
// 4. ПЕРЕДАЕМ НЕ СТРОКУ, А САМ ЭЛЕМЕНТ
var suggestView = new ymaps.SuggestView(addressInput,
{
results: 5 // Количество подсказок
});
suggestView.events.add('select', function(e)
{
var selectedItem = e.get('item');
var selectedValue = selectedItem.value;
// ВАЖНО: сначала предотвращаем стандартное поведение blur
addressInput.addEventListener('blur', function preventBlurHandler(event)
{
event.stopImmediatePropagation();
event.preventDefault();
console.log('Blur заблокирован');
}, { once: true }); // Сработает только один раз
// Устанавливаем значение
addressInput.value = selectedValue;
// Форсируем события
['change', 'input'].forEach(function(eventType)
{
addressInput.dispatchEvent(new Event(eventType, { bubbles: true }));
});
// 5. РАСЧЕТ СТОИМОСТИ
ymaps.geocode(selectedValue, { results: 1 }).then(function(res) {
const geoObject = res.geoObjects.get(0);
if (!geoObject) {
console.error('Адрес не найден');
return;
}
const userCoords = geoObject.geometry.getCoordinates();
ymaps.route([SHOP_COORDS, userCoords]).then(function(route) {
const distanceKm = route.getLength() / 1000;
const price = calculatePrice(distanceKm); // ВАША ПЕРЕМЕННАЯ price
console.log('Адрес выбран - добавляем ' + price + ' руб. к доставке');
// 1. Сохраняем стоимость через штатный механизм MiniShop2
if (typeof miniShop2 !== 'undefined') {
miniShop2.Order.add('delivery_extra_cost', price);
}
// 2. Показываем пользователю
if ($('#extra_cost_display').length) {
$('#extra_cost_display').show();
$('#extra_cost_value').text(price);
}
// 3. Обновляем стоимость
setTimeout(function() {
if (typeof miniShop2 !== 'undefined') {
miniShop2.Order.getcost();
console.log('✅ Стоимость отправлена, getcost() вызван');
}
}, 300);
// Дополнительно: показываем в блоке
if (document.getElementById('distance_result')) {
document.getElementById('distance_result').innerHTML =
'Стоимость доставки: ' + price + ' руб';
}
}).catch(function(error) {
console.error('Ошибка расчета маршрута:', error);
});
}).catch(function(error) {
console.error('Ошибка геокодирования:', error);
});
});
});
</script>так же у меня в чанке присуствует вот такое:<div id='distance_result' name='distance_result'></div> Это нужно, если вы хотите дополнительно клиенту обозначить стоимость доставки, либо если произошла ошибка расчета. Т.е. это я к тому, что можно и не добавлять эту строчку.
И, так, на стороне клиента все готово, теперь переходим к серверу.
И если, этот яваскрипт на пару с дипсиком (ИИ), мы написали буквально за пару минут, то дальнейшие манипуляции отняли несколько дней.
https://docs.modx.pro/components/minishop2/development/services/connection
Вот ссылка на, насколько я понимаю, официальную документацию Минишоп2. Но, увы, это устаревшая документация, и об этом ни где ничего не сказано. Увы!
Ну да, обо всем по порядку.
Нужно подрубить свой собственный обработчик доставки.
Если сделать, все как описано в инструкции, то при заходе в настройки доставки, т.е. там где нужно выбрать свой обработчик, получаем ошибку 500, модикс так и пишет: «ошибка 500».
Собственно на устранение ошибки ушел целый рабочий день.
А вся проблема в том, что
в примере из руководства, собственный обработчик начинается с
if (!class_exists('msDeliveryInterface')) {
require_once dirname(dirname(dirname(__FILE__))) . '/model/minishop2/msdeliveryhandler.class.php';
}Но это не правильно. У меня версия минишопа minishop2-4.4.2-plа в это версии, и я думаю, что и относительно свежих предыдущих версиях, этот файл лежит в другом месте, а именно:
if (!class_exists('msDeliveryInterface')) {
require_once MODX_CORE_PATH . 'components/minishop2/handlers/msdeliveryhandler.class.php';
}И, так, вот полный скрипт обработчика, который у меня находится вот здесь:core/components/minishop2/custom/delivery/my_msdeliveryhandler.class.php
<?php
if (!class_exists('msDeliveryInterface')) {
require_once MODX_CORE_PATH . 'components/minishop2/handlers/msdeliveryhandler.class.php';
}
class my_msDeliveryHandler extends msDeliveryHandler implements msDeliveryInterface
{
public function getCost(msOrderInterface $order, msDelivery $delivery, $cost = 0.0)
{
// 1. Берём базовую стоимость доставки (из настроек способа)
$baseCost = parent::getCost($order, $delivery, $cost);
// 2. Получаем доп. стоимость из сессии
$extraCost = 0;
$props = $order->get('properties');
if (isset($props['delivery_extra_cost'])) {
$extraCost = (float)$props['delivery_extra_cost'];
} elseif (isset($_SESSION['minishop2']['order']['delivery_extra_cost'])) {
$extraCost = (float)$_SESSION['minishop2']['order']['delivery_extra_cost'];
}
// 3. Складываем: базовая + доп. стоимость
$totalCost = $baseCost + $extraCost;
// Логируем для отладки
$this->modx->log(modX::LOG_LEVEL_INFO,
"Доставка: базовая=$baseCost, доп=$extraCost, итого=$totalCost");
return $totalCost;
}
}ну и собственно на этом почти все, согласно инструкции, нужно еще зарегистрировать свою службу в модиксе.Я делал это из консоли (уж не знаю, как другие, а для меня это было открытием. Консоль — это доп пакет, который можно установить из магазина приложений модикса).
В консоли нужно выполнить следующий код:
if ($miniShop2 = $modx->getService('miniShop2')) {
$miniShop2->addService('deivery', 'название своей службы',
'{core_path}components/msprofile/model/msprofile/customeraccount.class.php');
}Ну и дело за малым, нужно зайти в настройки минишопа, в раздел доставок, и в нужной выбрать свой обработчик.Тадаааан! =)))
Вроде ничего не забыл!=)
Всех с наступающим!