Skip to content

POS Customer Display

Overview

POS Customer Display is the screen the shopper looks at while the cashier rings up a sale. It shows the cash bill’s lines as they are added, the running subtotal, tax, discount, rounding, total, amount paying and change, and — when the counter has nothing in the basket — an idle screen with the branch name, the date and time, a message you choose and a carousel of images you upload.

It is read-only. It creates nothing, settles nothing, and never calls a document endpoint. Everything it shows comes from the POS General Applet’s local draft, read out of the same browser database.

Where it fits

UpstreamThis appletDownstream
POS General Applet writing the current cash bill into its offline draft (draft_hdr, draft_line) in the browser’s IndexedDB database POS_<tenantCode>Reads the same database live and renders itThe shopper’s eyes. Nothing else.
The branch and sales-agent rows POS General stores in its settings tableThe idle screen’s store name and sales-agent name
Images uploaded in Settings → Attachment Settings (bl_pos_customer_view_attachment)The idle carousel
The two applets are coupled through one browser’s IndexedDB, not through the server. Both open new Dexie('POS_' + tenantCode). The display therefore only shows a cash bill that is being rung up in the same browser profile on the same machine — typically the cashier’s browser with the display opened in a second window on a second monitor. A display opened on a separate device, a separate browser, or a private window sees an empty database and stays on the idle screen forever.

Screens and menus

MenuRouteWhat it shows
Cash BillposThe display itself. Three panels are registered: POS Main (totals), Item (the line grid) and Message (the idle screen). The container switches to Item when the draft has at least one line and to Message when it has none.
Settings → Application Settingssettings/application-settingsDisplay Settings → Idle Screen Settings: a single MESSAGE field
Settings → Attachment Settingssettings/attachment-settingsThe image library for the idle carousel
Personalization → Default Selectionpersonalization/personal-default-selectionDefault Branch and Default Location

Totals panel (POS Main): SUBTOTAL, TAX, DISCOUNT, ROUNDING, TOTAL, PAYING, CHANGE, all formatted to two decimals, plus the image carousel.

Line grid (Item): NAME, UNIT PRICE, QTY, AMOUNT, with an expandable child row carrying the same four columns for make-to-order component lines.

Idle screen (Message): the branch name and the sales-agent name from the POS settings row, a clock that ticks every second, and the configured message.

The shared settings navigation also renders links to Permission Wizard, Permission Set, User Permission, Role Permission and Release Notes, because that markup is fixed in blg-shared-utilities. None of those routes exist in this appletapp.routing.ts registers only application-settings and attachment-settings under settings, so each of those links falls through to the applet’s 404. The permission, webhook and feature-visibility components are imported at the top of the routing file and never used.

Screenshots needed

No screenshots exist for this applet. A capture session should take: the idle screen with a message and a carousel image; the display mid-sale with two or three lines and the totals panel; Settings → Application Settings; and Settings → Attachment Settings with the listing and the Edit Attachment form. Capture on a scratch tenant — the idle screen prints the branch name and sales-agent name.

Configuration

Before you can use it

PrerequisiteWhereWhy
POS General installed and in use in the same browserPOS General AppletIt is the only writer of the POS_<tenantCode> database this applet reads.
A signed-in session with an e-mail in local storagePlatform loginmakeDatabase() returns without opening anything when localStorage.email is missing, so every panel stays empty.
A POS settings row (branch, sales agent) written by POS GeneralPOS General → its own Default SelectionThe idle screen’s store name and sales-agent name come from that row, not from this applet’s Default Selection.

Applet settings

SettingWhere it is setWhat it controlsDefaultEffect when changed
MESSAGESettings → Application Settings → Display Settings → Idle Screen SettingsThe line of text on the idle screennoneTakes effect on the next settings load. The component initialises the field to "Welcome" but then overwrites it with whatever the setting holds — including nothing — so an unset MESSAGE shows a blank line rather than Welcome.
POS_ATTACHMENT_GUIDSettings → Attachment Settings — tick rows in the Default Selection columnA comma-separated list of attachment GUIDs; the display builds one carousel slide per GUIDnoneThe carousel is empty until at least one row is ticked.

Both are tenant-wide applet settings saved through saveMasterSettingsInit. There is no branch-level or per-terminal variation.

Personalization → Default Selection offers Default Branch and Default Location. That component is routed directly, so its @Input() appletSettings$ and @Output() save are never bound — the screen cannot load or save. Nothing in the applet reads DEFAULT_BRANCH or DEFAULT_LOCATION either.

