Реалізація бронювання оренди (авто, обладнання) на сайті

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Реалізація бронювання оренди (авто, обладнання) на сайті
Складна
~2-4 тижні
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Реалізація бронювання аренди (авто, обладнання) на веб-сайту

Аренда відрізняється від готелю двома речами: одиниця аренди фізично перемішується (автомобіль уїжджає), а тривалість можуть вимірюватися в годинах, а не лише в добах. З цього витікають специфічні завдання: облік місця видачі та повернення, почасове ціноутворення, залог.

Модель даних

CREATE TABLE rental_items (
    id              SERIAL PRIMARY KEY,
    category_id     INTEGER,
    name            VARCHAR(255) NOT NULL,
    description     TEXT,
    vin_or_serial   VARCHAR(100),           -- VIN для авто, серійний номер для техніки
    license_plate   VARCHAR(20),            -- лише для авто
    year            SMALLINT,
    status          VARCHAR(20) DEFAULT 'available',
    -- available | rented | maintenance | out_of_service
    daily_rate      NUMERIC(10,2),
    hourly_rate     NUMERIC(10,2),
    deposit_amount  NUMERIC(10,2),
    min_rental_hours SMALLINT DEFAULT 24,
    max_rental_days  SMALLINT,
    images          JSONB DEFAULT '[]',
    specs           JSONB DEFAULT '{}',     -- характеристики (мощність, обсяг, etc.)
    is_active       BOOLEAN DEFAULT TRUE
);

CREATE TABLE rental_locations (
    id      SERIAL PRIMARY KEY,
    name    VARCHAR(100),
    address TEXT,
    lat     NUMERIC(9,6),
    lng     NUMERIC(9,6)
);

CREATE TABLE rentals (
    id                  BIGSERIAL PRIMARY KEY,
    item_id             INTEGER REFERENCES rental_items(id),
    customer_name       VARCHAR(255) NOT NULL,
    customer_email      VARCHAR(255) NOT NULL,
    customer_phone      VARCHAR(50),
    driver_license      VARCHAR(50),            -- для авто
    pickup_location_id  INTEGER REFERENCES rental_locations(id),
    return_location_id  INTEGER REFERENCES rental_locations(id),
    pickup_at           TIMESTAMP NOT NULL,
    return_at           TIMESTAMP NOT NULL,
    actual_return_at    TIMESTAMP,              -- реальне повернення
    status              VARCHAR(20) DEFAULT 'pending',
    -- pending | confirmed | active | completed | cancelled | overdue
    total_amount        NUMERIC(12,2),
    deposit_amount      NUMERIC(12,2),
    deposit_status      VARCHAR(20) DEFAULT 'not_charged',
    -- not_charged | held | released | partially_withheld | withheld
    extras              JSONB DEFAULT '[]',     -- додаткові послуги
    notes               TEXT,
    created_at          TIMESTAMP DEFAULT NOW(),
    CONSTRAINT no_item_overlap EXCLUDE USING gist (
        item_id WITH =,
        tsrange(pickup_at, return_at, '[)') WITH &&
    ) WHERE (status NOT IN ('cancelled'))
);

Розрахунок вартості

Аренда може тарифіціватися по-різному: перші години по одній ставці, потім суточна:

from decimal import Decimal
from datetime import datetime, timedelta

def calculate_rental_price(item: dict, pickup_at: datetime, return_at: datetime, extras: list = None) -> dict:
    duration = return_at - pickup_at
    total_hours = duration.total_seconds() / 3600

    if total_hours <= 24 and item['hourly_rate']:
        # Почасова аренда
        base_price = Decimal(str(item['hourly_rate'])) * Decimal(str(total_hours))
        billing_unit = 'hourly'
    else:
        # Суточна (ceil — неповний день вважається як повний)
        import math
        days = math.ceil(total_hours / 24)
        base_price = Decimal(str(item['daily_rate'])) * days
        billing_unit = 'daily'

    extras_total = sum(
        Decimal(str(e['price'])) * (e.get('quantity', 1))
        for e in (extras or [])
    )

    return {
        'base_price': base_price,
        'extras_total': extras_total,
        'total': base_price + extras_total,
        'billing_unit': billing_unit,
        'deposit': Decimal(str(item['deposit_amount'])),
    }

Залог (депозит)

Залог замораживається на карті при підтвердженні бронювання через Payment Intent з capture_method='manual':

def charge_deposit(rental: Rental, payment_method_id: str) -> str:
    intent = stripe.PaymentIntent.create(
        amount=int(rental.deposit_amount * 100),
        currency='usd',
        payment_method=payment_method_id,
        capture_method='manual',  -- тільки заморозка, не списання
        confirm=True,
        metadata={'rental_id': str(rental.id), 'type': 'deposit'},
    )
    update_rental_deposit_status(rental.id, 'held', intent.id)
    return intent.id

def release_deposit(rental: Rental):
    stripe.PaymentIntent.cancel(rental.deposit_payment_intent_id)
    update_rental_deposit_status(rental.id, 'released')

def withhold_deposit(rental: Rental, amount: Decimal, reason: str):
    # Частичне або повне списання залога при пошкодженнях
    stripe.PaymentIntent.capture(
        rental.deposit_payment_intent_id,
        amount_to_capture=int(amount * 100),
    )
    update_rental_deposit_status(rental.id, 'withheld' if amount == rental.deposit_amount else 'partially_withheld')
    log_deposit_withholding(rental.id, amount, reason)

Облік просрочки повернення

Cron-завдання щих 30 хвилин знаходить активні аренди з просроченою return_at:

def check_overdue_rentals():
    overdue = db.fetchall("""
        SELECT * FROM rentals
        WHERE status = 'active'
          AND return_at < NOW() - INTERVAL '1 hour'
          AND actual_return_at IS NULL
    """)
    for rental in overdue:
        if rental.status != 'overdue':
            update_status(rental.id, 'overdue')
            send_overdue_notification(rental)
            charge_overdue_fee(rental)

Доплата за просрочку = суточна ставка × кількість просроченых днів (мінімум 1).

Місця видачі та повернення

Аренда в різних пунктах (one-way) може стояти дорожче. Наценка за one-way зберігається в таблиці маршрутів:

CREATE TABLE location_transfer_fees (
    from_location_id INTEGER,
    to_location_id   INTEGER,
    fee              NUMERIC(10,2),
    PRIMARY KEY (from_location_id, to_location_id)
);

Документи клієнта

При аренді авто потрібні водійські права. Фото документів завантажуються при бронюванні і зберігаються в захищеному S3-бакеті з обмеженим доступом. Посилання дійсні 15 хвилин (presigned URL).

Строки реалізації

Базова аренда одного типу об'єктів без залога і one-way — 8–11 робочих днів. Суточне + почасове ціноутворення, залог через Stripe, просрочка, декілька пунктів видачі, завантаження документів, особистий кабінет клієнта — 14–20 робочих днів.