Skip to content

Assigning a Transit Time Profile to a Rate Card

This document describes the complete flow for assigning a specific transit time profile to a rate card — from UI interaction to database write.

This document describes the complete flow for assigning a specific transit time profile to a rate card — from UI interaction to database write.


Navigate to the Rate Card Details page, then click the Transit Times tab.

2. Page Load — Profile Dropdown Pre-Population

Section titled “2. Page Load — Profile Dropdown Pre-Population”

On DOMContentLoaded, the page automatically loads all available profiles:

DOMContentLoaded
→ loadTransitTimeProfiles()
→ GET /api/transit-profiles/
→ populateProfileDropdown()
fills #transitProfileSelect with all active profiles

Source: rate_card_details.html lines 4513-4537, 4734

Each profile option shows its name, with (Default) appended to the system default profile.

Change the #transitTimeModeSelect dropdown to “Use Specific Profile” (value: profile).

This fires handleTransitModeChange('profile') which:

  • Shows the #profileSelectContainer div (the profile picker dropdown)
  • Keeps the transit times content table visible
  • Updates the description text to: “Using a specific transit time profile. Select the profile to use for this rate card.”

Source: rate_card_details.html lines 4557-4588

function handleTransitModeChange(mode) {
const profileContainer = document.getElementById('profileSelectContainer');
// Show/hide profile selector
if (profileContainer) {
profileContainer.style.display = mode === 'profile' ? 'block' : 'none';
}
// ...
}

Select the desired profile from the #transitProfileSelect dropdown. The dropdown lists all active profiles fetched in step 2.

Clicking the “Save Mode” button calls saveTransitTimeMode() which:

  1. Validates that a profile is selected (when mode is profile)
  2. Sends a PUT request to update the rate card
async function saveTransitTimeMode() {
const mode = document.getElementById('transitTimeModeSelect').value;
const profileId = document.getElementById('transitProfileSelect').value;
if (mode === 'profile' && !profileId) {
alert('Please select a transit time profile.');
return;
}
const response = await fetch(`/api/rate-cards/${currentRateCardId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
transit_time_mode: mode,
transit_time_profile_id: mode === 'profile' ? parseInt(profileId) : null
})
});
// ...
}

Key: When mode is not profile, transit_time_profile_id is sent as null.

Source: rate_card_details.html lines 4598-4641


Endpoint: PUT /api/rate-cards/<id> in api/rate_cards_api.py lines 540-560

The PUT handler performs two validations:

if 'transit_time_mode' in data:
if data['transit_time_mode'] in ['inherit', 'profile', 'custom', 'none']:
rate_card.transit_time_mode = data['transit_time_mode']
else:
return jsonify({'error': 'Invalid transit_time_mode. Must be: inherit, profile, custom, or none'}), 400
if 'transit_time_profile_id' in data:
if data['transit_time_profile_id'] is None or data['transit_time_profile_id'] == '':
rate_card.transit_time_profile_id = None
else:
# Verify profile exists and is active
profile_check = db.session.execute(
text("SELECT id FROM transit_time_profiles WHERE id = :profile_id AND is_active = TRUE"),
{'profile_id': data['transit_time_profile_id']}
).fetchone()
if profile_check:
rate_card.transit_time_profile_id = data['transit_time_profile_id']
else:
return jsonify({'error': 'Transit time profile not found or inactive'}), 404

This writes two columns on the rate_cards row:

ColumnValue
transit_time_mode'profile'
transit_time_profile_idThe selected profile ID (e.g. 5)

The assignment is a direct foreign key — no join table:

rate_cards.transit_time_profile_id → transit_time_profiles.id
  • One rate card points to one profile at a time
  • Multiple rate cards can share the same profile
  • Changes to a profile propagate to all rate cards using it

After the PUT succeeds, the frontend:

  1. Shows a green “Saved” badge in #transitModeStatus (auto-hides after 3 seconds)
  2. Calls loadTransitTimesForMode('profile') which fetches and displays the transit times from the newly assigned profile in the table below

Source: rate_card_details.html lines 4620-4633, 4643-4660


When a transit time is needed (e.g. during rate computation), TransitTimeService.get_transit_time() in models/transit_time_profiles.py lines 321-392 resolves the profile:

mode = rate_card.transit_time_mode or 'inherit'
# For 'profile' mode — use the assigned profile
if mode == 'profile' and rate_card.transit_time_profile_id:
profile = TransitTimeProfile.query.get(rate_card.transit_time_profile_id)
# Fallback — use the system default profile
if not profile:
profile = TransitTimeProfile.get_default() # is_default = TRUE

ElementIDPurpose
Mode dropdown#transitTimeModeSelectSelect inherit / profile / custom / none
Profile dropdown#transitProfileSelectPick which profile to assign
Profile container#profileSelectContainerShown only when mode = profile
Save button(inline onclick)Calls saveTransitTimeMode()
Status indicator#transitModeStatusShows “Saved” badge after success
Manage Profiles link(anchor tag)Links to /operations/rate/transit-time-profiles

ComponentFileLines
Mode selector HTMLtemplates/portals/operations/rate_card_details.html1409-1454
handleTransitModeChange()templates/portals/operations/rate_card_details.html4557-4588
loadTransitTimeProfiles()templates/portals/operations/rate_card_details.html4513-4525
populateProfileDropdown()templates/portals/operations/rate_card_details.html4528-4538
saveTransitTimeMode()templates/portals/operations/rate_card_details.html4598-4641
initializeTransitTimeMode()templates/portals/operations/rate_card_details.html4708-4729
PUT handler (mode + profile)api/rate_cards_api.py540-560
TransitTimeService.get_transit_time()models/transit_time_profiles.py321-392