Skip to content

Suppliers

External vendors — airlines, hotels, DMC, visa desks, transport, food. Managed from /suppliers, with a per-supplier detail page that exposes the ledger, hotel/FIT/food/transport assets, and transaction history.

Scope

  • List + categoriessrc/pages/suppliers/Suppliers.tsx. Tabbed by category (Ticketing / Visa / Hotel / Food / Transport / General), grid or list view, inactive toggle.
  • Detail pagesrc/pages/suppliers/SupplierDetailPage.tsx (route /suppliers/:id). Shows linked inventory (airline blocks, FIT, hotels, food, transfers) plus the transaction ledger.
  • Service layersrc/services/supplierService.ts. Fetch, create, update, soft/hard-delete supplier; fetch/create/update/delete supplier transactions.
  • Math helperssrc/pages/suppliers/suppliersMath.ts (+ tests) for filtering and category counts.

Pages

Suppliers.tsx/suppliers

Route gated by inventory.view today (src/App.tsx:171).

Route permission drift

Semantically the /suppliers route should be gated by suppliers.view, but no such permission exists and the route currently uses inventory.view. This is tracked in docs/PERMISSIONS.md §8 drift item 5. Until that's fixed, revoking inventory.view hides the suppliers page as a side effect.

Categories (Suppliers.tsx:89-96):

Key Label Icon tint
ticketing Ticketing blue
visa Visa purple
hotel Hotel orange
food Food green
transport Transport yellow
general General slate

hotel, food, transport categories show a city filter; others don't (Suppliers.tsx:98CITY_ENABLED_SUPPLIER_CATEGORIES).

Create-supplier form (Suppliers.tsx:107-121) collects: name, category, currency (defaults to DEFAULT_CURRENCY), city, logo URL, website URL, contact name/email/phone, address, notes, linked airline, GSTIN. Ticketing suppliers can be linked 1:1 to an airline record (airlineId).

SupplierDetailPage.tsx/suppliers/:id

Route gated by inventory.view (src/App.tsx:172). Aggregates everything hanging off one supplier:

  • Linked hotels, FIT inventory, airline blocks, food packages, ground transfers.
  • Supplier transaction ledger (built via buildSupplierLedgerData from src/services/ledgerService.ts).
  • Inline "Add transaction" dialog with type (debit / credit / refund / adjustment), amount + currency, date, description, reference link, linked GL account.

Service layer — src/services/supplierService.ts

Thin wrappers over /suppliers REST endpoints. All functions round-trip through mapSupplier / mapTransaction (supplierService.ts:105-144) to convert API date strings into Date objects and default currency/isActive.

Function Endpoint Purpose
fetchSuppliers({ includeInactive }) GET /suppliers List. Pass includeInactive=true to include soft-deleted.
createSupplier(payload) POST /suppliers Create.
updateSupplier(id, patch) PATCH /suppliers/:id Partial update.
deleteSupplier(id) DELETE /suppliers/:id Soft-delete (isActive=false).
hardDeleteSupplier(id) DELETE /suppliers/:id?hard=true Permanent remove.
fetchSupplierTransactions(supplierId) GET /suppliers/:id/transactions Ledger rows.
createSupplierTransaction(supplierId, payload) POST /suppliers/:id/transactions Debit / credit / refund / adjustment.
updateSupplierTransaction(id, patch) PATCH /suppliers/transactions/:id Edit a transaction.
deleteSupplierTransaction(id) DELETE /suppliers/transactions/:id Remove a transaction.

Transaction types (SupplierTransactionType) are debit (purchase), credit (inflow), refund, adjustment. See Suppliers.tsx:100-105 for the label/colour mapping.

Suppliers in finance

Suppliers are the counterparty on supplier payables in the GL.

  • Each transaction posted against a supplier creates or references a journal entry (SupplierTransaction.journalEntryId). createSupplierTransaction accepts an accountId for the offsetting GL account (bank / cash / expense).
  • The supplier ledger is rendered from the same journal data via buildSupplierLedgerData — it's the same underlying source as the Trial Balance, so the supplier ledger closing balance matches the payable control account.
  • TDS — when posting a supplier payment, users with finance.tds.deduct can apply a TDS rate; the handler splits the payment into a net payment + TDS liability line. Quarterly export via finance.tds.export.
  • Advance allocationfinance.allocations.supplier_advance allows allocating a previously-paid advance to a specific purchase (granular permission, seeded, not yet fully wired per PERMISSIONS.md §8).

Airlines vs ticketing suppliers

An airline (the entity that operates flights) and a ticketing supplier (the vendor through whom tickets are purchased, e.g. a GDS or consolidator) are separate records. A ticketing supplier can optionally link to one airline via airlineId (supplierService.ts:23, :42) — used so that inventory blocks and tickets roll up to the right finance counterparty.

Permissions

Canonical reference: docs/PERMISSIONS.md §4.1 and §6.13.

Action Permission Enforced at
View /suppliers inventory.view (should be suppliers.view — drift) Route App.tsx:171
View /suppliers/:id inventory.view (same) Route App.tsx:172
Add supplier suppliers.create <PermissionGate> + API
Edit supplier suppliers.edit <PermissionGate> + API
Delete supplier suppliers.delete <PermissionGate> + API
Add transaction suppliers.edit <PermissionGate>
Edit transaction suppliers.edit <PermissionGate>
Delete transaction suppliers.delete <PermissionGate>
Apply TDS on supplier payment finance.tds.deduct <PermissionGate> + API
Export 26Q CSV finance.tds.export <PermissionGate> + API

Roles that hold suppliers.* by default (PERMISSIONS.md §5.2): B2B_* (partial), OPS_MANAGER, OPS_EXEC (edit only), plus super-admin tier.

  • Partners — different concept (external sellers, not vendors).
  • Hotels / Airline Blocks / FIT / Ground Transfers — per-category inventory rolls up to one supplier.
  • Finance module — supplier payables, TDS, advance allocation.
  • PERMISSIONS.md §6.13 — authoritative action matrix.