Attachment Settings maintains bl_pos_customer_view_attachment rows: Sort Code, Code, Description, the uploaded file and its upload date, with Save, Delete and a file-replace action. Slides are served from …/core2/tnt/dm/erp/pos/customer-view-attachments/backoffice-ep/pub/file/{guid}?tenantCode=…, which the backend registers as an anonymous endpoint — the image URL needs no login, only the tenant code and the attachment GUID. Treat anything you upload here as publicly readable by anyone who has the link.

Feature visibility / permissions

bl_applet_client_side_perm_dfn holds zero rows for posCustomerDisplay (checked 2026-09-14), and the applet reads no HIDE_* / SHOW_* keys, so there is nothing to gate client-side — and the Feature Visibility screen is not routed here in any case.

Server-side, only the attachment library is behind permissions: TNT_API_DM_ERP_POS_CUSTOMER_VIEW_ATTACHMENT_READ / _CREATE / _UPDATE / _DELETE (with _OWNER and _ADMIN as the broad grants). The display itself calls no authenticated endpoint at all — it reads the local database and the anonymous image URLs.

Fields

Settings → Attachment Settings → Edit Attachment

FieldMeaningRequiredNotes
CodeShort identifier for the imageNo validator
DescriptionFree textNo validator
Sort CodeCarousel orderNo validator
FileThe image itselfTo have anything to showPreview shown; a delete icon removes the file, a separate Delete removes the whole record

Display line grid

ColumnSource
NAMEdraft_line.name
UNIT PRICEdraft_line.price
QTYdraft_line.qty
AMOUNTdraft_line.amount_txn

Child rows come from the line’s item_child_json and repeat the same four columns.

Lifecycle and effects

There is no document, no server document type, no signum, no journal and no stock movement. This applet writes exactly one kind of record — the attachment rows in bl_pos_customer_view_attachment — and otherwise only reads.

How the live figures arrive. POSDexieService opens new Dexie('POS_' + tenantCode) and exposes Dexie liveQuery observables over the draft_hdr, draft_line and settings object stores. POS General opens the same database name with the same stores and writes the cash bill in progress into them. The display re-renders whenever those stores change — no polling, no websocket, no server call.

On start-up the service also deletes an older database named POS_V2_<tenantCode>_<email> if one exists; that is a one-time migration cleanup, not part of normal operation.

A schema detail worth knowing. Both applets declare Dexie version 5 over the same database name, but their syncing store differs: POS General declares ++id, date, date_doc_sync, this applet declares ++id, date. Two applications declaring different schemas under the same name and version number is a latent conflict — whichever one opens or upgrades the database first determines which indexes exist.

The idle carousel. POS_ATTACHMENT_GUID is split on commas and each GUID becomes an image URL against the anonymous public-file endpoint. There is also an unused loadDefaultAttachment effect that would fetch the same attachments through the authenticated getByGuid service; its dispatch in app.component.ts is commented out, so that path is dead — the carousel always uses the direct URLs.

Related applets

Troubleshooting

SymptomCauseFix
The display never leaves the idle screen while the cashier is ringing up a saleThe two applets are not sharing an IndexedDB — a different browser, a different device, a different profile, or a private window.Open the display in a second window of the same browser profile as POS General, on the same machine.
Every panel is blank, including the idle screenmakeDatabase() returned early because localStorage.email was empty.Sign out and sign back in on that browser.
The idle screen shows the branch and clock but no messageMESSAGE has never been saved. The component’s built-in Welcome default is overwritten with the empty setting.Set a message in Settings → Application Settings.
The carousel is emptyNo attachment row is ticked in the Default Selection column, so POS_ATTACHMENT_GUID is empty.Tick at least one row in Settings → Attachment Settings.
An image is ticked but does not renderThe row has no file, or the file was deleted while the attachment record remained.Re-upload the file on the Edit Attachment screen.
Settings → Permission Set (or any permission link, or Release Notes) shows the 404 pageThose links are hard-coded in the shared settings navigation; this applet registers no such routes.Manage permissions from an applet that does route them.
Personalization → Default Selection will not saveThe component is routed directly, so the output that would carry the save is unbound.Nothing to do — the two keys are not read by this applet anyway.
A carousel image URL was shared and opens for someone outside the tenantThe image endpoint is anonymous by design.Only upload material you are content to publish.

Related documentation

Last updated on