Skip to content

Instantly share code, notes, and snippets.

@aungkyawminn
Created December 30, 2025 16:03
Show Gist options
  • Select an option

  • Save aungkyawminn/ed99d6c1bdb5c9a4c129320c55003199 to your computer and use it in GitHub Desktop.

Select an option

Save aungkyawminn/ed99d6c1bdb5c9a4c129320c55003199 to your computer and use it in GitHub Desktop.

Ticket Price Calculation – Reverse Pricing Model

This document explains how Eventickat calculates ticket prices using a reverse pricing model where organizers specify what they want to receive, and the system calculates what customers will pay.


1. The Core Concept

Traditional Pricing (NOT our approach)

Organizer sets: Price = 50,000 MMK
Platform deducts: Fees & taxes
Organizer receives: 50,000 - fees = ??? (unknown until after)

Problem: Organizer doesn't know their actual payout until after fees are deducted.


Reverse Pricing (Our approach)

Organizer sets: Payout = 50,000 MMK (what they want to receive)
System calculates: Price = 56,952 MMK (what customer pays)
Platform guarantees: Organizer receives exactly 50,000 MMK

Benefit: Organizer knows their exact revenue upfront. All fees are added on top.


2. Why Reverse Pricing?

Business Goals

  1. Transparency for Organizers

    • They know exactly what they'll earn
    • No surprises after fees are deducted
    • Easier financial planning
  2. Simplicity for Customers

    • They see one final price
    • No separate fee line items
    • Clean checkout experience
  3. Platform Control

    • Platform controls commission structure
    • Can adjust fees without affecting organizer revenue
    • Clear audit trail

3. The Four Components of Price

Every ticket price is composed of exactly four components:

3.1 Payout Amount

What: Money the organizer receives
Set by: Event organizer
Example: 50,000 MMK

3.2 Platform Fee

What: Commission the platform earns
Based on: Payout amount (not final price)
Calculation: Percentage or fixed amount
Storage: Percentage stored as number (5 = 5%)
Example: 5% of 50,000 = 2,500 MMK

3.3 Tax Amount

What: Government tax (e.g., VAT, commercial tax)
Based on: Final price (creates circular dependency)
Calculation: Percentage of final price
Example: 5% of final price

3.4 Payment Fee

What: Payment gateway processing fee
Based on: Final price (creates circular dependency)
Calculation: Percentage + fixed amount
Storage: Rate stored as decimal (0.025 = 2.5%)
Example: 2.5% of final price


Important: Storage Format Differences

Platform Fee (platform_fee_rules table):

  • Stored as percentage: fee_value = 5 means 5%
  • Must divide by 100 in calculation

Payment Fee & Tax (settings table):

  • Stored as decimal: rate = 0.05 means 5%
  • Use directly in calculation (no division)

Why different?

  • Platform fee rules are admin-managed (easier to input as 5 vs 0.05)
  • Payment/tax settings are JSON config (standard decimal format)

4. The Calculation Challenge

The Circular Dependency Problem

We need to calculate:
price = payout_amount + platform_fee + tax_amount + payment_fee

But BOTH tax_amount and payment_fee depend on price:
tax_amount = price × tax_rate
payment_fee = (price × payment_rate) + payment_fixed

This creates TWO circular references:
tax_amount needs price
payment_fee needs price
price needs both tax_amount and payment_fee

The Solution: Algebraic Formula

We solve for price algebraically:

Let P = final price

Given:
- tax_amount = P × tax_rate (rate is decimal: 0.05 = 5%)
- payment_fee = (P × payment_rate) + payment_fixed (rate is decimal: 0.025 = 2.5%)
- P = payout_amount + platform_fee + tax_amount + payment_fee

Substitute:
P = payout_amount + platform_fee + (P × tax_rate) + (P × payment_rate) + payment_fixed

Rearrange:
P - (P × tax_rate) - (P × payment_rate) = payout_amount + platform_fee + payment_fixed
P × (1 - tax_rate - payment_rate) = base

Therefore:
P = base / (1 - tax_rate - payment_rate)

Where:
base = payout_amount + platform_fee + payment_fixed

Important: Rates are stored as decimals (0.05 = 5%), not percentages (5).


4.1 Integer Pricing & Rounding

Why Integer-Only Pricing?

