Delivery Calculator Development on Vue.js for 1C-Bitrix
A delivery calculator is needed on the product page, in the cart, and on the pre-checkout page — so the user knows the shipping cost before entering any details. Standard Bitrix only shows delivery options at the checkout step. A Vue calculator solves this through preliminary calculation.
Delivery Calculation API in Bitrix
Bitrix calculates delivery via \Bitrix\Sale\Delivery\Services\Manager. For preliminary calculation, we create a "virtual" order:
class DeliveryCalculatorController extends \Bitrix\Main\Engine\Controller
{
public function calculateAction(array $items, string $locationCode): array
{
// Create a temporary order object without saving
$order = \Bitrix\Sale\Order::create(SITE_ID, null);
$basket = \Bitrix\Sale\Basket::create(SITE_ID);
foreach ($items as $item) {
$basketItem = $basket->createItem('catalog', $item['id']);
$basketItem->setFields([
'QUANTITY' => $item['qty'],
'CURRENCY' => 'RUB',
]);
}
$order->setBasket($basket);
// Set the delivery address
$shipmentCollection = $order->getShipmentCollection();
$shipment = $shipmentCollection->createItem();
$shipment->setField('DELIVERY_LOCATION', $locationCode);
// Get the list of available services with prices
$deliveries = \Bitrix\Sale\Delivery\Services\Manager::getRestrictedObjectsList($shipment);
$result = [];
foreach ($deliveries as $delivery) {
$calcResult = $delivery->calculate($shipment);
$result[] = [
'id' => $delivery->getId(),
'name' => $delivery->getName(),
'price' => $calcResult->isSuccess() ? $calcResult->getPrice() : null,
'days' => $calcResult->getPeriodDescription(),
];
}
return ['deliveries' => $result];
}
}
Calculator Component
<script setup>
const props = defineProps(['productId', 'productWeight', 'productDimensions']);
const city = ref('');
const locationCode = ref('');
const deliveryOptions = ref([]);
const isLoading = ref(false);
// City autocomplete via DaData or Bitrix location API
async function onCityInput(query) {
const locations = await locationApi.suggest(query);
// User selects — we save the locationCode
}
async function calculate() {
if (!locationCode.value) return;
isLoading.value = true;
const result = await deliveryApi.calculate({
items: [{ id: props.productId, qty: 1 }],
locationCode: locationCode.value,
});
deliveryOptions.value = result.deliveries;
isLoading.value = false;
}
</script>
Default City Detection
Bitrix automatically detects the user's city via \Bitrix\Sale\Location\LocationManager::getUserLocation() (by IP through GeoIP). Use this for pre-population:
$detectedLocation = \Bitrix\Sale\Location\LocationManager::getUserLocation();
echo '<div id="delivery-calc" data-location-code="' . $detectedLocation['CODE'] . '"
data-location-name="' . htmlspecialchars($detectedLocation['NAME']['RU']) . '"></div>';
Calculation Caching
Delivery calculation is a potentially slow operation (external requests to SDEK, DPD APIs). Cache the results:
$cacheKey = md5(json_encode($items) . $locationCode);
$cache = \Bitrix\Main\Data\Cache::createInstance();
if ($cache->initCache(3600, $cacheKey, '/delivery-calc/')) {
return $cache->getVars();
}
// ... calculation ...
$cache->startDataCache();
$cache->endDataCache($result);
TTL — 1 hour, rates change infrequently.
Real-World Case
A store selling oversized goods (furniture): shipping costs vary significantly by city and product dimensions. Users were adding items to the cart just to find out the delivery price, then leaving. A Vue calculator directly on the product page with IP-based city detection let users immediately see "Delivery to Krasnodar from 1,200 RUB, 3–5 days". The checkout abandonment rate dropped — per client data.
Delivery Timelines
| Option | Timeline |
|---|---|
| Calculator with manual city input | 3 to 5 business days |
| With IP geolocation and autocomplete | 5 to 8 business days |
| With external delivery service API integration | 8 to 12 business days |







