Клієнт набирає кошик на 5000 грн, на checkout'і бачить розрахунок вартості доставки 800 грн — і йде. За даними Baymard Institute, 48% покинутих кошиків — через неочікувану вартість доставки. Маємо понад 5 років досвіду в e-commerce та понад 50 реалізованих проєктів, тож гарантуємо якісне рішення. Ми проєктуємо онлайн-калькулятори доставки, які показують точну суму з вибором способу та терміну — до оформлення замовлення на сайті. Результат: конверсія checkout'у зростає на 15–25%. У цій статті — як ми робимо такий калькулятор: від схеми даних до інтеграції з СДЭК та Поштою Росії.
Наприклад, інтернет-магазин електроніки зіткнувся з тим, що старий калькулятор видавав вартість лише після введення всіх даних — і клієнти йшли. Ми впровадили миттєвий розрахунок через кеш і PostgreSQL, і конверсія checkout'у зросла на 20% за тиждень. Вартість інтеграції СДЭК – від 15 000 грн, Пошти Росії – від 10 000 грн. Середня економія наших клієнтів на логістиці становить 3000–5000 грн на місяць.
Які проблеми вирішує калькулятор доставки?
Неочікувані витрати. Клієнт бачить фінальну вартість до оформлення — відмов менше. Ми додаємо кешування, щоб розрахунок ішов за 200–500 мс — це в 3 рази швидше за прямий запит до API.
Непрацюючі API. Перевізники змінюють версії, падають ліміти — наша архітектура з інтерфейсами ізолює збої. Упав СДЭК — клієнту показуємо тарифи з БД або Пошту Росії.
Складні правила. Безкоштовна доставка від суми, зони, габаритна вага — все закладається в таблицю тарифів. Налаштовується без коду через адмінку.
Переваги розрахунку через БД
Таблиці зон і тарифів у PostgreSQL працюють за 10–50 мс. Таблиці БД працюють у 20 разів швидше за прямі API-запити. Кешуємо результат на 5 хвилин, тому для повторних запитів (той самий місто і вага) відповідь приходить миттєво.
Поширені помилки при інтеграції API
Головна помилка — не враховувати габаритну вагу. Кур'єрські служби можуть брати оплату за об'єм, а не за реальну вагу. Ми вбудовуємо перевірку max(weight, length*width*height/5000). Друга помилка — відсутність fallback-у: якщо API перевізника не відповідає, показуємо тарифи з БД. У нас це автоматично в DeliveryCalculatorService. Третя — повільний розрахунок без кешування: ми кешуємо результат на 5 хвилин і використовуємо debounce на фронтенді.
Чому PostgreSQL підходить для тарифів?
PostgreSQL дозволяє гнучко керувати зонами та ставками через SQL-запити. Ми використовуємо масиви для регіонів і JSONB для додаткових правил. Використання індексів у PostgreSQL дозволяє отримувати дані за 1–5 мс. Це дає продуктивність на рівні 10–50 мс на запит, що критично для checkout. Для великих інтернет-магазинів ми рекомендуємо горизонтальне масштабування бази даних, щоб забезпечити швидкість розрахунків при пікових навантаженнях. На відміну від зовнішніх API, ми не залежимо від їхньої доступності та лімітів.
Як ми розробляємо калькулятор
Етапи
- Аналітика — визначаємо перевізників, зони доставки, правила безкоштовної доставки. Збираємо дані про середню вагу та габарити товарів.
- Проєктування схеми — створюємо таблиці
delivery_zonesтаdelivery_rates. Проєктуємо інтерфейсDeliveryProviderInterface. - Реалізація сервісу — пишемо
DeliveryCalculatorServiceз підтримкою кешування та fallback'ом на БД. - Інтеграція з API — підключаємо СДЭК та Пошту Росії через єдиний інтерфейс. Кожна служба — окремий клас.
- Фронтенд — React-компонент з підказкою міст через DaData. Debounce 600 мс, щоб не смикати сервер.
- Тестування — перевіряємо на реальних замовленнях, юніт-тести для сервісу.
- Деплой — розгортаємо на сервері, налаштовуємо кешування.
Схема даних
Схема даних (розгорнути)
CREATE TABLE delivery_zones (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(255),
country CHAR(2) DEFAULT 'RU',
regions TEXT[], -- коди регіонів ФІАС
cities TEXT[], -- коди міст КЛАДР
carrier_id INT REFERENCES carriers(id)
);
CREATE TABLE delivery_rates (
id BIGSERIAL PRIMARY KEY,
carrier_id INT REFERENCES carriers(id),
zone_id BIGINT REFERENCES delivery_zones(id),
method VARCHAR(50), -- 'courier', 'pickup', 'post'
weight_from_g INT DEFAULT 0,
weight_to_g INT,
price NUMERIC(10,2) NOT NULL,
days_min SMALLINT,
days_max SMALLINT,
free_from NUMERIC(12,2), -- безкоштовно при сумі від X
is_active BOOLEAN DEFAULT TRUE
);
Інтеграція з СДЭК
class CdekDeliveryProvider implements DeliveryProviderInterface
{
private string $baseUrl = 'https://api.cdek.ru/v2';
public function calculate(DeliveryRequest $request, int $weightG): array
{
$token = $this->getToken();
$response = Http::withToken($token)
->post("{$this->baseUrl}/calculator/tarifflist", [
'type' => 1,
'currency' => 1,
'lang' => 'rus',
'from_location' => ['code' => config('cdek.from_city_code')],
'to_location' => ['address' => $request->destination->address],
'packages' => [[
'weight' => $weightG,
'length' => 30,
'width' => 20,
'height' => 10,
]],
]);
if (!$response->successful()) return [];
return collect($response->json('tariff_codes', []))
->map(fn($t) => new DeliveryOption(
carrierId: 'cdek',
method: $this->mapTariffToMethod($t['tariff_code']),
name: 'СДЭК — ' . $t['tariff_name'],
price: $t['delivery_sum'],
daysMin: $t['period_min'],
daysMax: $t['period_max'],
))
->toArray();
}
}
Пошта Росії підключається за аналогією через клас RussianPostProvider.
Фронтенд-компонент
const DeliveryCalculator: React.FC<{ cartItems: CartItem[] }> = ({ cartItems }) => {
const [city, setCity] = useState('');
const [options, setOptions] = useState<DeliveryOption[]>([]);
const [loading, setLoading] = useState(false);
const calculate = useDebouncedCallback(async (cityValue: string) => {
if (cityValue.length < 3) return;
setLoading(true);
try {
const res = await api.post('/delivery/calculate', {
destination: cityValue,
items: cartItems.map(i => ({ product_id: i.id, quantity: i.qty })),
});
setOptions(res.data.options);
} finally {
setLoading(false);
}
}, 600);
return (
<div>
<input
placeholder="Введіть місто доставки"
value={city}
onChange={e => { setCity(e.target.value); calculate(e.target.value); }}
className="border rounded px-3 py-2 w-full"
/>
{loading && <p className="text-sm text-gray-400 mt-2">Розраховуємо вартість...</p>}
{options.length > 0 && (
<ul className="mt-3 space-y-2">
{options.map(opt => (
<li key={opt.id} className="flex justify-between items-center border rounded px-3 py-2">
<div>
<p className="font-medium">{opt.name}</p>
<p className="text-sm text-gray-500">{opt.daysMin}–{opt.daysMax} днів</p>
</div>
<span className="font-semibold">
{opt.isFree ? 'Безкоштовно' : formatPrice(opt.price)}
</span>
</li>
))}
</ul>
)}
</div>
);
};
Порівняння служб доставки
| Параметр | СДЭК | Пошта Росії |
|---|---|---|
| Типи доставки | Кур'єр, постамат, ПВЗ | Поштомат, відділення, кур'єр |
| Середній термін | 1-5 днів | 3-14 днів |
| Точність розрахунку | Висока (API v2) | Середня (потрібне зазначення індексу) |
| Підтримка габаритної ваги | Так | Так (через об'єм) |
Типові помилки та як їх уникнути
Головна помилка — не враховувати габаритну вагу. Кур'єрські служби можуть брати оплату за об'єм, а не за реальну вагу. Ми вбудовуємо перевірку max(weight, length*width*height/5000). Друга помилка — відсутність fallback-у: якщо API перевізника не відповідає, показуємо тарифи з БД. У нас це автоматично в DeliveryCalculatorService. Третя — повільний розрахунок без кешування: ми кешуємо результат на 5 хвилин і використовуємо debounce на фронтенді.
Що входить в роботу?
Склад робіт:
- Схема даних (таблиці зон і тарифів).
- Сервіс обчислення DeliveryCalculatorService з підтримкою кешування.
- Інтеграція з двома службами доставки: СДЭК та Пошта Росії.
- Фронтенд-компонент на React/Next.js з підказкою міст через DaData.
- API-ендпоінт з кешуванням на 5 хвилин.
- Документація з налаштування тарифів і додавання нових перевізників.
- Навчання вашої команди роботі з калькулятором — 1 година.
- Доступ до API перевізників (підготовка та налаштування).
- Підтримка після впровадження — 1 місяць гарантії.
Орієнтовні терміни по етапах:
| Етап | Тривалість |
|---|---|
| Аналітика | 0.5–1 день |
| Проєктування схеми | 0.5 дня |
| Реалізація сервісу | 1–1.5 дня |
| Інтеграція API | 1–2 дні |
| Фронтенд | 1–2 дні |
| Тестування | 0.5–1 день |
| Деплой | 0.5 дня |
Загальний термін: від 3 до 5 робочих днів залежно від кількості перевізників і складності тарифів.
Замовте розробку калькулятора доставки під ключ, щоб ваші клієнти бачили точну вартість до оформлення замовлення. Напишіть нам – оцінимо ваш проєкт.







