---
title: Product codes
order: 5
updated: 2026-07-12
---

# Product codes

Product codes are the specific variants that live under a *Product Head*. If your head is *Steel Pipes*, the codes might be `SP-50MM-A`, `SP-75MM-A`, and so on. Codes are what actually get picked on enquiries, quotations, orders, purchase orders, and stock records — the head is just the umbrella they hang under. Each code carries its own units, description, HSN code, and tax rate, inheriting sensible defaults from its parent head but able to override them where a variant genuinely differs.

## Before you start

- The parent product head must already exist, and its *Allowed Units* / *Allowed Makes* must cover everything the code needs. A code can only be given units the head allows. See [Products](/docs/records/products).
- Settle on a code-naming format everyone in your firm follows. There is no automatic uniqueness check, so consistent naming is what keeps searches clean.
- Product units are shared firm-wide and are maintained under *Data Entry → Utilities → Product Units*. See [Utilities](/docs/records/utilities).

## Open the product codes screen

1. Open *Data Entry* in the sidebar and click *Products*.
2. Find the product head in the list and click its *Update Product Code* button. If you only have view permission the button reads *View Product Code* instead.

The codes screen shows *Product Codes* as the title, the parent head name (*Product Head : …*), a search box, and a paged list of every code under that head. Codes are listed alphabetically by name and load in batches as you scroll.

### Who can do what

Every action on this screen is gated by a database permission, and the same permission is re-checked on the server for every request:

- *+ Add Product Code* appears only with *Add Product Code* (`database.addProductCode`).
- *Edit* appears with *Edit Product Code* (`database.editProductCode`). Without it — but with *View Product Code List* (`database.viewProductCodeList`) — you get a read-only *View* button instead.
- *Documents* appears only with *Edit Product Code*.
- *Delete* appears only with *Delete Product Code* (`database.deleteProductCode`).
- The *Transfer Code* menu on the *Products* page needs *Edit Product Code*.

If you are missing a permission the corresponding button simply does not render, and the API rejects the call with a `403` even if it is sent directly.

## Add a code

Click *+ Add Product Code* to open the *Add Product Code* modal. It opens pre-filled with the parent head's defaults, so in many cases you only need to set the name.

### Product Code Name

The variant's identifier, for example `ERW Pipe 25mm`. **Required** — saving is blocked (client and server) if it is empty. There is no enforced uniqueness, so two codes under the same head can share a name; keep names distinct yourself to avoid confusion in searches and on documents.

### Allowed Units

The units this code can be sold or bought in (for example `Nos`, `Meter`, `Kg`). **At least one unit is required.** The picker only lists units the parent head already allows — you cannot grant a code a unit the head does not carry. When the modal opens for a new code, **every** unit the head allows is pre-selected; trim it down to the ones that actually apply to this variant. Manage the master unit list under [Utilities](/docs/records/utilities).

### Default Description

A rich-text description pre-filled onto documents where this code appears. It starts out seeded with the parent head's *Default Description*, which you can keep, edit, or clear. The text is sanitised on the server before it is stored, so pasted markup that contains anything unsafe is stripped.

### HSN Code

The numeric HSN classification code, for example `7304`. It is a whole number only (no decimals, minimum `0`) and defaults to the head's *Default HSN Code*. If the parent head has *HSN code is same for all product codes* switched on, this field is **locked** to the head's value and cannot be edited here (see the gotcha below).

### Default Tax Rate

The GST slab applied to this code. Pick one of the fixed slabs:

- `0% — Exempt`
- `5% — GST`
- `12% — GST`
- `18% — GST`
- `28% — GST`

It defaults to the head's *Default Tax Rate*. If the parent head has *Tax rate is same for all product codes* switched on, this field is **locked** to the head's value.

### HSN Code is always the same

A per-code checkbox (**off by default**). When ticked, the HSN code is frozen for this variant: *"You will not be able to change the HSN Code while adding an Enquiry."* Use it when a code's HSN should never be overridden at enquiry time. This is a code-level lock and is independent of the head-level *HSN code is same for all product codes* setting — though if the head-level setting is on, this checkbox is forced on and disabled.

### Tax rate is always the same

The same idea for the tax rate (**off by default**). When ticked, the tax rate cannot be changed while adding an enquiry. Forced on and disabled when the head enforces a firm-wide tax rate.

Click *+ Add Product Code* at the bottom to save. The server re-validates the payload, confirms the parent head exists, and sanitises the description before storing the code.

## Find a code

Use the *Search product codes…* box above the list. Typing runs a fuzzy search (debounced by roughly a third of a second) scoped to the current head only, returning up to `30` matches. Clear the box to return to the full paged list.

## Edit a code

Click *Edit* on a row to open the *Edit Product Code* modal. It loads the code's current values and exposes the same fields as the add form. A few behaviours differ:

