Quotations
Pricing templates
Owners and managers manage per (country, visa type, entry type, sticker visa) pricing templates from an admin page — each template defines a Visa Fee and Consulting Fee (always present) plus any number of admin-defined optional extra fields, and an optional notes override.
Templates are hard-deleted, not soft-deleted, so a retired combination can be recreated immediately without hitting a stale uniqueness conflict. Historical quotes that referenced a deleted template keep their own frozen line items — they just lose the back-link to the template.
Quote wizard
A 5-step flow available from the dashboard and the Quotations page:
- Pick customer
- Pick service type — visa or ticket
- Pick the customer’s specific request
- Auto-populated (visa) or manually-entered (ticket) pricing fields, fully editable, with support for custom fields
- Live HTML preview before generating
Lifecycle
DRAFT (editable) → GENERATED (PDF rendered, pricing frozen, number assigned) → SENT (emailed, resendable)Drafts can be edited, deleted, or reopened from the Quotations list.
Auto-expiry
Quotes carry a 3-day expiry from creation and are filtered out of every read path automatically once expired — no background job needed for the filtering itself (a separate daily cleanup job later soft-deletes the expired rows; see Deployment & CI/CD).
Multi-currency
Staff can pick a currency (LKR, USD, EUR, GBP, AUD, INR) on the pricing step. The exchange rate is fetched and locked in permanently at creation time — it’s never re-applied later, so a sent quote’s price never silently drifts if rates change afterward. Rates are cached server-side for an hour to protect the free-tier exchange-rate API quota, and cached client-side for up to 3 days.