Skip to main content

SCG — Travel Expense Rules

This document describes how travel expenses are calculated for trips governed by the SCG corporate policy.

At a glance:

  • Each leg carries an explicit start time and end time.
  • A later leg's start time cannot overlap the previous leg's end time, compared in UTC.
  • Policy tier selection uses two factors only: Time (duration) and Location.

Key Concepts​

TermDescription
TripA travel request that groups one or more travellers travelling together (or around the same time). A trip is an organisational container only — expense is always calculated per traveller, never at the trip level.
TravellerAn individual assigned to the trip. Each traveller has their own itinerary — their own departure location, destination(s), and times. Travellers on the same trip may depart from different cities, arrive at different destinations, and travel at different times.
LegA single segment of a traveller's itinerary, defined by a departure location, destination, start time, and end time. A traveller's itinerary is an ordered sequence of legs.
Same-day handoffWhen one leg ends on the same calendar day that the next leg begins. This is the only condition under which two of a traveller's legs are linked together.
Connected chainA run of consecutive legs (belonging to one traveller) linked by same-day handoffs. Used only for policy selection — the UI still shows each leg separately.

Important: Travellers on the same trip are calculated completely independently — no factor (time, location, policy tier) is shared between them. Two travellers going to the same destination at the same time each get their own separate calculation.

Important: A traveller's legs are sequential in time — they do not overlap. Legs are linked only when they hand off on the same calendar day, never by partial overlap.


Leg Times & Timezone​

Every leg is bounded by an explicit start time and end time.

Non-overlap rule​

A later leg's start time must not overlap the previous leg's end time. In other words, for any two consecutive legs:

Ordering constraint
leg[n+1].startTime ≥ leg[n].endTime

Timezone for comparison​

Because an SCG trip can cross many countries (and therefore many timezones), all time comparisons — including the non-overlap check and the same-day-handoff check — are evaluated in UTC. Local timezones are normalised to UTC before any leg-to-leg comparison is made.

Timezone on the UI​

On the UI, the selected time follows the local time of the location for that leg (departure/destination). The local time the user sees and picks is converted to UTC internally for storage and comparison.

Important: What the user sees is local time; what the system compares is UTC. A pair of legs that look non-overlapping in their respective local times may still overlap once normalised to UTC — the constraint is always enforced against the UTC values.


Policy Factors​

Two factors select the policy tier (the per-unit rate), evaluated per leg (or per connected chain when legs hand off on the same day).

#FactorWhat it measuresUsed for
1TimeThe duration of the leg. For a connected chain, the sum of the durations of all connected legs.Tier selection
2LocationThe location of the leg. The amount of expense is regulated by the location defined in the policy settings.Tier selection

How Connected Legs Are Handled​

Policy selection is applied per leg. When consecutive legs hand off on the same calendar day (one leg ends on the day the next begins), they are linked into one connected chain, and the Time factor is computed across the whole chain.

Legs that do not share a handoff day — including legs that are merely adjacent (one ends the day before the next begins) — are not linked and are evaluated independently.

Important: Linking legs into a chain only affects policy calculation. The UI continues to display each leg separately as originally defined.


Calculation Rules​

1. Time (duration)​

  • The duration of a single leg is endTime − startTime, computed in UTC.
  • For a connected chain, the duration is the sum of the durations of all connected legs.
  • The chain duration is used to select the policy tier.

Example:

LegRouteStart (UTC)End (UTC)Duration
ABangkok → HanoiJun 1, 08:00Jun 1, 12:004h
BHanoi → TokyoJun 1, 15:00Jun 1, 22:007h

Leg A ends Jun 1 and leg B begins Jun 1 → same-day handoff → one connected chain. Chain duration = 4h + 7h = 11h → used to select the policy tier.

Note: Because durations are summed, the non-overlap rule guarantees the segments never double-count: leg[n+1].startTime ≥ leg[n].endTime.


2. Location​

  • Each leg has a location, and the amount of expense is regulated by that location as defined in the policy settings.
  • The policy settings map a location to its rates — a full-day rate and a half-day rate (the half-day rate defaults to half the full-day rate unless the policy defines it explicitly).
  • The location supplies the per-unit rates that the Expense Formula below multiplies by the time-based units.

Expense Formula​

The amount is computed per leg or per connected chain, after the Time (duration) and Location (rate) factors are known.

Let H be the duration in hours (endTime − startTime, in UTC; the summed chain duration for a connected chain), and let fullDayRate / halfDayRate be the rates for the leg's location.

Expense formula
fullDays = floor(H / 24)
remainderHours = H − (fullDays × 24)

amount = fullDays × fullDayRate + remainderAmount

remainderAmount rounds the leftover hours by the half-day / full-day rule:

Remainder (remainderHours)RuleremainderAmount
< 5hdrop0
≥ 5h and < 12hhalf-dayhalfDayRate
≥ 12hfull-dayfullDayRate

Examples (using a full-day rate of 190,000 and a half-day rate of 95,000):

DurationfullDaysremainderHoursRemainder ruleAmount
2d 13h (61h)213h≥ 12h → full-day2 × 190,000 + 190,000 = 570,000
1d 7h (31h)17h5–<12h → half-day190,000 + 95,000 = 285,000
1d 3h (27h)13h< 5h → drop190,000 + 0 = 190,000
4h (4h)04h< 5h → drop0

Connected Chains Spanning Different Locations​

When a connected chain stays in a single location, the formula above runs once on the summed duration using that location's rate.

When the legs of a chain fall under different location rates, the per-unit rate is ambiguous because the chain is billed as one summed duration. This is the open case below. No final decision has been made yet — the recommendation is documented here for confirmation.

Status: proposed (pending confirmation). The recommended approach is Option A below.

Bill each time unit at the rate of the location the traveller is actually in during that unit.

  1. Compute fullDays and remainderHours from the summed chain duration, exactly as in the formula above.
  2. Lay the chain on one continuous timeline (legs are non-overlapping and same-day-connected) and walk it from the chain start in 24-hour blocks.
  3. Charge each whole-day block at the full-day rate of the location occupied during that block (the leg whose UTC time range covers the block).
  4. Charge the leftover remainderHours with the half/full/zero rule, at the rate of the location occupied during the remainder window (normally the final leg / destination).

Pro: most accurate and defensible to finance — every day is paid at the rate of where it was spent. Con: needs a per-block location lookup.

Option B — Single representative location​

Bill the whole chain with one location's rate, applied once to the summed duration. The most sensible single choice is the final destination (the last leg) — where the traveller ends up and where per-diem typically accrues. (A conservative variant bills at the highest rate among the chain's locations.)

Pro: trivial to implement. Con: ignores time spent in cheaper/pricier intermediate locations.

Option C — Proportional split​

Split the computed units across legs in proportion to each leg's share of the chain duration, then bill each share at its own location's rate.

Pro: roughly fair without per-block lookup. Con: the < 5h / < 12h thresholds are defined on the total duration, so attributing the rounded remainder to a specific leg is ambiguous.

Recommendation: adopt Option A — it keeps the existing "sum the chain duration" rule intact while honouring each location's regulated rate, and it produces the result finance can most easily audit. Use Option B (final destination) only if implementation simplicity must win over accuracy.


Summary: Connected Chain Behaviour​

FactorHow it is computed for the connected chain
TimeSum of the durations (endTime − startTime, in UTC) of all connected legs
LocationThe location of the leg / chain, used to look up the regulated full-day / half-day rates in policy settings
Amountfloor(H/24) × fullDayRate plus a remainder of 0 / halfDayRate / fullDayRate (for the < 5h / < 12h / ≥ 12h leftover). For chains across different location rates, attribute each day to its location — see Option A.

Calculation Flow​

Calculation flow
For each traveller:
1. Take the traveller's ordered list of legs.
2. Validate ordering: each leg's startTime (UTC) must be ≥ the previous
leg's endTime (UTC) — later legs must not overlap earlier ones.
3. Link consecutive legs into a connected chain when one leg ends on the
same calendar day (UTC) the next leg begins (same-day handoff).
Legs without a same-day handoff are standalone.
4. For each chain (or standalone leg):
a. Time → sum of (endTime − startTime) across the chain, in UTC.
b. Location → the leg/chain location, looked up in policy settings.
5. Select the rates for each chain using: Time + Location.
6. Compute the amount with the Expense Formula:
H = duration in hours
fullDays = floor(H / 24) → × fullDayRate
remainderHours = H − (fullDays × 24)
remainderHours < 5 → + 0
5 ≤ remainderHours < 12 → + halfDayRate
remainderHours ≥ 12 → + fullDayRate
(For a chain spanning different location rates, attribute each day
to the location occupied that day — see "Connected Chains Spanning
Different Locations", Option A.)
7. Display results on the UI per original leg (not per connected chain),
showing times in the local timezone of each leg's location.

Notes​

  • Every leg has an explicit start time and end time; all leg-to-leg comparisons are done in UTC, while the UI shows and accepts times in the local timezone of the location.
  • The start time of a later leg can never overlap the end time of the previous leg (checked in UTC).
  • Legs are linked into a connected chain only by a same-day handoff, never by partial overlap.
  • Linking legs into a chain is a calculation concept only; individual legs remain unchanged in the UI and in stored data.
  • Travellers on the same trip are fully independent. Different departure cities, destinations, and times between travellers have no effect on each other's calculation.