Item Master Extensions
You look after the item master at GadgetSphere — about 5,200 SKUs shared by three companies — and three questions keep coming back: why does a smartphone sold by the online company post to the retail company’s sales account?, where do product photos actually live?, and why did an e-Invoice go out without a classification code? All three are answered by records that hang off the item but are not the item: the extension rows, the images, the per-company GL code links and the LHDN classification. This page explains what each one is, which screen writes it and what reads it, then walks the one procedure a multi-company retailer needs — posting the same item to different accounts in different companies. Reading it takes fifteen minutes; the procedure takes about five minutes per product family.
Meet GadgetSphere
GadgetSphere Sdn Bhd (GS) sells flagship smartphones over the counter in 22 branches. GadgetSphere Online Sdn Bhd (GSO) sells the same SKUs from a web store, and GadgetSphere Distribution Sdn Bhd (GSD) sells them wholesale. One item record, SP-FLAG-256, serves all three — but GS wants its sales in SALES-SMARTPHONE-KV01-style branch accounts, GSO wants everything in SALES-ONLINE-GSO, and the group accountant wants purchases of that phone in COST-SMARTPHONE whichever company bought it. That is a per-company GL code problem, and it is the first thing this page solves.
Four things that hang off an item
An item in BigLedger is one header row (bl_fi_mst_item_hdr — code, name, type, UOM, tax, the GL code on the Main tab) plus lines for its units of measure and child items. Around that sit four families of records that the item screen writes and other parts of the system read:
| What you see on the screen | What it is | Where it is stored | Who has it |
|---|---|---|---|
| Checkboxes and small fields on Create / Edit — Track inventory, Serialised, Ecom sync, Remarks, Prefix | Extension rows — one row per named key, a plain key-value store on the item | bl_fi_mst_item_ext | 79 of 90 tenants; the largest business table on the platform at ~24 M rows |
| Manage Media tab | Images — one row per uploaded picture, pointing at a file in the platform’s file store | bl_fi_mst_item_image_hdr | 26 of 90 tenants, ~220,000 pictures |
| Company Linking → GL Codes tab | Per-company GL codes — up to six rows per item per company, keyed by what kind of transaction is posting | bl_fi_mst_item_company_glcode_link | 25 of 90 tenants |
| E-Invoice tab → Item classification | LHDN classification — a pointer from the item to one of the 45 codes the tax authority publishes | bl_fi_mst_item_classification_hdr (the list) and three columns on the item header | The list is in every tenant; 66 tenants have classified their items |
Take them in turn.
The extension rows — a key-value store on the item
Every item can carry any number of extension rows. Each row is a key (param_code, echoed in param_name), a type (param_type: STRING, NUMERIC, DATE, JSON or FILE) and a value in the matching column (value_string, value_numeric, value_datetime, value_json or value_file). The developers’ comment on the table says it plainly: “to store additional attributes for the item.” There is no registry of allowed keys — the backend checks that a row has a guid, belongs to the item, has a revision and a status, and nothing else.
In practice the 24 million rows across the platform are a small number of keys, and it helps to know which ones matter:
| Key | Written by | Read by | What it means for you |
|---|---|---|---|
TRACKING_INVENTORY (true / false) | The Create item screen, for Basic Item only, from the Track inventory checkbox | The Doc Item Maintenance applet itself, right after the first save, to decide whether to create the matching inventory item record (the physical stock record the Inventory Item Maintenance applet keeps); the item export | If this is false, the item never gets a stock record and never moves stock. Once the inventory item exists, changing the flag does not remove it |
SERIALIZED | The Create / Edit screen | Copied to the inventory item’s own extension row when the stock record is created; the item-code service | Whether each unit carries a serial number. The stock-side copy is the one the serial-number screens consult |
ECOM_SYNC_CHECKED | The Create screen and the CSV import (Ecom sync column) | The marketplace and web-store connectors, which also write it back | Whether the item is offered to e-commerce listings |
REMARKS, ABBREVIATION (from the Prefix field), ITEM_STATUS, OBSOLETE_DATE, GL_CODE, COUPON_VALID_PERIOD, MTO_GROUP_DISCOUNT_* | The Create / Edit screen, one row each when the field is filled | The same screen, and the voucher applet for ABBREVIATION | Ordinary fields that happen to be stored as rows |
ITEM_ATTACHMENT (type FILE) | Uploading a file (not an image) to the item | The screen; nothing posts or prints it | An attachment — a spec sheet, a warranty card PDF. See the next section for how it differs from an image |
SETTLEMENT_TYPE, CASHBOOK_CODE, FPX_*, CHARGES_*, SURCHARGE_TO_CUSTOMER_*, PAYMENT_PROVIDER_* | The PNS Settlement Method tab and the settlement-method import | The POS payment buttons and the payment-channel screens | Only on items that are payment methods, not stock. Covered on Payment aggregators and settlement methods |
EMP_ITEM_* (17 keys) | The migration from the legacy Wavelet EMP product | Nothing in the current product | Where the row count comes from: 48 tenants were migrated, and each migrated item carries 17 of these. They are inert. Do not delete them, and do not expect them on items created in BigLedger |
Three facts about how the rows behave, all verified against the applet and the backend:
- A key is one row, updated in place. The Edit screen finds the row by
param_nameand overwrites its value; it does not add a second row. Duplicates do exist (39 tenants hold about 6,800 duplicate item-and-key pairs, from imports and older versions), and where they do, the screen reads the first one it finds. - The document applets do not read these flags. Nothing in the POS or the sales and purchase document applets checks
TRACKING_INVENTORYorSERIALIZEDon the item. Whether a line moves stock is decided by the document type and by whether the inventory item record exists (see Costing internals). Whether a serial number is demanded is decided on the stock side. So a wrong flag shows up as a missing stock record or a missing serial prompt, never as a message naming the flag. ext_code,ext_type,ext_optionand the line scope are designed and unused. The comment onext_codedescribes a future template link; in production the column is empty on 99.99% of rows (the only system value isSYSTEM_DEFAULTon attachments).item_line_guid— “may be empty if the extension is meant for document header only” — is set on 2% of rows, all written by marketplace connectors.
Images and attachments — two tables, one word
The Manage Media tab and the attachments control on the item look similar and go to different places:
| You upload… | Endpoint the screen calls | Row created | Type marker | Served to the public? |
|---|---|---|---|---|
| A picture on the Manage Media tab | …/financial-items/add-images/{item} | bl_fi_mst_item_image_hdr, param_code ITEM_ATTACHMENT, param_type FILE | image_type = PUBLIC_READ_ONLY if you tick public | Yes — …/pub/image-file/{guid} serves it without a login |
| A file attached to the item | …/financial-items/add-files/{item} | bl_fi_mst_item_ext, same ITEM_ATTACHMENT / FILE markers | ext_type = PUBLIC_READ_ONLY if public | No public URL |
Both point at a row in the platform’s file store (value_file is the file’s guid — the column comment says exactly that). An item can have any number of images; the backend validates the row’s guid, item and status and nothing about count or order. The seq_no column exists for ordering and is empty on 98.5% of rows in production, so if your web store shows pictures in an unexpected order, the order is whatever the connector chose, not a sequence you set here.
Deleting an image from Manage Media marks the row DELETED and then removes the file record and the stored object — the row stays (28% of image rows on the platform are deleted ones), the picture is gone. Creating an alias item copies the original’s images as new files.
Images reach the marketplaces through the marketplace-sync job, which pushes item images to listings. Pictures the connectors pull from a marketplace are recorded under the marketplace item’s own records, which may point back at an image row here but are not the same thing.
Per-company GL codes — which account a line posts to
This is the part that answers GadgetSphere’s first question, and it needs the whole rule, because the GL code link is the third of four places the posting engine looks:
- A GL code on the document line wins outright (the accounts clerk picked it on the invoice).
- Otherwise a GL code on the document header — and note this beats the item link.
- Otherwise the item-company link for this company and this item, filtered by the transaction code.
- Otherwise the company’s default GL code for the same transaction code — the “Default GL Codes” that every company must have, or FINAL fails with MISSING_DEFAULT_GL_CODE.
The transaction code is set by the document, not by you: SALES for sales-side documents, PURCHASE for purchase-side, SALES_RETURN and PURCHASE_RETURN for the return documents (sales return, purchase return, consignment return). Two more codes — SALES_DISCOUNT and PURCHASE_DISCOUNT — are offered on the screen and accepted by the backend, and the posting engine resolves a discount code but never uses it for the lookup, so a link saved under them has no effect today. Documents that post under other codes — a purchase GRN stock-in (INVENTORY_NOT_INVOICED), a stock adjustment (STOCK_ADJUSTMENT), consignment stock (CONSIGNMENT_STOCK) — cannot be given an item-level link at all, because the backend only accepts the six codes above; they always use the company default unless the line or header names a GL code.
A link row is item + company + chart of accounts + GL code + transaction code. The backend checks that each of those exists when given and that the code is one of the six; it does not check that the combination is unique, and the posting engine takes the first matching row it finds, in no defined order. Keep one row per item, company and code. Note also what the screen does on first save (below): it writes a row for every one of the six codes, including the ones you left empty, which is why 38% of link rows on the platform carry no GL code. An empty row is harmless — the engine falls through to the company default — but it is why the GET listing looks fuller than what you set.
The LHDN classification — 45 codes, one list
The Classifications menu shows the list the Malaysian tax authority publishes for e-Invoice lines: 45 codes from 001 (Breastfeeding equipment) to 045 (Self-billed – non-monetary payment to agents, dealers or distributors), under one type, MALAYSIA-EINVOICE. The list is seeded into every tenant by the platform; every one of the 90 tenants has exactly these 45 rows and no tenant has added a second type, although the screen lets you add a row. The combination of code, type and status is unique.
An item’s classification is three columns on its header — the list row’s guid, its code and its description — set on the item’s E-Invoice tab, or inherited from a category’s e-Invoice defaults or from a template when the field is empty. One behaviour of that tab to know about: if the item has no classification and no template or category supplies one, opening the E-Invoice tab pre-fills 022 – Others and treats it as a change. It is a convenience for accessories; it is wrong for a smartphone, and it is silent, so check the field rather than trusting the pre-fill.
A document line carries its own copy of the code and description, and at submission the rule is: the line’s own classification is used; if the line has none, the item’s; if neither, the line goes out without one — and classification is a mandatory field on an LHDN e-Invoice line. For a retailer the code is almost always 003 (Computer, smartphone or tablet) for the hardware, 022 (Others) for accessories that fit nothing else, and 044 (Vouchers, gift cards, loyalty points) for gift cards. 66 of the 81 tenants with items have classified them; on average four items in five carry a code. The rest is the source of “submitted without classification” rejections.
Before you start
- You are editing items in the Doc Item Maintenance applet and have the permission set that includes
API_TNT_DM_ITEM_COMPANY_GLCODE_LINK_CREATE(the applet’s OWNER or ADMIN roles have it). - The item is already linked to the company on the Company Linking tab — the GL Codes tab lives inside that link, so an item
GSOcannot see cannot be givenGSOaccounts. - The GL codes you want to post to exist in the company’s chart: for GadgetSphere,
SALES-ONLINE-GSOandCOST-SMARTPHONEinGSO’s chart,SALES-SMARTPHONE-KV01inGS’s. See the Chart of Accounts setup guide. - You have one test invoice you can post and void in each company.
Step 1: Give the item its accounts in each company
By the end of this step, a sale of SP-FLAG-256 by GSO posts to SALES-ONLINE-GSO and a purchase of it by either company posts to COST-SMARTPHONE, without anyone picking a GL code on the invoice.
Doc Item Maintenance → Items → open SP-FLAG-256 → Company Linking tab → open the GSO link → GL Codes tab.
You see six dropdowns, each filtered to GSO’s chart:
| Screen label | Transaction code stored | Used when |
|---|---|---|
| Sales/Revenue GL Code | SALES | The item is sold by GSO |
| Sales/Revenue Return GL Code | SALES_RETURN | A GSO customer returns it |
| Sales/Revenue Discount Code | SALES_DISCOUNT | Never read by posting today — leave empty |
| Purchase/Expenses GL Code | PURCHASE | GSO buys it |
| Purchase/Expenses Return GL Code | PURCHASE_RETURN | GSO returns it to the supplier |
| Purchase/Expenses Discount Code | PURCHASE_DISCOUNT | Never read by posting today — leave empty |
Pick SALES-ONLINE-GSO for the first, SALES-ONLINE-GSO for the return (a return credits the same account), COST-SMARTPHONE for the purchase and the purchase return. Save. Behind the scenes the screen writes one link row per dropdown — four with your codes and two empty ones for the discount fields — and on a later visit it updates the rows in place.
Repeat for the GS link with SALES-SMARTPHONE-KV01 and COST-SMARTPHONE. If you have 400 smartphone SKUs to do, use Import Item → Doc Item With GL Code instead. Despite the name, this import is exactly these links: its template has five columns — ITEM_CODE, COMPANY_CODE, CHART_OF_ACCOUNT_CODE, GL_CODE, TXN_CODE — one row per item, company and transaction code, and TXN_CODE must be one of the six codes above or the row fails with TXN_CODE_IS_NOT_VALID. The import matches an existing row on all four keys, so re-importing the same code is idempotent, but importing a different code for the same item, company and transaction code adds a second row rather than replacing the first — delete the old one first.
The most common failure: the sale still posts to the company default. Nine times out of ten the invoice header carries a GL code (a template or a default selection put it there), and the header beats the item link. Open the posted invoice, look at the header’s GL code field, and clear it on the template.
Step 2: Put a picture on the item
Doc Item Maintenance → Items → open the item → Manage Media tab → upload.
Tick public if the web store or a marketplace listing should be able to show it — that is what sets PUBLIC_READ_ONLY and makes the public URL work. Leave it unticked for internal reference shots. There is no primary-image flag and no reliable ordering; if your storefront needs a specific hero image, set it on the storefront side.
The most common failure: the picture shows in BigLedger and not on the listing. It was uploaded without public, or it went in as an attachment (an extension row) rather than an image. Re-upload it on Manage Media with public ticked.
Step 3: Check the classification before the first e-Invoice
Doc Item Maintenance → Items → open the item → E-Invoice tab → Item classification.
For SP-FLAG-256 choose 003 – Computer, smartphone or tablet. To do a whole category at once, set the category’s e-Invoice defaults; items created under it inherit the code, and the E-Invoice tab fills it in for existing items whose field is empty when you open them. Then run the e-Invoice discrepancies report after the first day’s submissions — an item without a classification produces a rejected line, not a warning at save time.
What success looks like
Post one GSO cash bill for SP-FLAG-256 (no GL code on the header or line) and open its journal: the revenue line is SALES-ONLINE-GSO. Post one GS invoice for the same item: SALES-SMARTPHONE-KV01. Post a GSO purchase invoice for it: COST-SMARTPHONE. On the item, the Manage Media tab shows the picture with public on, and the E-Invoice tab shows 003. Void the three test documents. Five minutes.
Common mistakes
| Mistake | What you see | Fix |
|---|---|---|
| Setting GL codes on the item’s Main tab and expecting them to differ per company | Every company posts to the same account | The Main-tab GL code is the item’s single code (used by Account Code items). Per-company accounts live on the Company Linking → GL Codes tab |
| A GL code on the document header | The item link is ignored on every line of that document | Clear the header GL code on the document template; the header beats the item link |
| Filling the Discount GL code fields | Nothing happens | Posting never reads SALES_DISCOUNT / PURCHASE_DISCOUNT links today. Discounts post through the company default |
| Two link rows for the same item, company and code (after an import with a new code) | The account changes from one invoice to the next | List the links (GET …/item-company-glcode-links/query), delete the older row; keep one row per code |
| Track inventory left unticked at create | The item never appears in stock balance; a stock-out document line for it moves nothing | Open the item on the Edit screen, tick Track inventory and save — the Edit screen’s save creates the stock record when the item has none. Confirm it exists in the Inventory Item Maintenance applet before selling the item |
| Image uploaded as an attachment, or without public | Picture visible in BigLedger, missing on the listing | Re-upload on Manage Media with public ticked |
| No classification on the item or the line | e-Invoice line rejected by LHDN | Set it on the item or its category; re-submit |
| Opening the E-Invoice tab of an unclassified item and saving | The item is now 022 – Others, whatever it is | The tab pre-fills 022 when nothing else supplies a code. Pick the right code before you save |
Related documentation
- Doc Item Maintenance applet — every tab and setting on the item screen
- Inventory Item Maintenance applet — the stock record an item’s
TRACKING_INVENTORYflag creates - Costing internals — what happens to stock and cost when a line moves
- Payment aggregators and settlement methods — the settlement-method family of extension rows
- e-Invoice submission mechanics — where the classification ends up
- Chart of Accounts setup guide — the accounts the GL Codes tab offers