Session Pricing
HandyCafe uses a segment-based pricing engine to calculate session costs in your internet cafe or gaming center. Instead of applying a single flat rate for the entire session, the engine divides each session into segments, each with its own pricing context. This approach ensures accurate billing even when sessions span multiple time slots, pricing changes, pauses, or disconnections.
Core Concepts
Before diving into the details, here are the key terms:
| Term | Definition |
|---|---|
| Base hourly rate | The price per hour before any multipliers are applied. Set in Settings > Pricing. |
| Pricing slot | A named time period with a specific multiplier. There are 8 slots, each color-coded. |
| Multiplier | A factor applied to the base rate. 1.0 = standard price, 0.5 = half price, 2.0 = double price. |
| Segment | A continuous period within a session where the pricing context (slot, multiplier, base price) remains unchanged. |
| Settlement | The final calculation that determines how much the customer owes when a session ends. |
Base Hourly Rate
The base hourly rate is the foundation of all pricing calculations. It is set in Settings > Pricing and represents the standard price per hour of PC usage.
All internal calculations use minor currency units (for example, cents for USD, kurus for TRY). If your base rate is $3.00 per hour, the internal value is 300. This eliminates floating-point rounding issues.
Dual Currency Support
HandyCafe supports a base currency and a local currency with an exchange (FX) rate. If you operate in a country where international pricing differs from local pricing:
- Base currency. The currency used for internal pricing calculations.
- Local currency. The currency displayed to customers and used for payments.
- FX rate. The conversion factor between base and local currencies.
If both currencies are the same, the FX rate is treated as 1.0 and has no effect.
Pricing Slots
There are 8 color-coded pricing slots, each representing a different pricing tier:
| Slot | Color | Typical Use |
|---|---|---|
| Blue | Blue | Standard rate |
| Orange | Orange | Evening or weekend surcharge |
| Red | Red | Peak hours premium |
| Green | Green | Off-peak discount |
| Teal | Teal | Student or member rate |
| Gray | Gray | Holiday or special pricing |
| Cyan | Cyan | Night rate |
| Emerald | Emerald | Promotional rate |
Each slot has three properties:
- Name. A descriptive label (for example, "Peak Hours" or "Night Discount").
- Multiplier. A decimal value that modifies the base rate. Common values include 1.0 (standard), 0.5 (half price), 1.5 (50% surcharge), 2.0 (double price). The multiplier must be zero or positive.
- Schedule data. An internal representation that defines which hours of which days the slot applies to. This is managed automatically through the schedule grid.
Slots can be individually enabled or disabled. Disabled slots are ignored by the pricing engine.
The Schedule Grid
The pricing schedule is a 7-day by 24-hour matrix (168 one-hour blocks in total). Each block is assigned to one pricing slot. The schedule determines which multiplier applies at any given moment.
The grid is configured in Settings > Pricing Schedule. Days run from Monday to Sunday and hours run from 00:00 to 23:00. To assign a slot to a time block, select the block in the grid and choose the desired slot color.
How the Engine Reads the Schedule
Internally, each hour block maps to a position in the schedule data. The engine checks each enabled slot's schedule data to determine which slot is active for any given day and hour.
If no slot has its bit set for a given hour, the engine falls back to the base rate with a multiplier of 1.0.
When the pricing schedule feature is disabled entirely (in Settings > Pricing), all sessions use the base rate with a 1.0 multiplier regardless of time.
Pricing Segments
A segment is a continuous time period within a session where the pricing context does not change. The pricing engine creates a new segment whenever any of these boundary events occur:
| Boundary | Trigger |
|---|---|
| session_start | A new session begins |
| session_stop | The session is stopped |
| pause | The cashier pauses the session |
| resume | The cashier resumes a paused session |
| tick | The clock crosses an hour boundary into a different pricing slot |
| disconnect | The client PC loses its network connection |
| offline | The client PC goes offline |
| load_recovery | The server restarts and recovers a running session |
Each segment records:
| Field | Description |
|---|---|
| session_id | The session this segment belongs to |
| segment_start | Unix timestamp when the segment began |
| segment_end | Unix timestamp when the segment ended (null if still open) |
| pricing_slot_id | The ID of the active pricing slot (for example, "blue", "red", or "base") |
| multiplier | The multiplier value from the pricing slot |
| base_price_snapshot | The base hourly rate captured at the moment the segment opened |
| amount | The calculated cost for this segment (set when the segment closes) |
| boundary_reason | Why this segment was created |
Why Snapshot the Base Price?
The base_price_snapshot captures the base hourly rate at the exact moment the segment opens. This is critical because an administrator could change the base rate mid-session. By snapshotting, each segment uses the rate that was in effect when it started, ensuring fair and auditable billing.
Cost Formula
The cost of a single segment is calculated as:
amount = ceil( (base_price_snapshot * multiplier * duration_seconds) / 3600 )
More precisely, the engine uses scaled integer arithmetic to avoid floating-point errors:
- The multiplier is scaled to a fixed-point integer (multiplied by 1,000,000).
- The calculation is performed entirely in 128-bit integers.
- Ceiling division is used. The result always rounds up to the next minor unit.
Calculation by Minutes
If the "calculate by minutes" option is enabled in Settings > Pricing, the formula changes slightly:
amount = ceil( (base_price_snapshot * multiplier * used_minutes) / 60 )
Where used_minutes = ceil(duration_seconds / 60). This means any partial minute is counted as a full minute.
Session Total Calculation
The total session cost is computed in three steps:
Step 1: Sum All Segments
raw_total = sum of all closed segment amounts + open segment partial amount
The open segment partial amount is calculated in real time using the formula above with the current timestamp as the segment end.
Step 2: Apply Rounding
rounded_total = round_up(raw_total, rounding_step)
Rounding always goes up (ceiling) to protect revenue. The rounding step is configurable in Settings > Pricing. For example, if the rounding step is 50 (representing $0.50 in a currency with 2 fraction digits), a raw total of $3.27 rounds up to $3.50.
Step 3: Apply Startup Fee Minimum
final_total = max(rounded_total, startup_fee)
The startup fee is the minimum charge for any session, regardless of duration. If the rounded total is less than the startup fee, the startup fee is charged instead.
Settlement
Settlement is the process of finalizing the billing for a session. There are two settlement stages:
Start Settlement (Prepaid Only)
When a prepaid session begins, a "start" settlement record is created. This captures:
- Calculated cost. The system-calculated cost for the purchased time.
- Amount charged. The amount the customer actually paid (usually the same as the calculated cost).
For "Lock at Purchase" prepaid mode, this locked amount determines the session's cost regardless of pricing changes during the session.
Stop Settlement
When any session (prepaid or postpaid) is stopped, a "stop" settlement record is created:
| Field | Description |
|---|---|
| Calculated cost | The system-calculated total from all pricing segments |
| Amount charged | The amount actually charged (defaults to the calculated cost) |
| Manually adjusted amount | If the cashier manually adjusted the price, the original calculated cost is preserved here |
| Commission rate | Payment method commission rate (as a percentage) |
| commission_fee | The calculated commission amount |
| fixed_fee | Payment method fixed fee |
| computed_timeline_snapshot | A JSON record of every pricing segment in the session |
The timeline snapshot provides a complete audit trail showing exactly how the cost was calculated, segment by segment.
Payment Method Fees
Each payment method can have two types of fees:
Commission (Basis Points)
The commission rate is expressed as a percentage. The commission fee is calculated by applying this rate to the amount charged.
Example: If the amount charged is $10.00 (1000 minor units) and the payment method has a 2.5% commission rate, the commission fee is $0.25 (25 minor units).
Fixed Fee
A flat fee deducted per transaction, regardless of the amount. For example, a credit card processing fee of $0.30.
Both fees are informational. They represent the cost to the business of accepting that payment method. They are recorded in the settlement but are not added to the customer's bill.
VAT (Value Added Tax)
VAT is configured as a percentage (0--100%) in Settings > Pricing. It is applied on top of the calculated session amount:
VAT = amount charged x (VAT rate / 100)
The VAT amount is displayed separately in the payment dialog so the cashier can see the tax breakdown.
Prepaid Pricing Modes
As described in Session Management, prepaid sessions support two pricing modes:
Lock at Purchase
When a prepaid session starts, the "start" settlement locks the charged amount. For the duration of the session:
- The session end time is fixed based on the purchased minutes.
- Even if the pricing schedule changes, the session continues until the locked time expires.
- The stop settlement uses the locked amount from the start settlement.
Live Schedule
The session's remaining time is recalculated continuously as pricing slots change:
- If the session enters a cheaper slot, the remaining time stretches (the customer gets more minutes for their money).
- If the session enters a more expensive slot, the remaining time contracts.
- The stop settlement reflects the actual pricing applied throughout the session.
Fraction Digits
The number of decimal places used for currency display is configurable (2--4 fraction digits). This affects how amounts are displayed in the UI but does not change the internal minor-unit calculations.
Example: With 2 fraction digits, $3.50 is displayed as "3.50". With 3 fraction digits, it would display as "3.500".
Practical Examples
Example 1: Simple Postpaid Session
- Base rate: $3.00/hour (300 minor units)
- Schedule: Standard slot (multiplier 1.0) all day
- Session: 10:00 AM to 11:30 AM (90 minutes)
- Startup fee: $0.50
Calculation:
Segment 1: (300 * 1.0 * 5400) / 3600 = 450 minor units ($4.50)
Total: max($4.50, $0.50) = $4.50
Example 2: Session Spanning Two Slots
- Base rate: $4.00/hour (400 minor units)
- Schedule: Standard (1.0) from 10:00--12:00, Happy Hour (0.5) from 12:00--14:00
- Session: 11:00 AM to 1:00 PM (120 minutes)
- Startup fee: $1.00
Calculation:
Segment 1 (11:00-12:00, standard): (400 * 1.0 * 3600) / 3600 = 400 ($4.00)
Segment 2 (12:00-13:00, happy hour): (400 * 0.5 * 3600) / 3600 = 200 ($2.00)
Total: $4.00 + $2.00 = $6.00
Final: max($6.00, $1.00) = $6.00
Example 3: Session with Pause
- Base rate: $2.00/hour (200 minor units)
- Schedule: Standard slot (multiplier 1.0) all day
- Session: Start 10:00, Pause 10:30, Resume 11:00, Stop 11:45
- Startup fee: $0.50
Calculation:
Segment 1 (10:00-10:30, active): (200 * 1.0 * 1800) / 3600 = 100 ($1.00)
Paused period (10:30-11:00): no charge
Segment 2 (11:00-11:45, active): (200 * 1.0 * 2700) / 3600 = 150 ($1.50)
Total: $1.00 + $1.50 = $2.50
Final: max($2.50, $0.50) = $2.50
Next Steps
- Session Management: Learn the full session lifecycle
- Settings: Pricing: Configure the base rate, rounding, and startup fee
- Settings: Pricing Schedule: Set up the 7x24 schedule grid
- Payment Methods: Configure payment methods with commission and fees