Payments & Coupons
Relevant source files
The following files were used as context for generating this wiki page:
The Payments & Coupons module handles the financial lifecycle of service transactions within the Subito platform. It encompasses order creation, payment processing via external gateways (specifically Juspay), refund management, and the application of promotional incentives through a robust coupon system.
This module ensures that financial transactions are tracked accurately from the initial CREATED state of an order through to final CAPTURED or REFUNDED statuses. It integrates closely with the booking system to calculate subtotals, GST, and final amounts after applying discounts or surge pricing.
Sources: packages/db/src/schema/payments.ts, packages/db/src/schema/coupons.ts, packages/db/drizzle/0000_normal_the_order.sql:13-16
Payment Architecture
The payment system is structured around four primary entities: Orders, Payments, Refunds, and Saved Payment Methods. The system primarily uses INR as the default currency and integrates with the Juspay HyperSDK for transaction processing.
Entity Relationships
The following ER diagram illustrates how financial entities relate to users and bookings.
The diagram above shows the one-to-many relationship between orders and payments, as well as the linkage between bookings and financial records.
Sources: packages/db/src/schema/payments.ts:139-182, packages/db/drizzle/0000_normal_the_order.sql:659-693
Financial Workflow and Statuses
Transactions follow a strict state machine defined by PostgreSQL enums. An order begins in the CREATED state and moves toward COMPLETED or FAILED.
| Entity | Possible Statuses |
|---|---|
| Order | CREATED, PENDING, AUTHORIZED, CAPTURED, COMPLETED, FAILED, CANCELLED, REFUND_INITIATED, REFUNDED |
| Payment | PENDING, AUTHORIZED, CAPTURED, FAILED, CANCELLED, REFUNDED |
| Refund | INITIATED, PROCESSING, COMPLETED, FAILED |
Sources: packages/db/src/schema/payments.ts:18-47, packages/db/drizzle/0000_normal_the_order.sql:12-16
Payment Methods
The system supports multiple payment modes, categorized by the payment_method enum:
- UPI: Unified Payments Interface (e.g., Google Pay, PhonePe).
- CARD: Credit and Debit cards (tracks last four digits, brand, and expiry).
- NETBANKING / WALLET: Digital banking and mobile wallets.
- COD: Cash on Delivery for physical settlements.
Sources: packages/db/src/schema/payments.ts:36-43, packages/db/src/schema/payments.ts:119-130
Transaction Identification
Unique identifiers are generated for various financial events to maintain idempotency and traceability:
- Order ID: Prefixed with
ORDfollowed by a base-36 timestamp and a random string. - Payment ID: Prefixed with
PAYfor individual transaction attempts. - Refund ID: Prefixed with
RFfor tracking reversals.
Sources: apps/api/src/utils/helpers.ts:11-30
Coupon System
The coupon system allows for dynamic discounting based on flat rates or percentages. It includes sophisticated applicability rules to target specific service categories or listings while enforcing usage limits.
Coupon Configuration Data Model
| Field | Type | Description |
|---|---|---|
code | varchar(50) | Unique promotional code (e.g., "WELCOME10"). |
discountType | enum | PERCENTAGE or FLAT. |
discountValue | decimal | The numeric value of the discount. |
minCartValue | decimal | Minimum amount required in the cart to apply the coupon. |
maxDiscount | decimal | Ceiling for percentage-based discounts. |
maxUsagePerUser | integer | Limit on how many times a single user can use the code. |
isFirstTimeOnly | boolean | Restricts use to the user's first successful booking. |
Sources: packages/db/src/schema/coupons.ts:17-43, packages/db/drizzle/0000_normal_the_order.sql:351-375
Application Flow
When a coupon is applied to a booking, a record is created in the coupon_usage table to track the specific discount amount granted and ensure usage limits are enforced.
The diagram depicts the validation and calculation steps required before a coupon discount is finalized.
Sources: packages/db/src/schema/coupons.ts:47-59, packages/db/src/seed.ts:403-445
Financial Calculations
The project utilizes shared utility functions to ensure consistency in tax and currency formatting across the API and database seeding processes.
GST and Rounding
The system standardizes on a 2-decimal precision for all financial values. GST is typically calculated at a default rate of 18% unless overridden by app settings.
export function roundToTwoDecimals(num: number): number {
return Math.round(num * 100) / 100
}
export function calculateGST(amount: number, rate = 0.18): number {
return roundToTwoDecimals(amount * rate)
}
Sources: packages/shared/src/utils/index.ts:1-7, apps/api/src/utils/helpers.ts:63-69
Currency Formatting
Amounts are formatted for the Indian locale (en-IN) using Intl.NumberFormat to handle Indian Rupee (INR) symbol placement and decimal grouping.
Sources: packages/shared/src/utils/index.ts:35-42
Summary
The Payments & Coupons module provides a centralized architecture for all financial operations. By separating Orders from specific Payment attempts, the system supports multiple retries and detailed gateway logging via Juspay. The Coupon system further complements this by providing flexible marketing tools with granular control over service applicability and user usage limits.
Sources: packages/db/src/schema/payments.ts, packages/db/src/schema/coupons.ts