SO Consolidation
The batch biller: it gathers the order lines of many finalised sales orders and, when you press GENERATE SI, issues one internal sales invoice per company, branch, customer and sales agent, from a run you create or from a dated event. The invoice is created as a draft, so nothing posts until someone finalises it in Sales Invoice (Internal), and undoing a run means voiding or deleting that invoice there. No screen shows whether a run worked, so judge it by its Sales Orders and Sales Invoices tabs, and check what was billed before, because the run cannot.
Your job, and the screen for it
| The job | Screen or tab | Read |
|---|---|---|
| Bill many finalised sales orders together — one invoice per company, branch, customer and sales agent; pick the template on Create, date it today or earlier; finish the last run for that company and branch first | SO Consolidation Run › Create, with an SO Consolidation Template | Templates, and what a run actually picks up; Run — Create |
| Choose the order lines and issue the draft invoices — tick only lines not on an invoice yet | Run detail › Sales Orders tab, then GENERATE SI | The pipeline; Templates, and what a run actually picks up |
| Check what a run produced — the listing’s Status column is not the result | Run detail › Sales Orders and Sales Invoices tabs; reload Sales Invoices after GENERATE SI | Troubleshooting |
| Finalise the consolidated invoices — they are drafts and post nothing until then; check each one’s date and billing address first | Sales Invoice (Internal) applet | Posting proof |
| Schedule a dated or repeating consolidation — give a repeating rule an end, and check a run appeared after each event date | SO Consolidation Event › Create, with Is Recurring / RRULE | Event — Create |
| Set up a billing group to reuse | SO Consolidation Template, then its filter tabs after saving; a sales agent on every Sales Order (Internal) header | Before you can use it; Templates, and what a run actually picks up |
Overview
SO Consolidation is the batch biller. Where a customer has accumulated many finalised sales orders over a period — a month of deliveries, a week of counter orders — this applet gathers the order lines and issues one consolidated internal sales invoice per customer, instead of one invoice per order.
It has three objects. A Template is a saved filter set you can reuse. An Event is a dated (and optionally repeating) instruction to consolidate. A Run is what an event produces, or what you create directly: a named, date-bounded batch whose lines you can inspect and whose resulting invoices you can see.
The same consolidation machinery also carries a parallel Job Sheet variant — Job Sheet to Sales Invoice — with its own applet, JS Consolidation. Its page says where it differs from this one.
FAILED
with the message “There is no Job Sheet under company: … branch: … customer: … salesman: …”. On a run
you create on the screen, that result is then overwritten with a success. The listing’s Status column
is neither: it is the record’s own ACTIVE or INACTIVE. Judge a run by its Sales Orders tab (were lines
made?) and its Sales Invoices tab (were invoices made?). See Troubleshooting.Where it fits
| Direction | Applet | Why |
|---|---|---|
| Upstream | Sales Order (Internal) | Only lines of a Sales Order (Internal) at posting status FINAL are eligible |
| Downstream | Sales Invoice (Internal) | The consolidated invoice is an ordinary internal sales invoice, created as a draft; finalising it there is what posts revenue and moves stock |
| Beside | Job Sheet (Internal) | The same consolidation machinery has a Job Sheet to Sales Invoice path of its own |
| Beside | Scheduler | Not used. The consolidation jobs run when you save a run or an event, or press GENERATE SI. A Scheduler entry cannot start them, and nothing sweeps them later |
Screens and menus
Three screens, all linked, plus the standard Settings and Personalization sections.
| Menu item | Route | What it is |
|---|---|---|
| SO Consolidation Run | so-consolidation-run | The main screen. A listing of runs (Run Name, Created Date, Updated Date, Status), a Create form, and a detail view |
| SO Consolidation Event | so-consolidation-event | Dated instructions to consolidate, with optional recurrence |
| SO Consolidation Template | so-consolidation-template | Reusable filter sets that an event or run can be seeded from |
The Run detail view has eight tabs: Details, Branches, Companies, Customers, Sales Agent, Export, Sales Orders, Sales Invoices. The four filter tabs each have an Add sub-screen that picks the entities for that run; the Sales Orders tab lists the candidate order lines (Branch, Customer, Sales Agent, Item Code, Qty) and is where selection happens — selection is at line level, so part of a sales order can be consolidated and the rest left open; the Sales Invoices tab shows what the run produced.
Configuration
Before you can use it
| Prerequisite | Where | Why |
|---|---|---|
Sales orders at posting status FINAL | Sales Order (Internal) | Draft and non-final orders are invisible to the query |
| A sales agent on the order header | Sales Order header | The salesman filter is mandatory and the grouping key includes it; orders with no sales agent can never be matched |
| At least one company, one branch, one customer and one sales agent selected on the run | This applet | All four are hard-required — see below |
Applet settings
This applet has no working configuration. All three settings screens are non-functional, and nothing in the applet changes its behaviour based on a setting.
| Screen | State |
|---|---|
| Settings → Field Settings | The toggles shown (Unit Discount, SST/VAT/GST, WHT, Blanket Order, Department Settings…) are copied from a sales-document settings screen, describe nothing in this applet, and SAVE does nothing |
| Settings → Default Selection | Displays, but what you enter is never saved |
| Personalization → Default Selection | The same result |
The reason is mechanical, not a permission: the Field Settings screen is a stub with no form behind its toggles, and both Default Selection screens declare a save output that nothing emits and nothing binds. The Personalization menu also lists a Field Settings entry with no route behind it, so that click opens nothing.
Two batch behaviours that would normally be settings are instead fixed by the platform when it queues the job, not anywhere a user can reach: the page size in which a run reads sales-order lines, and whether a job processes one named event or run or sweeps every unprocessed one. Everything you start from this applet processes the one event or run you saved.
Feature visibility / permissions
This applet has no feature-visibility codes of its own.
The Permission Set screen carries a full six-verb set (_OWNER, _ADMIN, _CREATE, _UPDATE,
_DELETE, _READ) for each of Consolidation Template Hdr, Consolidation Event Hdr,
Consolidation Run Hdr and Consolidation Run Line, all prefixed
TNT_DM_ERP_SALES_ORDER_TO_SALES_INVOICE_CONSOLIDATION_….
GENERATE SI is governed by the run line create permission.
Fields
Run — Create
| Field | Meaning | Required | Notes |
|---|---|---|---|
| Run Name | The batch’s name | Yes | Shown in the run listing and not on the invoices, so name it for the month or channel it covers, not “run 1” |
| SO Consolidation Template | Copies a saved template’s four filter lists into the run | No, but see Templates | The only way this form fills the four lists |
| Companies / Branches / Customers / Sales Agents | The four filter sets | Yes, in effect | Not on this form: they come from the template, or from the run’s tabs after it is saved. Each is checked only when the run executes, and an empty one fails the run |
| Current Run Start Date / End Date | The start date decides when the run is processed, not which orders it takes. The second date is stored and nothing that processes the run reads it | No, but treat the start date as required | It opens at the date the previous run closed on, so check it. Today or earlier: the run is processed as you press Create. Later than today: it is never processed (see Templates). Empty: the create path reads it at once, so the run either fails to save or is never picked up (read in the code, not run) |
| Previous Run · Name · Start Date · End Date | The preceding run, for continuity | Read-only | Filled from the most recently created run; its end date becomes this run’s start date |
| Description | Free text | No | Left blank, the template’s description is copied in when the run is saved |
| Status | ACTIVE by default | — | Not read by the run job. An INACTIVE run is still processed; only deleting it stops it |
Event — Create
| Field | Meaning | Required | Notes |
|---|---|---|---|
| Cycle Start Date / Cycle End Date | An event dated today or earlier becomes a run when you save it. An event dated later may never become a run (see below). Both dates are copied onto the run, and neither chooses which orders are billed | Yes, though the form does not mark them | The server refuses an event missing either date. On a repeating event each occurrence gets its own start date, and the second date you typed is replaced by the close of that occurrence’s calendar period (for daily and weekly rules, of its first day) |
| Is Recurring / RRULE | Repetition | No | An iCalendar RRULE string, the same recurrence model Stock Replenishment uses — editing or deleting a recurring event asks whether the change applies to this occurrence, this and future ones, or all. Occurrences are created up front as separate events; an unending rule stops after about a hundred. A rule that repeats every period (interval 1) with no finish date and no count creates only the first event, so give the rule a finish date or a number of occurrences, then open the Events listing and count them. Only the occurrences already due when you save become runs; the later ones share the caution below |
| SO Consolidation Template | Copies a saved template’s four filter lists into the event | No | The only way this form fills the four lists |
| Companies / Branches / Customers / Sales Agents | The four filter sets | Yes, in effect | Copied from the event’s own lists onto every run the event creates |
| Description, Status | No | The description is copied onto every run the event makes. Status is not read by the event job: an INACTIVE event still turns into a run on its date; only deleting it stops it |
An event dated in the future may never become a run. When you save an event, the platform checks it once, there and then. An event not yet due is skipped, and as far as the source shows nothing checks it again when its date arrives: no Scheduler entry can start the event job, and the platform’s per-tenant processing pass does not look at this applet’s queue. That holds for a one-off event dated later and for every future occurrence of a repeating one. This was read in the code and has not been tested on a tenant. After each event date, open the Event listing and check that a run appeared. If none did, create the run by hand.
Lifecycle and effects
Posting proof
| Server document type | None of its own. Templates, events, runs and run lines are not financial documents |
| Amount signum / quantity signum | Not applicable. The document it creates is an ordinary Sales Invoice and carries that document type’s signums |
| What it creates | One internal sales invoice per company, branch, customer and sales agent, at posting status DRAFT |
| Dr/Cr equation | None here. The draft posts nothing; when it is finalised in Sales Invoice (Internal) it posts exactly as any internal sales invoice does |
| GL precedence | Not applicable here; inherited from the sales invoice |
| Stock processor | None here; inherited from the sales invoice |
| What VOID reverses | There is no void on a run. Reversing means voiding or deleting the consolidated sales invoice in its own applet |
| What it does write | Run lines, one per eligible sales-order line; one draft sales invoice per group; document links tying the orders to the invoice; and a permanent removal of the orders from the sales-order-to-sales-invoice open queue |
The pipeline
flowchart TD
T["Template<br/>saved filter set"] -.seeds.-> E
E["Event<br/>date + optional RRULE + filters"] -->|event job<br/>event date <= today| R["Run header<br/>filters copied from the event"]
RC["Run created directly<br/>in the applet"] --> R
R -->|run job| RL["Run lines<br/>one per eligible FINAL sales-order line"]
RL -->|GENERATE SI<br/>run-line job| G["Group by company + branch<br/>+ customer + sales agent"]
G --> SI["One draft Sales Invoice per group<br/>posts when finalised"]
SI --> L["Document links<br/>sales order to sales invoice"]
SI --> Q["Open-queue rows for SO to SI<br/>permanently deleted"]
Three background jobs drive the chain, and each is started by something you do on this applet’s screens, not by a clock. The Scheduler cannot start them.
Event → Run. Saving an event starts the event job for that event. If the event is due (dated today or earlier) and has not yet produced a run, the job creates a run from it — copying the four filter sets, the dates, the name and the template link — records the run on the event, and starts the run job at once. An event that already has a run is never processed again. An event not yet due is skipped, and see the caution under Event — Create about when it is looked at again.
Run → Run lines. The run job processes a run only once. It requires all four filter sets to be
non-empty and fails the run with a specific message if any is missing. It then works through each
company and branch, counting eligible sales-order lines — a Sales Order (Internal) whose posting status
is FINAL, whose customer is in the customer set and whose sales agent is in the salesman set — and
compares that with the run lines that already exist for the pair in any run. What it does next is in
Templates, and what a run actually picks up.
Run lines → Invoice. Pressing GENERATE SI on the Sales Orders tab queues the run-line job and returns at once: the “The sales invoices were successfully created” message means the work was queued, not done. The job skips any ticked line that already has an invoice or carries any status. It takes the distinct (company, branch, customer, sales agent) combinations among the rest and, for each, reads back exactly the selected order lines and builds one Sales Invoice from them, created exactly as a hand-keyed internal sales invoice is and then immediately updated so the running number and derived fields are populated. It is created as a draft. It is dated the moment the job runs, its billing and delivery address and customer details come from the last sales order in the group, and its description reads “Consolidated from Sales Order id: …”, naming that last order only. Only item lines are carried. The run lines are then stamped with the invoice link and a shared group reference, and the orders are permanently removed from the sales-order-to-sales-invoice open queue so they no longer offer themselves for conversion. A failure is written to the run line, not shown to you; reload the Sales Invoices tab to see what was made.
Run-line status values
The status on a run line is free text, not a fixed list — and no tab in this applet shows it. The Sales Orders tab fetches the run lines but puts only branch, customer, sales agent, item and quantity in columns; the Status on the run listing is the record’s ACTIVE/INACTIVE flag, and the Status on the Sales Invoices tab is the invoice’s own posting status. The processing result lives in two fields on the line — a processing status and a processing error (the exception message, or the stack trace) — and the way to read them is the run-lines query the Sales Orders tab itself calls, filtered by the run’s guid (the field names and the path are in this page’s sources), or to ask BigLedger support to read them for you. The values written are:
| Value | Meaning |
|---|---|
POSTED | The whole chain succeeded and at least one open-queue entry was found and removed |
FAILED_TO_CREATE_CONSOLIDATED_SALES_INVOICE | The consolidated invoice was rejected on creation; the message column carries the reason |
FAILED_TO_UPDATE_CONSOLIDATED_SALES_INVOICE | The invoice was created but the follow-up update failed |
FAILED_TO_UPDATE_SALES_INVOICE_DATA_IN_RUN_LINE | The invoice is correct; writing its link back onto the run lines failed |
FAILED_TO_DELETE_GENDOC_LINE_OPEN_QUEUE | Everything succeeded except clearing the open queue |
| (unchanged) | No open-queue entries were found. POSTED is written only when there were open-queue entries to remove, so a successful consolidation of orders that had none leaves the run line’s status untouched |
Templates, and what a run actually picks up
A template is a name, a description, a status and four lists: companies, branches, customers and sales agents. You fill the lists on the template’s own filter tabs after you save it. Pick the template on the Run or Event Create form and its four lists are copied into the new run or event. That is the only way the Create form fills them. It has no picker of its own for companies, branches, customers or sales agents.
What happens behind the screen.
- The copy is taken once, when you pick the template. Editing the template afterwards changes no run or event already made. That includes a repeating event. The event copies its own four lists onto every run it makes, not the template’s. A customer you add to the template next month is not billed by an event you created last month.
- The run remembers which template it came from, and nothing uses that. The run job chooses orders from the run’s own four lists. The template view has no list of the runs made from it.
- The run’s dates do not choose orders. The run takes every sales-order line at posting status FINAL whose company, branch, customer and sales agent are in its lists, whatever the order’s date. The start date only decides when the run is processed.
- Nothing new since the last run: the new run gets no lines for that company and branch. When the eligible lines are no more than the run lines already held for the pair, by any run, the new run makes none. Its Sales Orders tab stays empty for that pair; the earlier run keeps its lines.
- New orders finalised since: the run takes every such line again, including lines an earlier run already invoiced. It first deletes every run line for that company and branch, from every run and for every customer. That includes an earlier run’s record of which invoice each line went to. It then lists every eligible line again under the new run, with no mark on those already invoiced. When you press GENERATE SI, the only check is the run line’s own invoice link, and a re-listed line has lost it, so it can be billed a second time.
- The Qty column is not a quantity. It shows how many eligible lines the run found for that company and branch, the same number on every line of the pair.
Four cautions, each with the symptom you will see:
- Pick the template on Create, or the run has nothing to work with. A run whose start date is today or earlier is processed the moment you press Create. Without a template its four lists are empty, so it makes no lines, and a run is never processed twice. Symptom: the Sales Orders tab stays empty.
- Do not date a run in the future. A run with a later start date is queued and marked as handed over straight away. The run job only takes runs that were never marked, so as far as the code shows, that run never makes its lines. Symptom: the start date passes and the Sales Orders tab stays empty. Create the run on the day you want it to run. A future-dated event is no way round this (see Event — Create).
- No screen shows whether a run was processed. The listing’s Status column is the record’s own status, ACTIVE or not. It is not the result of processing, and no screen shows the processing error. The Sales Orders tab is your evidence: empty means this run made no lines, either because it failed or because an earlier run already holds every eligible line for that company and branch.
- Two runs over the same company and branch interfere. The second can delete the first’s lines, including the link to the invoice they produced. Finish and check one run before you create the next.
Your job. Whoever bills these customers keeps one template per billing group, for example one per branch and sales agent, and keeps it current. When a customer or sales agent joins or leaves the group, edit the template and re-create any event made from it. Before you press GENERATE SI, compare the Sales Orders tab with the invoices the last run produced. Tick only lines that are not on one yet, because nothing here stops a second invoice for a line a later run has re-listed. Afterwards, open the Sales Invoices tab and count one invoice per customer and sales agent you expected, then finalise each draft in Sales Invoice (Internal), checking its date and billing address. If the orders were already invoiced by hand, do not select them. The run does not know that. Do not create the next run for that company and branch until this cycle’s invoices are final.
Related applets
- Sales Order (Internal) — the source documents, and where the sales agent that forms part of the grouping key is set.
- Sales Invoice (Internal) — where the draft the run produces is finalised; everything about posting, tax and stock is decided there.
- Job Sheet (Internal) — the sibling consolidation path in the same backend subsystem.
- JS Consolidation — the job-sheet twin of this applet; its page lists where the two differ.
- Scheduler — not used by this applet’s runs or events.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
Support, or the API, reports a run as FAILED with “There is no Job Sheet under company: … branch: … customer: … salesman: …”, although its run lines and invoices exist | A known defect: the run never counts the lines it matched, so the “nothing found” check always fires. On a run created on the screen the result is then overwritten with a success, so the recorded result is wrong either way | Check the Sales Orders and Sales Invoices tabs rather than any status. A fix in the platform is needed |
| A run that made no lines is never retried | The run job processes a run once. Once any result has been recorded, that run is permanently skipped | Create a new run |
| “The sales invoices were successfully created” but the Sales Invoices tab is empty | The message appears when the work is queued. Creation failed or has not finished | Reload the tab. If it stays empty, the failure is in the run line’s processing status and error fields, which no tab shows — read them through the run-lines query or ask support; see Run-line status values |
| A new run’s Sales Orders tab is empty although orders are FINAL | An earlier run already holds lines for every eligible order in that company and branch | Use the earlier run, or finalise new orders first and accept that the earlier run’s lines move to the new one |
| An order already invoiced appears again, unmarked | A later run deleted and re-created the lines for that company and branch | Check against the invoices before ticking; see Templates, and what a run actually picks up |
| A future-dated event never produced a run | An event is checked when you save it; nothing checks it again on its date | After each event date, check the Event listing and create the run by hand |
| The invoice’s address or description names only one order | The header is taken from the last sales order in the group | Correct the draft before finalising it |
| The run fails immediately with “There is no company/branch/customer/salesman guid to process” | One of the four filter sets is empty. All four are mandatory — there is no “all customers” option | Populate all four tabs before running |
| A finalised sales order is never picked up | The run requires a Sales Order (Internal) at posting status FINAL, whose customer is in the customer set and whose sales agent is in the salesman set. An order with no sales agent matches nothing | Set the sales agent on the order header, or widen the salesman filter |
| Orders from several customers end up on one invoice, or one customer’s orders are split across several | The grouping key is the full tuple (company, branch, customer, sales agent) — not the customer alone. Two sales agents on the same customer’s orders produce two invoices; two branches produce two more | Expected. Narrow the run if you need one invoice per customer |
| Run lines read back (through the API) with a blank processing status after an apparently successful run | POSTED is written only when open-queue entries were found. Where the company has no knock-off flow configured for sales order → sales invoice, there are none, and the status is left as it was | Check the Sales Invoices tab; see the company’s Knock Off Configuration |
| An earlier run’s lines have disappeared | A later run over the same company and branch found new orders and deleted every run line for that pair, whichever run made them | Do not create a second run for a company and branch until the first run’s invoices are final |
| The consolidated invoice exists but the sales orders still offer themselves for conversion elsewhere | The open queue is cleared in a separate step after the invoice is saved; if that step fails the run line records FAILED_TO_DELETE_GENDOC_LINE_OPEN_QUEUE | Confirm it through the run-lines query (or ask support); the invoice itself is good, so warn whoever converts orders not to invoice those again until the queue rows are cleared; see Run-line status values |
| Settings screens do nothing | None of the three works; see Applet settings | — |
Related documentation
- Sales module — where this sits in the product.