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 + categories —
src/pages/suppliers/Suppliers.tsx. Tabbed by category (Ticketing / Visa / Hotel / Food / Transport / General), grid or list view, inactive toggle. - Detail page —
src/pages/suppliers/SupplierDetailPage.tsx(route/suppliers/:id). Shows linked inventory (airline blocks, FIT, hotels, food, transfers) plus the transaction ledger. - Service layer —
src/services/supplierService.ts. Fetch, create, update, soft/hard-delete supplier; fetch/create/update/delete supplier transactions. - Math helpers —
src/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:98 — CITY_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
buildSupplierLedgerDatafromsrc/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).createSupplierTransactionaccepts anaccountIdfor 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.deductcan apply a TDS rate; the handler splits the payment into a net payment + TDS liability line. Quarterly export viafinance.tds.export. - Advance allocation —
finance.allocations.supplier_advanceallows 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.
Related
- 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.