MMK (Myanmar Kyat) has no decimal subdivisions:

  • ✓ Valid: 56,757 MMK
  • ✗ Invalid: 56,757.50 MMK (no 0.50 Kyat exists)

All monetary values must be integers for:

  • Legal compliance (currency regulations)
  • Payment gateway compatibility
  • Customer clarity (no confusing decimals)

Rounding Strategy

Step 1: Calculate Price (Round Up)

price = ceil(base / (1 - tax_rate - payment_rate))

Why ceil? Ensures customer pays enough to cover all fees. Better to round up 1 MMK than undercharge.

Step 2: Calculate Individual Fees

platform_fee = round(payout_amount × platform_fee_rate / 100)
tax_amount = round(price × tax_rate)
payment_fee_calculated = round(price × payment_rate + payment_fixed)

Step 3: Absorb Rounding Difference

payment_fee = price - payout_amount - platform_fee - tax_amount

Why absorb in payment_fee?

  • Payout amount: Fixed (organizer expectation)
  • Platform fee: Fixed (business rule)
  • Tax amount: Legal requirement (must be accurate)
  • Payment fee: Variable (can absorb 1-2 MMK differences)

Exact Sum Guarantee

Mathematical Guarantee:

price = payout_amount + platform_fee + payment_fee + tax_amount

Always true, enforced by code:

if ($sum !== $price) {
    throw new Exception("Fee breakdown sum doesn't match price");
}

Benefits for Auditing:

  • Database queries can validate sum = price
  • No rounding discrepancies
  • Clean financial reports
  • Transparent fee breakdown

5. Step-by-Step Calculation Flow

Step 1: Organizer Input

Organizer creates event ticket and sets:

  • Payout amount: 50,000 MMK

Step 2: Platform Fee Calculation

System looks up applicable platform fee rule based on:

  • Event-specific rule (highest priority)
  • Organizer-specific rule (medium priority)
  • Default rule (fallback)

Calculation:

  • Rule: 5% PERCENTAGE
  • Platform fee = 50,000 × 0.05 = 2,500 MMK

Step 3: Get Tax Configuration

System retrieves tax configuration:

  • Tax type: VAT
  • Tax rate: 0.05 (5% as decimal)
  • Applies to: Final price

Note: Tax will be calculated from final price (see Step 4)

Step 4: Calculate Price (Algebraic Solution with Integer Arithmetic)

System retrieves payment fee settings for payment method:

  • Payment method: VISA
  • Payment rate: 0.025 (2.5% as decimal)
  • Payment fixed: 0 MMK

Calculation:

base = payout_amount + platform_fee + payment_fixed
base = 50,000 + 2,500 + 0
base = 52,500 MMK

price = ceil(base / (1 - tax_rate - payment_rate))
price = ceil(52,500 / (1 - 0.05 - 0.025))
price = ceil(52,500 / 0.925)
price = ceil(56,756.76)
price = 56,757 MMK (integer)

Step 5: Calculate Individual Fees (Integer Rounding)

Now calculate tax and payment fee from the final price:

tax_amount = round(price × tax_rate)
tax_amount = round(56,757 × 0.05)
tax_amount = round(2,837.85)
tax_amount = 2,838 MMK (integer)

payment_fee_calculated = round(price × payment_rate + payment_fixed)
payment_fee_calculated = round(56,757 × 0.025 + 0)
payment_fee_calculated = round(1,418.925)
payment_fee_calculated = 1,419 MMK (initial)

Step 6: Absorb Rounding Difference

Adjust payment_fee to ensure exact sum:

payment_fee = price - payout_amount - platform_fee - tax_amount
payment_fee = 56,757 - 50,000 - 2,500 - 2,838
payment_fee = 1,419 MMK (final, exact)

Verification:

50,000 + 2,500 + 1,419 + 2,838 = 56,757 ✓ (exact match)

Step 7: Final Price

Customer pays: 56,757 MMK (integer, no decimals)


6. Breakdown Verification

Let's verify the math adds up:

Component          Amount (MMK)
────────────────────────────────
Payout amount         50,000  ← Organizer receives
Platform fee           2,500  ← Platform earns
Payment fee            1,419  ← Gateway charges
Tax amount             2,838  ← Tax authority
────────────────────────────────
Total Price           56,757  ← Customer pays ✓

Verification:

  • Customer pays: 56,757
  • Organizer gets: 50,000
  • Platform + fees + tax: 6,757
  • Math checks out ✓