- The values shown for HSN and tax follow the head's enforcement: if the head enforces a uniform HSN or tax, the modal shows the head's value (locked), not any older per-code value.
- **Removing a unit that is still in use is blocked.** If you deselect a unit and that unit is still referenced by an enquiry (or other document) for this code, saving fails and a *Where used* panel opens listing exactly where the unit is used. Restore the unit or clean up those records first. Nothing is saved until the conflict is cleared.
- The product head cannot be changed from this modal. To move a code to a different head, use *Transfer a code to another head* below.

*View* (read-only) shows the same layout with every field disabled and no save button.

## Attach documents

With *Edit Product Code* permission, each row shows a *Documents* button that opens the *Documents* modal for that code — datasheets, drawings, certificates, and the like.

- Drag and drop files onto the drop zone, or click *browse* to pick them.
- Each file may be up to `50 MB`. Oversized files are skipped with a message; there is no overall total cap on a product code's documents.
- Each attachment lists its filename, size, upload date, and who uploaded it. *View* opens a preview; *Remove* deletes the file after a small confirmation.

## Delete a code

Click *Delete*, then confirm in the *Delete Product Code* dialog. Deletion is permanent, but it is guarded: the server checks whether the code is referenced **anywhere** — not just enquiries, but sales orders, purchase orders, stock arrivals, deliveries, transfers, adjustments, conversions, vendor invitations, and drafts, among others. If any reference exists the delete is refused and a *Where used* panel opens showing every record type that still points at the code, so you can decide what to do. A code with no references is removed immediately. See [Deleting records](/docs/records/deleting-records) for how the shared "where used" guard works across the app.

## Transfer a code to another head

If a code was filed under the wrong product head, you can move it without re-creating it or touching the enquiries, orders, and stock records that use it. Those records resolve the head from the code at read time, so after the move they simply start showing the code under its new head — no historical amounts change.

1. On the *Products* page, open the options menu (the table's settings/slider dropdown at the top right) and choose *Transfer Code*. This entry only appears if you can edit product codes.
2. In the *Transfer Product Code* modal, on the *Move from* side pick the **source head**, then the **product code** within it.
3. On the *Move to* side pick the **destination head**. It must be different from the source — the field shows *"Must differ from the source head"* otherwise.
4. Click *Transfer Code*, review the *Confirm Transfer* summary, and confirm.

Before the move goes through, the server re-checks that the destination head can actually hold the code. The transfer is **blocked** — with a message telling you what to fix — if any of these fail:

- **Units** — the destination head does not allow one of the units the code uses.
- **Makes** — the destination head does not allow a make the code is used with on any enquiry or order.
- **HSN** — the destination head enforces a fixed HSN code that differs from the code's.
- **Tax** — the destination head enforces a fixed tax rate that differs from the code's.

When a make conflict is the cause, a *Where used* breakdown shows exactly where those makes are referenced. Fix the destination head (add the missing units/makes) or align the code's HSN/tax first, then try again. The move is a single, all-or-nothing change: nothing is altered until every check passes. As a safeguard against stale screens, the server also verifies the code still belongs to the source head you selected; if someone else moved it in the meantime you are asked to refresh and retry. Makes are managed under [Manufacturers](/docs/records/manufacturers).

## Common questions

### Why can I not edit the HSN code or tax rate on this code?

The parent product head has been set so that all codes share its value. Open the product head, untick *HSN code is same for all product codes* (or *Tax rate is same for all product codes*), then come back and edit the code. While the head enforces the value, the field is locked here and the server ignores any value sent for it — it always uses the head's. See [Products](/docs/records/products).

### What is the difference between the head-level and code-level "same" settings?

The head-level *…is same for all product codes* forces **every** code under the head to the head's HSN or tax and locks the field on each code. The code-level *HSN Code / Tax rate is always the same* checkbox is narrower: it lets the code keep its own value but prevents that value being overridden when someone adds an enquiry for it.

### Why can't I add a unit to a code?

The unit picker only offers units the parent head allows. Add the unit to the head's *Allowed Units* first (or add it to the master list under [Utilities](/docs/records/utilities)), then it becomes selectable on the code.

### I removed a unit and the save was blocked — why?

That unit is still used by an enquiry or other document for this code. The app will not silently break those records. The *Where used* panel shows where it is used; update or clear those records, then remove the unit.

### Can the same code name exist under two different product heads?

Yes. A code belongs to exactly one head, and the app does not stop you reusing a similar name under a different head — they are treated as separate items. Consistent naming is on you.

### Will moving a code to another head change past quotations or orders?

No. Every enquiry, order, and stock record derives the head from the code at read time, so a transfer only changes which head the code appears under going forward. Historical numbers and amounts are untouched.

### How do product codes end up on a quotation?

You pick a product head and one of its codes while building an enquiry; the code's description, unit, HSN, and tax defaults flow onto the quotation from there. See [Generate a quotation](/docs/enquiry-bank/generate-quotation).
