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.
Step-by-Step User Flow
Section titled “Step-by-Step User Flow”1. Open Rate Card Details
Section titled “1. Open Rate Card Details”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 profilesSource: rate_card_details.html lines 4513-4537, 4734
Each profile option shows its name, with (Default) appended to the system default profile.
3. Select “Use Specific Profile” Mode
Section titled “3. Select “Use Specific Profile” Mode”Change the #transitTimeModeSelect dropdown to “Use Specific Profile” (value: profile).
This fires handleTransitModeChange('profile') which:
- Shows the
#profileSelectContainerdiv (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'; } // ...}4. Pick a Profile
Section titled “4. Pick a Profile”Select the desired profile from the #transitProfileSelect dropdown. The dropdown lists all active profiles fetched in step 2.
5. Click “Save Mode”
Section titled “5. Click “Save Mode””Clicking the “Save Mode” button calls saveTransitTimeMode() which:
- Validates that a profile is selected (when mode is
profile) - 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
Backend Handling
Section titled “Backend Handling”Endpoint: PUT /api/rate-cards/<id> in api/rate_cards_api.py lines 540-560
The PUT handler performs two validations:
Mode Validation (lines 541-545)
Section titled “Mode Validation (lines 541-545)”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'}), 400Profile Validation (lines 547-560)
Section titled “Profile Validation (lines 547-560)”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'}), 404This writes two columns on the rate_cards row:
| Column | Value |
|---|---|
transit_time_mode | 'profile' |
transit_time_profile_id | The selected profile ID (e.g. 5) |
Database Relationship
Section titled “Database Relationship”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
What Happens After Save
Section titled “What Happens After Save”After the PUT succeeds, the frontend:
- Shows a green “Saved” badge in
#transitModeStatus(auto-hides after 3 seconds) - 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
Runtime Resolution
Section titled “Runtime Resolution”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 profileif mode == 'profile' and rate_card.transit_time_profile_id: profile = TransitTimeProfile.query.get(rate_card.transit_time_profile_id)
# Fallback — use the system default profileif not profile: profile = TransitTimeProfile.get_default() # is_default = TRUEUI Elements Reference
Section titled “UI Elements Reference”| Element | ID | Purpose |
|---|---|---|
| Mode dropdown | #transitTimeModeSelect | Select inherit / profile / custom / none |
| Profile dropdown | #transitProfileSelect | Pick which profile to assign |
| Profile container | #profileSelectContainer | Shown only when mode = profile |
| Save button | (inline onclick) | Calls saveTransitTimeMode() |
| Status indicator | #transitModeStatus | Shows “Saved” badge after success |
| Manage Profiles link | (anchor tag) | Links to /operations/rate/transit-time-profiles |
File Reference
Section titled “File Reference”| Component | File | Lines |
|---|---|---|
| Mode selector HTML | templates/portals/operations/rate_card_details.html | 1409-1454 |
handleTransitModeChange() | templates/portals/operations/rate_card_details.html | 4557-4588 |
loadTransitTimeProfiles() | templates/portals/operations/rate_card_details.html | 4513-4525 |
populateProfileDropdown() | templates/portals/operations/rate_card_details.html | 4528-4538 |
saveTransitTimeMode() | templates/portals/operations/rate_card_details.html | 4598-4641 |
initializeTransitTimeMode() | templates/portals/operations/rate_card_details.html | 4708-4729 |
| PUT handler (mode + profile) | api/rate_cards_api.py | 540-560 |
TransitTimeService.get_transit_time() | models/transit_time_profiles.py | 321-392 |