7. When Calculations Happen

7.1 Event Creation (Admin/Organizer Side)

Timing: When organizer creates ticket
Input: Payout amount (50,000 MMK)
Output: Calculated price (56,757 MMK)
Purpose: Show organizer what customers will pay
Stored in: event_tickets table (payout_amount, price)

7.2 Purchase Time (Customer Side)

Timing: When customer completes payment
Input: Payout amount from event_tickets
Output: Recalculated fee breakdown
Purpose: Create immutable pricing snapshot
Stored in: purchase_tickets table (all fee components)

Why recalculate?

  • Platform fee rules may have changed
  • Payment method affects payment fee
  • Creates audit trail
  • Ensures accuracy at point of sale

8. Special Cases

8.1 Free Tickets

Payout amount: 0
All fees: 0
Final price: 0
Logic: No fees apply to free tickets

8.2 Early Bird Pricing

Two approaches:

Approach A: Different payout amounts

  • Normal payout: 50,000 MMK → Price: 56,952 MMK
  • Early bird payout: 40,000 MMK → Early price: 45,562 MMK
  • Organizer receives different amounts

Approach B: Same payout, promotional discount

  • Payout stays: 50,000 MMK
  • Early price: 45,000 MMK (promotional loss)
  • Organizer still receives 50,000 MMK
  • Platform absorbs difference

Current Implementation: Approach A (separate early_price field)

8.3 Multiple Payment Methods

Different payment methods have different fees:

  • AYAPAY: 0% + 0 MMK
  • VISA: 2.5% + 0 MMK
  • KPAY: 0% + 0 MMK
  • PAYPAL: 5% + 0 MMK

Challenge: Should ticket price vary by payment method?

Solution A: Variable Pricing (Not Recommended)

AYAPAY selected: Price = 56,000 MMK
VISA selected:   Price = 57,200 MMK  

Problem: Customer sees price change, causes confusion.

Solution B: Fixed Payment Fee Override (Recommended ✓)

Organizer selects accepted payment methods and system uses highest fee rate:

Event Settings:

Accepted Methods: VISA, KPAY, AYAPAY
Highest Fee: VISA (2.5%)
Payment Fee Override Rate: 0.025
Payment Fee Override Fixed: 0

Result:

Price shown: 57,200 MMK (calculated with 2.5%)
VISA selected: 57,200 MMK ✓
KPAY selected: 57,200 MMK ✓ (customer pays same, platform absorbs difference)

Benefits:

  • Consistent price displayed
  • No checkout surprises
  • Platform can incentivize lower-fee methods
  • Industry standard practice (Eventbrite, Ticketmaster)

9. Configuration & Rules

9.1 Platform Fee Rules

Storage: platform_fee_rules table
Scope: Default / Organizer-specific / Event-specific
Type: PERCENTAGE or FIXED
Time-based: Uses effective_from and effective_to

Priority:

  1. Event-specific rule (if exists)
  2. Organizer-specific rule (if exists)
  3. Default rule (fallback)

9.2 Payment Fee Settings

Storage: settings table (key: payment_fee_rules)
Format: JSON with fee per payment method
Structure: {percent: X, fixed: Y} per method

9.3 Tax Rules

Storage: settings table (key: tax_rules)
Format: JSON with tax configuration
Fields:

  • Country code
  • Currency
  • Tax type (VAT, commercial tax, etc.)
  • Tax rate (decimal)
  • Applies to (TICKET / PLATFORM_FEE / BOTH)

10. Immutability & Audit

Why Store Everything?

When a customer purchases a ticket, we store a complete snapshot:

  • payout_amount - What organizer receives (integer)
  • platform_fee - Platform commission (integer, calculated once)
  • payment_fee - Gateway fee (integer, calculated once)
  • tax_amount - Tax collected (integer, calculated once)
  • price - What customer paid (integer)
  • net_amount - Total amount charged (integer, same as price)
  • currency - Currency code

Why Never Recalculate at Settlement?

Problem with recalculation:

  • Platform fee rules may have changed
  • Tax rates may have changed
  • Payment fee settings may have changed
  • Creates audit nightmare
  • Breaks financial promises

Solution:

  • Calculate once at purchase time
  • Store complete breakdown (all integers)
  • Settlement only aggregates stored values
  • Historical accuracy guaranteed

