Customers & Categories
Everything for maintaining customer master records — their linked user account, addresses, categories, sales and credit settings, and tax identifiers — plus the two supporting look-up lists: Customer Categories and Advocate Associations.
A customer record is always attached to an existing User (see /staff/users) — every advocate, library, government office or company that AIR sells to must first exist as a user, and the Customer record adds the sales-facing details on top: addresses, credit terms, tax identifiers and category memberships. A user can exist without a customer record (staff, for example); a customer record cannot exist without a user.
Customer Resource
Nav: Customers → Customers. This is the master list of every customer account.
Columns
| Column | Shows |
|---|---|
| User ID | user.u_id — the linked user's ID (e.g. C-12345), searchable. |
| Name | The linked user's full name (via user.profile.full_name); shows — if the profile has no name set. |
| Delivery Priority | Badge showing Normal, High or Urgent — plain styling, no colour map. |
| Verified | Icon (tick/cross) for is_verified. |
| No Orders | Icon for do_not_accept_order — when on, this customer's orders are blocked further down the sale-order flow. |
| Salesperson | salesperson.u_id — the staff user this customer is assigned to. |
| Created | created_at, date + time. Hidden by default — switch it on from the column toggle. |
Filters
| Filter | What it narrows |
|---|---|
| Verified | Three-way (yes / no / all) on is_verified. |
| Do Not Accept Order | Three-way on do_not_accept_order. |
| Delivery Priority | Select over Normal / High / Urgent. |
Creating or editing a customer
Select New customer on the list, or Edit on a row. The form is the same for both, except User is locked once the record is created (a customer can never be re-pointed at a different user).
Section: Customer Details
Every relationship field here is a search-as-you-type Select over User records, and each one displays candidates using the same label pattern: "{u_id} — {full name}" — so you're always choosing a person by their ID and name together, never a bare ID.
| Field | Type | Required | Notes |
|---|---|---|---|
user_id | Select — User, label "{u_id} — {full_name}" | Yes | Searchable. Disabled on edit — the linked user cannot be changed after creation. |
delivery_priority | Select — DeliveryPriority | No | Normal / High / Urgent. |
parent_customer_id | Select — Parent Customer, same label pattern | No | Searchable, nullable. Links a sub-account (e.g. a branch) to a parent customer. |
salesperson_id | Select — Salesperson, same label pattern | No | Searchable, nullable. Disabled for non-super-admins — see callout below. Still saved even while disabled. |
ho_contact_person_id | Select — HO Contact Person, same label pattern | No | Searchable, nullable. The HO staff member this customer's queries route to. |
recovery_partner_id | Select — Recovery Partner, same label pattern | No | Searchable, nullable. Staff responsible for chasing overdue recovery on this account. |
so_confirm_by_id | Select — SO Confirmed By, same label pattern | No | Searchable, nullable. The staff member who confirms this customer's sale orders. |
If you are not a super administrator, when you create a customer the console automatically sets you as the Salesperson and disables the field — you cannot hand a new customer to a colleague by editing this field yourself, only a super admin can. If you leave it blank as a super admin, it defaults to you too. The field still submits its value even though it looks locked — it isn't simply ignored, it's fixed to your own user.
Section: Sales & Credit
Collapsible, collapsed by default.
| Field | Type | Required | Notes |
|---|---|---|---|
is_verified | Toggle | No | Marks the customer as verified (e.g. KYC/identity checked). |
do_not_accept_order | Toggle | No | When on, this customer is blocked from having new orders accepted. |
enforce_credit_limit | Toggle | No | Turns on credit-limit checking for this customer's orders. |
credit_limit | Numeric | No | Nullable. The ceiling checked when enforce_credit_limit is on. |
send_first_three_parts_on_credit | Toggle | No | Allows the first three monthly parts of a Full Set to go out even while payment is still pending. |
subscriber_expired | Toggle | No | Marks the subscription as lapsed. |
Section: Tax & ID
Collapsible, collapsed by default.
| Field | Type | Required | Notes |
|---|---|---|---|
gst_registration_number | Text (GSTIN) | No | Max 15 characters. |
gst_registration_type | Select — GstRegistrationType | No | Regular / Composition / Unregistered / Consumer / DeemedExport / Sez. Nullable. |
permanent_account_number | Text (PAN) | No | Max 10 characters. |
tan_number | Text (TAN) | No | Max 10 characters. |
aadhar_number | Text (Aadhaar) | No | Max 12 characters. |
company_cin | Text (CIN) | No | Max 21 characters. |
Relation managers
Open a customer record (via Edit) to reach two tabs beneath the form.
Addresses
Every delivery, billing or office address recorded for this customer.
- Select New address
Opens the address form below. There is no limit on how many addresses a customer can have.
- Choose the Type
One of
Primary,Billing,Shipping,OfficeorOther— required. A customer can have more than one address of the same type; the type is a label, not a uniqueness constraint. - Fill in the address
label(a free-text name for the address, e.g. "Chamber No. 4"),street,street2,city,pincode_idandregion_id(both searchable Selects — see Geography for how pincodes and regions are structured; Region matters more than it looks — read the note below), State (state_code: a searchable list of states, saved as the state's two-digit GST code; see the note below),country_code(defaults toIN),phone,mobile. - Set Default and Verified as needed
is_defaultmarks this as the address the customer's orders use unless another is chosen;address_verifiedmarks that HO has confirmed the address is deliverable. - Save
The address appears in the table with its Type, Street, City, and the Default/Verified icon columns. Use the row's Edit or Delete to change or remove it later.
Region is not just a label. A user who does not have customer.view_all — which is most Sales Executives — can only see a customer if one of that customer's addresses sits in a region inside their geography scope (or the customer has been assigned to them directly). An address with no Region makes the customer invisible to every scoped user. If an SE reports that a customer they just visited has vanished from their app, a blank or wrong Region on the address is the first thing to check.
Set it to the most specific region you can — the taluka if you know it, otherwise the district, otherwise the state. A scope matches a region and everything beneath it, so a district-scoped SE sees a taluka address inside their district, but a state-level address is above their scope and will not match.
Leaving Region blank is safe — the portal fills it in. If you pick a pincode and leave Region empty, the portal derives it from that pincode on save, taking the deepest one the pincode knows (taluka, else district, else state). This works the same here as it does in the SE field app. If you do pick a Region, your choice is kept as-is — so a Region that contradicts the pincode is your call to make, and worth a second look. Blank stays blank only when the pincode itself has no geography linked to it, which Geography explains how to fix.
The State of a sale order's shipping address is its GST place of supply: CGST + SGST within the home state, IGST elsewhere. That's why State is now a list of the seeded Indian states and union territories (saved as their GST codes, for example 27 for Maharashtra) instead of free text. The API accepts only those codes as well. You can still save an address without a State, but an order shipping to it can't confirm its lines if any line carries GST above 0 %. Older addresses with a code that isn't on the list are counted by the daily health check (Addresses with an invalid GST state code; see Diagnostics). Pick the right State to fix them.
The scoping described above applies to the field app, the API and Sale Orders — but not to this screen. Anyone who can open Customers in the console sees every customer, whatever their geography scope. Treat console access to Customers as portal-wide access, and grant it accordingly.
Categories
The set of Customer Categories this customer belongs to (a customer can hold more than one — for example both Advocate and a firm-level category).
- Select Attach
Opens a pre-loaded picker of existing categories — you choose from categories already defined on the Customer Categories list, you cannot create a new one from here.
- Pick the category and confirm
The category's Name, Code and Air Type badge appear in the table.
- To remove a membership, use Detach on its row
Detaching only removes the link between this customer and the category — it does not delete the category itself. Select multiple rows and use the bulk Detach action to remove several at once.
Planned: merge and bulk import
Two customer permissions are seeded but not wired to anything in this resource: customer.merge (merging two duplicate customer records into one) and customer.bulk_import (importing many customers at once, e.g. from a spreadsheet). Today, the Edit/Delete actions on the Customers list are the only actions available — there is no Merge button and no Import button anywhere on this page. When built, these will most likely appear as header actions on the Customers list (a bulk action for merge given two selected rows, and a header import action next to where New customer sits today) — but that UI does not exist in the console yet. In the meantime neither is a future promise — both are live API endpoints today: merging two customers and importing a CSV of customers both work, and so does verifying a customer (customer.verify), which likewise has no button here. If you need to merge duplicates or load a batch of customers, that work is done through the API rather than on this screen — ask a developer to run it. What is missing is the console UI, not the capability.
Customer Category Resource
Nav: Customers → Customer Categories. Categories classify customers by their nature — used for commission calculation and to control whether a customer needs manual re-validation when they already have a draft sale order. Built — full create/edit/delete.
Columns
| Column | Shows |
|---|---|
| Name | Searchable, sortable. |
| Code | Badge, searchable. |
| Air Type | Badge — Advocate, Library, Government, Individual, Company or Other; plain styling, no colour map. |
| Consider For Commission | Icon boolean. |
| Active | Icon boolean. |
| Created | Date + time, hidden by default. |
Filters
| Filter | What it narrows |
|---|---|
| Air Type | Select over all six AirType cases. |
| Active Status | Three-way on is_active. |
Creating or editing a category
Section "Category Details":
| Field | Type | Required | Notes |
|---|---|---|---|
name | Text | Yes | Max 100, unique. |
code | Text | Yes | Max 50, unique. Disabled once created. |
air_type | Select — AirType | Yes | Advocate / Library / Government / Individual / Company / Other. |
consider_for_commission | Toggle | No | When on, sales to customers in this category count toward salesperson commission calculations. |
validate_existing_draft_so | Toggle | No | When on, a customer already holding a draft sale order in this category is flagged for re-validation rather than proceeding silently. |
extended_parts_credit | Toggle — "Extended parts credit" | No | Default off. When on, customers in this category get a set's extended parts-on-credit limit instead of the regular one (see Products → Parts on credit). |
description | Textarea, full width | No | Free text. |
is_active | Toggle | No | Default on. |
There are no relation managers on this resource — category membership is managed from the customer's own Categories tab described above, using Attach/Detach.
Advocate Association Resource
Nav: Customers → Advocate Associations. A reference list of advocate/bar associations by district and state, used elsewhere to associate a customer with the local bar body they belong to. This is the simplest resource in the whole console — plain field-level CRUD with no relationships in its form and no relation managers. Built.
Columns
| Column | Shows |
|---|---|
| Name | Searchable, sortable. |
| District | Plain text — not searchable or sortable. |
| State Code | Plain text. |
| Active | Icon boolean. |
| Created | Date + time, hidden by default. |
Filters
Only one: Active Status, a three-way filter on is_active.
Creating or editing an association
Section "Association Details":
| Field | Type | Required | Notes |
|---|---|---|---|
name | Text | Yes | Max 255, unique. |
district | Text | No | Max 100. |
state_code | Text | No | Max 2. |
is_active | Toggle | No | Default on. |
Where customer data is used next
A customer record's salesperson, credit settings and category feed directly into the sale-order lifecycle documented in Sale Orders — for example enforce_credit_limit/credit_limit govern whether an order needs credit approval, and do_not_accept_order blocks new orders outright. Addresses and their linked pincodes/regions come from the structures explained in Geography.