Property Value URL /operations/create-bookingRoute Handler portals/operations/routes.py → create_booking() (line ~4116)Template templates/portals/operations/create_booking.html (~7,134 lines)Blueprint operations_portalBase Template portals/operations/base.htmlBlock {% block dashboard_content %}Auth @login_required (Flask-Login)Title ”Create Booking - iDrv5-MyFR8”
The form uses a 2-column layout :
Left Column - Customer info, job type, special instructions, booking summary
Right Column - Tabbed booking details (load, pickup, delivery), pricing, submission
Tab navigation (#customerLoadTabs):
Tab Content ID Fields Customer #customer-info-contentCustomer select, Invoice To radio, Third Party selector Load #load-details-contentCustomer Reference Number, Document upload, Hourly rate fields (conditional)
Job Type - Button group: LTL, FTL, Empty Run, Towhaul
Activity Type - Radio buttons: Pickup, Pickup and Delivery, Delivery Only, Local Start
Service Level - Button group (dynamically loaded from API)
Additional Requirements textarea
Displays: Type, Service Type, Charge By, Items Count, Total Weight, Total Volume
Draggable, reorderable tab navigation:
Tab ID Description Load Details #packaging-tabDefault active. Vehicle selection, unified load type entry, item tables Pickup #pickup-tabCompany info, address (Google Autocomplete), schedule, handling options Delivery #delivery-tabSame structure as Pickup with receiver_* prefixes Local Start #local-start-tabConditional. Shown only for local_start activity type
Add Stop Dropdown : Allows adding extra Pickup or Delivery tabs.
Charge By method + units
Base Price, Flat Rate (auto-computed), Fuel Levy %, Tailgate Fee
Estimated Total (calculated)
Surcharges section (dynamically populated addons)
Price Breakdown (shown when tax addons active)
Action buttons: Auto Calculate, Rate Computation Modal, Clear Pricing
Save Booking (primary button)
Cancel link
Field HTML ID Type Required Default Notes Customer customer_selectSelect dropdown Yes — Select Customer — Populated from /api/customers Add Customer add_customerButton No N/A Opens new customer form Invoice To invoice_to_customer / invoice_to_third_partyRadio No customer Options: customer, third_party Third Party Customer third_party_customerSelect dropdown Conditional Empty Shown when invoice_to = third_party
Field HTML ID Type Required Default Notes Reference Number N/A Text No Empty Max 500 chars Documents operations-file-inputFile (multiple) No N/A PDF, JPG, PNG, DOC, DOCX. Max 10MB each. Drag & drop Vehicle Type vehicle_typeSelect Conditional Empty Shown for hourly hire Hours Required hours_requiredNumber Conditional 1 For hourly hire bookings
Field HTML ID Type Required Default Notes Job Type job_typeHidden + Button group Yes ftl LTL, FTL, Empty Run, Towhaul Activity Type activity_*Radio Yes pickup_and_delivery Controls tab visibility Service Level selected_service_levelHidden + Button group No Empty From /api/service-levels
Field HTML ID Type Required Default Notes Vehicle Config booking-vehicle-configSelect Conditional — No vehicle selected — Required for FTL/Towhaul/Empty Run
Field HTML ID Type Required Default Notes Load Type unified-load-typeSelect Conditional — Select — Controls field visibility Selected Load Type selected_load_typeHidden No Empty freight, pallet, container, special
First row fields:
Field HTML ID Type Required Default Notes Quantity first-row-qtyNumber No 1 min=1 Length first-row-lengthDecimal No Empty CM, step=0.01 Width first-row-widthDecimal No Empty CM, step=0.01 Height first-row-heightDecimal No Empty CM, step=0.01 Weight first-row-weightDecimal No Empty KG, step=0.01
Additional rows added dynamically via “Add Item” button (.freight-item-row class). Each row has: type select, qty, length, width, height, weight, delete button.
Field HTML ID Type Required Default Notes Quantity pallet-qtyNumber No 1 min=1 Length pallet-length-cmDecimal No 120 CM, step=0.1 Width pallet-width-cmDecimal No 120 CM, step=0.1 Height pallet-height-cmDecimal No 275 CM, step=0.1 Total Weight pallet-total-weightDecimal No Empty KG, step=0.01 Pallet Brand palletTypeRadioRadio No standard standard, chep, loscam
Hire Account Details (shown when CHEP or LOSCAM selected):
Field HTML ID Type Required Default Notes Transaction Type hire-transaction-typeSelect No transfer transfer, exchange, one-way Docket Number hire-docket-numberText No Empty CHEP/LOSCAM docket ref Sender Account hire-sender-accountText No Empty Sender account number Receiver Account hire-receiver-accountText No Empty Receiver account number
Field HTML ID Type Required Default Notes Data Source towhaul-manual / towhaul-registryRadio No manual Manual Entry or From Client Registry Saved Asset towhaul-saved-assetSelect Conditional Empty Shown when registry selected Category towhaul-categorySelect Yes — Select — ROAD_TRAILER, HEAVY_MACHINERY, VEHICLE, RECREATIONAL Subcategory towhaul-subcategoryText No Empty e.g. Excavator, Skel Trailer Nickname towhaul-nicknameText No Empty e.g. Yellow Cat 320 Make/Model towhaul-makemodelText Yes Empty e.g. Caterpillar 320D VIN towhaul-vinText No Empty VIN or Serial Number Rego towhaul-regoText No Empty Registration plate Coupling towhaul-couplingSelect Yes — Select — KINGPIN, PINTLE_HOOK, BALL_50MM, DRAWBAR, NONE Braking towhaul-brakingSelect Yes — Select — AIR_LINES, ELECTRIC, HYDRAULIC, NONE Length towhaul-lengthNumber No 0 MM Width towhaul-widthNumber No 0 MM Height towhaul-heightNumber No 0 MM Weight towhaul-weightNumber Yes 0 KG
Display Summaries :
#total-cubic-weight - Total Cubic Weight
#chargeable-weight - Chargeable Weight
#total-pallets - Total Pallets
#total-floor-spaces - Total Floor Spaces
#total-pallet-weight - Total Pallet Weight
Fields use array naming: pickup[N][field_name] and delivery[N][field_name].
Field Name Pattern Type Required Notes Company Name pickup[N][company_name]Text Yes Sender/Receiver company Contact Person pickup[N][contact_person]Text No Contact name Address pickup[N][address]Text + Google Autocomplete Yes Google Places autocomplete Locality pickup[N][locality]Hidden No Suburb (from autocomplete) Postal Code pickup[N][postal_code]Hidden No Postcode (from autocomplete) State pickup[N][state]Hidden No State (from autocomplete) Zone ID pickup[N][zone_id]Hidden No Zone ID (from zone lookup) Email pickup[N][email]Email No Contact email Phone pickup[N][phone]Tel No Contact phone Opening Time pickup[N][opening_time]Time No HH:MM Closing Time pickup[N][closing_time]Time No HH:MM
Field Name Pattern Type Required Notes Date pickup[N][date]Date Yes YYYY-MM-DD Time From pickup[N][time_from]Time No HH:MM Time To pickup[N][time_to]Time No HH:MM
Field Name Pattern Type Default Addon Binding Residential pickup[N][residential]Hidden Empty pickup_residentialTailgate pickup[N][tailgate]Hidden Empty pickup_tailgateManual Handling pickup[N][manual_handling]Hidden Empty pickup_manual_handlingTime Slot pickup[N][time_slot]Hidden Empty pickup_time_slot
Field Name Pattern Type Required Notes Instructions pickup[N][special_instructions]Textarea No Max 500 chars
Delivery tabs follow the same structure with delivery[N][...] naming.
Shown only when activity_type = local_start. Prefix: local_start_*.
Field HTML ID Type Required Notes Company Name local_start_company_nameText No Site/company name Street Number local_start_street_numberText No Street local_start_streetText No Suburb local_start_suburbText No State local_start_stateText No Postcode local_start_postcodeText No Zone ID local_start_zone_idHidden No Opening Time local_start_opening_timeTime No Closing Time local_start_closing_timeTime No Contact Name local_start_contact_nameText No Contact Number local_start_contact_numberText No Contact Email local_start_contact_emailEmail No Notes local_start_notesTextarea No
Field HTML ID Type Required Default Notes Charge By Method charge_by_methodSelect Yes Loading… From rate calculation methods API Charge By Units charge_by_unitsNumber No 0 min=0, step=0.01 Base Price base_priceCurrency Yes 0.00 Flat Rate flat-rate-inputCurrency (read-only) No 0.00 Auto-computed from rate engine Fuel Levy fuel-levy-inputPercentage No 20 Fuel surcharge % Tailgate Fee service-fee-inputCurrency No 0 Total Cost total-costDisplay (span) No 0.00 Calculated
Hidden fields for rate calculation : sender_address, receiver_address, pickup_locality, delivery_locality, pickup_postal_code, delivery_postal_code, pickup_administrative_area_level_1, delivery_administrative_area_level_1, pickup_zone_id, delivery_zone_id, selected_service_level, chargeable-weight.
window._addonCache = {} // Keyed by ui_binding
window._addonCacheAll = [] // All applicable addons
window._activeAddonItems = {} // Keyed by addon_id -> line item data
window._computedEngineTotal = null // Last computed rate from API
Function Purpose toggleHandlingOption(button)Toggle handling option buttons (residential, tailgate, etc.). Toggles active state, sets hidden input, calls addAddonByBinding() or removeAddonByBinding(), updates total cost addAddonByBinding(binding)Add addon by UI binding string. Looks up in cache, creates line item, renders it removeAddonByBinding(binding)Remove addon by UI binding. Deletes from _activeAddonItems, removes DOM element renderAddonLineItem(item)Render addon as styled line item in surcharges list. Shows trigger mode badge, label, amount, taxable status removeManualAddon(addonId)Remove a manually added addon
Function Purpose handleLoadTypeChange(value)Handle main load type dropdown change. Hides all conditional fields, shows fields for selected type, updates selected_load_type hidden input addFreightRow()Add additional freight item row with all input fields clearLoadTypeForm()Clear all load type fields and reset selection handleBrandChange(value)Handle pallet brand selection (Standard/CHEP/LOSCAM). Shows/hides hire account details toggleHireDetails(event)Toggle hire account details section
Function Purpose calculateRatesFromAPI(showModalLog)Primary rate calculation . Validates fields, collects data, POSTs to /api/rate-entries/compute-rate, falls back to /api/rate-entries/check-entry. When showModalLog=true shows detailed modal; when false auto-fills silentlyapplyComputedRate()Apply lastComputedRate to form. Sets base_price and flat_rate fields, stores in _computedEngineTotal, calls updateTotalCost() updateTotalCost()Calculate and display total. Processes fuel levy, tailgate, all active addons (fixed/percentage), handles per-unit addons, applies taxes, updates #total-cost display clearPricing()Reset all pricing fields to defaults
Function Purpose fillInAddress(place, type)Populate address fields from Google Places result. Extracts components, populates form, calls zone resolution API fillInLocalStartAddress(place)Populate local start address from Google Places. Also extracts business name
Function Purpose collectPackageData()Collect all items/packages. Checks load type, collects freight/pallet/container data, falls back to legacy tables. Returns array of package objects collectAddressData(type)Collect address fields into structured object. Parameter: ‘pickup’ or ‘delivery’
Function Purpose submitBooking()Collect all form data, build JSON payload, POST to /api/connotes/, handle success/error responses
Function Purpose _getBookingQuantityForUnit(unitType)Calculate total quantity for a unit type. Handles: pallet/item (sum qty), kg (sum weight), km (distance), cubic_meter (total CBM) logToRatesModal(html, scrollToBottom)Append HTML to rates computation log modal
Primary rate calculation endpoint.
Request:
"destination_zone_id" : 2 ,
"packaging_type" : "Carton" ,
Response:
"rate_calculation_method" : "Per Pallet" ,
Fallback endpoint when compute-rate returns no results. Similar request/response structure.
Resolves address to zone ID.
Request:
Response:
Endpoint Method Used For /api/service-levelsGET Service type button group /api/rate-entries/rate-calculation-methodsGET Charge By dropdown /api/transport-equipment/configurationsGET Vehicle type dropdown /api/pallet-typesGET Pallet dimensions & pricing /api/container-typesGET Container selection /api/packaging-typesGET Freight type selection /api/customersGET Customer dropdown (loaded server-side)
Response:
"name" : "Residential Surcharge" ,
"addon_type" : "Surcharge" ,
"value_type" : "Fixed amount" ,
"customer_override_value" : null ,
"ui_binding" : "pickup_residential" ,
"trigger_mode" : "automatic" ,
"applies_on" : "subtotal" ,
"application_scope" : "per_booking" ,
Request:
"invoice_to" : "customer" ,
"third_party_customer_id" : null ,
"special_instructions" : "Handle with care" ,
"address_line1" : "123 Main St" ,
"contact_name" : "John Smith" ,
"contact_phone" : "0412345678" ,
"contact_email" : "john@example.com" ,
"company_name" : "Acme Corp" ,
"local_start_address" : null ,
"packaging_type" : "Carton" ,
"computed_total" : 195.00 ,
"fuel_levy_percentage" : 20 ,
"is_tailgate_pickup" : false ,
"is_tailgate_delivery" : false ,
"name" : "Residential Surcharge" ,
"value_type" : "Fixed amount" ,
"applies_on" : "subtotal" ,
Response:
"message" : "Booking created successfully" ,
"connote_number" : "CON-2026-000789"
1. User fills in required fields:
- Pickup address (required) → auto-resolves zone via /api/rate-entries/check-zone
- Delivery address (required) → auto-resolves zone
- Load type and items (recommended)
- Service level (optional)
2. Trigger: "Auto Calculate" button click or auto-trigger
3. calculateRatesFromAPI()
├─ Validate required fields present
├─ Collect booking data (customer, addresses, items)
├─ POST /api/rate-entries/compute-rate
│ ├─ Success → store in lastComputedRate, show Apply button
│ └─ No results → fallback to POST /api/rate-entries/check-entry
└─ Show computation modal with detailed log
4. User clicks "Apply Rate"
├─ Store in _computedEngineTotal
└─ Call updateTotalCost()
totalWeight = SUM (quantity * weight for each item)
cubicWeight = SUM ( L * W * H / 5000 for each item) // Australian standard
chargeableWeight = MAX (totalWeight, cubicWeight)
Updated in real-time as items change. Displayed in #total-cubic-weight and #chargeable-weight.
subtotal = base_price (from rate engine or manual)
For each addon in _activeAddonItems (ordered by calculation_order):
if value_type == "percentage":
amount = subtotal * (raw_value / 100)
amount = raw_value (fixed)
if application_scope == "per_unit":
For each tax addon (is_tax_addon == true):
taxableSubtotal = sum of non-tax, taxable addon amounts
tax = taxableSubtotal * (tax_rate / 100)
final = runningTotal + fuel_levy + tailgate_fee
1. User clicks "Save Booking"
2. Button disabled, loading state shown
├─ Collect all form data:
│ ├─ Pickup/Delivery addresses & times
│ ├─ All items/packages (via collectPackageData())
└─ Validate required fields
├─ Success → show success alert with connote number,
│ offer "View Details" / "Create Another"
└─ Error → display validation errors, re-enable Save button
Client-side : Customer (required), Pickup Address (required), Delivery Address (required), Base Price (required when not auto-computed), Job Type (required).
Server-side (in /api/connotes/): Customer fields, address structure, package data, pricing fields, addon data structure.
Job Type Effect FTL Vehicle required, Load details shown LTL Item entry required, Packaging shown Empty Run Vehicle required Towhaul Special towhaul form (coupling, braking, dimensions) Hourly Hours + Vehicle type fields shown
Activity Type Visible Tabs Pickup Load Details, Pickup Pickup and Delivery Load Details, Pickup, Delivery Delivery Only Load Details, Delivery Local Start Load Details, Local Start
Load Type Fields Shown Hidden Value Freight Qty, L, W, H, Weight (multiple rows) selected_load_type=freightPallet Qty, L, W, H, Weight, Brand radio selected_load_type=palletContainer Container type dropdown selected_load_type=containerSpecial/Towhaul Asset classification, identity, technical specs selected_load_type=special
Brand Hire Details Shown Standard No CHEP Yes - Transaction type, Docket #, Sender/Receiver accounts LOSCAM Yes - Transaction type, Docket #, Sender/Receiver accounts
Button UI Binding Auto-added Addon Residential Address pickup_residential / delivery_residentialResidential surcharge Tailgate Required pickup_tailgate / delivery_tailgateTailgate surcharge Manual Handling pickup_manual_handling / delivery_manual_handlingManual handling surcharge Time Slot Required pickup_time_slot / delivery_time_slotTime slot surcharge
Library Version Source Purpose jQuery 3.6.0 CDN DOM manipulation, AJAX Bootstrap 5.3+ CDN (via base template) Modals, buttons, layout, grid Flatpickr Latest CDN Date/time picker inputs SortableJS 1.15.0 CDN Drag-and-drop tab reordering Google Maps API Latest Via google_maps_api_key Address autocomplete (AU only) Bootstrap Icons Latest CDN Icons
File Purpose static/js/create_booking_skeleton.jsLoading skeleton screens static/js/booking-tabs-manager.jsDynamic tab creation and management for multiple pickups/deliveries
The majority of form logic is in <script> blocks within the template (~3,500+ lines):
Addon management (~200 lines)
Load type handling (~500 lines)
Rate calculation (~1,000 lines)
Form submission (~1,000 lines)
Address handling (~400 lines)
Google Maps init (~100 lines)
Addon system initialization (~300 lines)
Component Path Template templates/portals/operations/create_booking.htmlRoute Handler portals/operations/routes.py (line ~4116)Booking Tabs Manager static/js/booking-tabs-manager.jsSkeleton Loader static/js/create_booking_skeleton.jsRate Entries API api/rate_entries_api.pyConnotes API api/connotes_api.pyAddons API api/addons_api.pyService Levels API api/service_levels_api.pyCustomers API api/customers_api.pyTransport Equipment API api/transport_equipment_api.pyOperations Base Template templates/portals/operations/base.html
All form data sanitized on backend
CSRF protection via Flask-WTF
Google Maps API key validated server-side
Rate calculation validated on backend (client cannot set arbitrary rates without server confirmation)
File upload restricted to safe types: PDF, JPG, PNG, DOC, DOCX (max 10MB each)
@login_required on the route handler