Audit Validation Queries

Verify Fee Breakdown Sums Match Price:

-- Should return 0 rows (all tickets valid)
SELECT 
    id,
    price,
    (payout_amount + platform_fee + payment_fee + tax_amount) as calculated_sum,
    (price - (payout_amount + platform_fee + payment_fee + tax_amount)) as difference
FROM purchase_tickets
WHERE price != (payout_amount + platform_fee + payment_fee + tax_amount);

Verify No Decimal Values:

-- Should return 0 rows (all integers)
SELECT id, price, platform_fee, payment_fee, tax_amount
FROM purchase_tickets
WHERE price != FLOOR(price)
   OR platform_fee != FLOOR(platform_fee)
   OR payment_fee != FLOOR(payment_fee)
   OR tax_amount != FLOOR(tax_amount);

Monthly Revenue Breakdown:

SELECT 
    DATE_FORMAT(created_at, '%Y-%m') as month,
    COUNT(*) as tickets_sold,
    SUM(price) as total_revenue,
    SUM(payout_amount) as organizer_payouts,
    SUM(platform_fee) as platform_revenue,
    SUM(payment_fee) as payment_fees,
    SUM(tax_amount) as taxes_collected
FROM purchase_tickets
GROUP BY DATE_FORMAT(created_at, '%Y-%m')
ORDER BY month DESC;

11. Financial Flows

Revenue Distribution

Customer Payment (56,952 MMK)
    ↓
    ├─→ Payout to Organizer (50,000 MMK)
    ├─→ Platform Commission (2,500 MMK)
    ├─→ Payment Gateway (1,652 MMK)
    └─→ Tax Authority (2,500 MMK)

Settlement Logic

Platform collects from gateway: 56,952 MMK
Platform pays to organizer: 50,000 MMK
Platform keeps: 2,500 MMK (commission)
Platform forwards to tax authority: 2,500 MMK
Payment gateway already kept: 1,652 MMK (deducted at payment time)

12. Customer Experience

What Customer Sees

On Event Page:

VIP Ticket
Price: 56,952 MMK

At Checkout:

VIP Ticket × 1
Total: 56,952 MMK

Payment Method: [Select ▼]

After Payment:

Receipt
VIP Ticket: 56,952 MMK
Total Paid: 56,952 MMK

What Customer Doesn't See

  • Platform fee breakdown
  • Payment processing fee
  • Tax calculation details
  • Organizer payout amount

Why hidden?

  • Cleaner user experience
  • Reduces confusion
  • Industry standard practice
  • Single price is easier to understand

13. Organizer Experience

What Organizer Sets

When creating ticket:

Ticket Name: VIP Pass
Payout Amount: 50,000 MMK ← You set this

System shows:

Customer Price: 56,952 MMK ← System calculated
Your Payout: 50,000 MMK ← Guaranteed
Platform Fee: 2,500 MMK (5%)
Payment Fee: ~1,652 MMK (varies by method)
Tax: 2,500 MMK (5%)

What Organizer Gets

At settlement:

Tickets Sold: 100
Payout per Ticket: 50,000 MMK
Total Payout: 5,000,000 MMK ← Exact amount promised

Benefits:

  • Predictable revenue
  • No fee surprises
  • Easy financial planning
  • Clear commission structure

14. Key Principles

14.1 Organizer-Centric Pricing

The organizer's payout is the foundation of all pricing. Everything else is calculated from it.

14.2 Customer Simplicity

Customers see and pay one price. No hidden fees at checkout.

14.3 Platform Transparency

Platform fee is clear and auditable but not shown to customers.

14.4 Calculation Immutability

Once calculated and purchased, pricing is never recalculated.

14.5 Rule-Based Flexibility

Platform fees can vary by organizer, event, or time without breaking old tickets.


15. Summary

The Reverse Pricing Model:

  1. Organizer sets payout amount (what they want)
  2. System adds platform fee (based on payout)
  3. System adds tax (based on payout)
  4. System calculates price algebraically (including payment fee)
  5. Customer sees and pays final price
  6. All components stored as immutable snapshot
  7. Settlement uses stored values (never recalculates)
  8. Organizer receives exact payout promised

Core Philosophy: Organizers should know exactly what they'll earn. Customers should see exactly what they'll pay. Platform handles all the math in between.


End of document.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment