Recurring Sales Invoice Applet
Sets up a sales invoice that repeats — a monthly retainer, a support subscription, a rental. What it saves is a series of pending occurrences, not live invoices, so nothing here posts; a scheduled run turns each occurrence into a real sales invoice when its date comes round, and that invoice is finalised, printed and voided in Sales Invoice (Internal). Always set a recurrence rule before saving: with none, one save creates eight daily occurrences. And nothing is ever generated until the recurring generation run is scheduled for your tenant.
Overview
The Recurring Sales Invoice Applet is where you set up an invoice that should repeat — a monthly retainer, a support subscription, a rental. You fill in an ordinary sales invoice, tick Recurring, and describe the pattern; BigLedger writes out the whole series of future invoices as pending records, and a backend job turns each one into a real sales invoice when its date comes round.
It is a separate applet from Sales Invoice (Internal) because what it saves is a pending record — the series, its lines and attachments — not a live document. Nothing you do here posts to the ledger. The posting happens later, to the real invoice the job creates.
Where it fits
| Applet | Why | |
|---|---|---|
| The document it becomes | Sales Invoice (Internal) | Each occurrence is materialised as an INTERNAL_SALES_INVOICE by the backend job. That is where posting, stock movement and e-Invoice happen |
| The other way in | Sales Contract Applet | A sales contract folder holds recurring sales invoices of its own, kept as the same kind of pending record |
| Master data | Customer Applet, Pricebook, Tax Configuration, Organisation | Customer, prices, tax codes, branch and location |
| Accounts | Chart of Accounts | The GL codes the generated invoice will post to |
Screens and menus
The applet opens on its one menu entry:
| Menu | What it is |
|---|---|
| Recurring Sales Invoice | Listing, create and edit, plus a calendar view |
The listing shows Company, Branch, Location, Customer Name, Sales Agent, Currency, Transaction Amount, Updated Date, Created Date, Transaction Date and Created By. A calendar toggle above the grid swaps it for a calendar view of the same series.
Settings has three entries: Application Settings, Default Selection, Printable Format Settings. The webhook, feature-visibility and permission screens are reachable without menu entries. Personalization has one, Default Selection.
Configuration
Before you can use it
- Branch and location — both are required on the main form. Set defaults in Settings → Default Selection or the person entering the invoice picks them every time.
- A customer — Entity ID is required.
- At least one line — Create and Save are disabled without one.
- Everything the generated invoice will need: GL mapping, tax codes, document numbering for
INTERNAL_SALES_INVOICE. The recurring record carries no posting configuration of its own; the invoice the job creates is validated and posted like any other. - The recurring generation run must be scheduled for your tenant — look for
RECURRING_GENERIC_DOCUMENT_PROCESSORin the Scheduler applet’s processor picker. Without it the pending occurrences simply sit there. It is not one of the platform’s default clocks — nothing installs it for you — so until someone on your tenant creates that schedule the applet generates nothing, however many series are saved (see Nothing is ever generated under Troubleshooting for what it must carry).
Applet settings
Where they live. Application Settings is the field-configuration screen shared with the other document applets; Default Selection and Printable Format Settings belong to this applet. Personalization’s Default Selection is per-login and wins over the applet-level one.
| Setting | Where set | What it controls | Default | Effect when changed |
|---|---|---|---|---|
DEFAULT_BRANCH | Settings → Default Selection; Personalization → Default Selection | Branch pre-filled on a new recurring invoice | null | Pre-fills the required Branch field |
DEFAULT_LOCATION | both | Location pre-filled | null | Selecting a branch auto-fills it from the branch’s main location |
DEFAULT_COMPANY | both, not rendered | Company on the header | null | Derived from the chosen branch |
DEFAULT_ORIENTATION | Personalization only | Tab layout | null | HORIZONTAL / VERTICAL, applied to the workspace and every line-item screen |
PRINTABLE | Settings → Printable Format Settings | Default print format | unset | Used when printing |
VERTICAL_ORIENTATION | no screen in this applet | Gates the vertical-layout branches | — | Honoured if set, but there is no control for it here |
DISABLE_GEN_DOC_LISTING | no screen in this applet | Suppresses the initial listing load | — | Honoured if set, but there is no control for it here |
Personalization also holds the one-column or two-column workspace choice.
About fifty further INCLUDE_*, ENABLE_*, ENABLE_CUSTOM_STATUS_* and HIDE_* keys exist for this
applet. They have no applet-local settings screen; they are rendered, if at all, by the shared
field-configuration screen, so their defaults and persistence could not be confirmed here.
A language drop-down is shown and saved by both Default Selection screens, and nothing in this applet reads what it saves.
Document behaviour settings
There is no status-flow, posting-behaviour, workflow or approval setting in this applet. No approval engine touches it — the platform’s generic approval engine covers Purchase Order, Purchase Requisition and Stock Requisition only, and nothing in the sales chain has one.
Feature visibility / permissions
The applet has no recurring-specific permission. A recurring sales invoice is governed by the four
ordinary internal-sales-invoice document permissions —
TNT_API_DOC_INTERNAL_SALES_INVOICE_CREATE_TGT_GUID, …_READ_…, …_UPDATE_…, …_DELETE_… — for the
document and its attachments alike. Whoever may create a sales invoice may create a recurring one.
The one client-side permission code the applet carries, INTERNAL_SALES_INVOICE_DISPLAY_PRICING, is checked
only on the switched-off Line Items screen, so it has no effect here.
Fields
Main Details
| Field | Meaning | Required | Notes |
|---|---|---|---|
| Branch | Branch the invoice belongs to | Yes | No error message is shown, so an unset branch silently disables Create |
| Location | Stock location | Yes | Same caveat |
| Transaction Date | Shown, but not what dates the invoices | No | Defaults to today. On save BigLedger overwrites it on every occurrence with that occurrence’s own date, counted from Start Date — or from the moment you save when Start Date is empty. Set the dates you want in Start Date, not here (read, not run — see the test below) |
| Recurring | Shows or hides Start Date, End Date and the recurrence editor | No | It does not decide whether a series is made. The server never reads it: saving with it unticked still expands a series (eight daily occurrences when there is no rule — see The two stages) |
| Start Date, End Date | Start Date is the first occurrence, with its time | No | Shown only when Recurring is ticked. End Date does not stop the series — only the end date or count inside the recurrence editor does. A rule with no end there makes 101 occurrences whatever End Date says (read, not run) |
| Recurrence rule | The pattern | No | The rule is written only once you change something in the recurrence editor. Tick Recurring, leave the editor untouched and save, and there is no rule — so you get the eight-daily fallback, not the Daily pattern the editor appears to show |
| Credit Terms | Payment terms | No | Permanently disabled; its hint “Entity ID must be selected first” never comes true |
| MemberCard | Membership link | No | Read-only; opens a member picker |
| Currency | Document currency | No | Defaults to the branch currency, else MYR |
| Sales Lead | Corporate / Non-Corporate | No | Defaults to Corporate |
Reference, Remarks, Permit No, Tracking ID and CRM Contact are free fields, and every generated invoice copies them as saved: a Reference of “March rental” is on the April and May invoices too. If each period needs its own reference, whoever finalises the generated draft changes it there before finalising. There is no document number on this screen: each invoice is numbered when the run creates it, not when the series is saved.
The recurrence editor
The control is the recurrence editor shared across BigLedger. It produces an iCalendar RFC 5545 recurrence rule, which is what the backend expands.
| Field | Options | Default |
|---|---|---|
| Recurrence Pattern | Daily, Weekly, Monthly, Yearly | Daily. Monthly with no month day picked repeats on Start Date’s day of the month; Yearly with no month and day repeats on Start Date |
| Recurrence Days | Monday–Sunday, multi-select | only when Weekly |
| Recurrence Month Days | 1–31, multi-select | only when Monthly. A day the month does not have is skipped, not moved: day 31 bills in seven months a year, day 29–30 misses February. For month-end billing pick day 28, or bill on the 1st (read, not run) |
| Yearly Month / Yearly Day | January–December / 1–31 | only when Yearly |
| End Date or Recurrence Count | radio, then the date or the number | End Date selected, both empty. Left empty, the rule never ends and one save writes 101 occurrences. The count includes the first occurrence |
There is no interval control — every rule runs at interval 1, so “every second month” cannot be expressed in this editor.
A one-series test for the date rules above, all read from source and not run: create a test series with Start Date on 31 January next year, Transaction Date on any other day, Monthly on day 31 and a Recurrence Count of 3, and save. The listing should show three occurrences, dated 31 January, 31 March and 31 May, and none on the Transaction Date. Then delete it with All invoices — its dates are in the future, so nothing has been generated from it.
Account and Lines
Customer: Entity ID is required; name, status, e-mail, phone, ID number, entity type, identity type, description and currency are optional.
Lines: Qty is required with a minimum of 1, and Net Amount, Net Amount with Tax and Transaction Amount are required with a minimum of 0. The remaining twenty or so price, discount and tax fields carry a minimum but are not required. Batch, bin and payment sub-forms have their own required sets.
Starting a series from a template, and saving one
A sales invoice template is a saved invoice shape: company, branch, location, reference, currency, remarks and the lines — item, quantity, unit, prices, discounts, tax codes and the analysis codes. It holds no customer and no date. Templates are made in three places: by hand on the Sales Invoice Template menu of Sales Invoice (Internal), with Save As Template on this applet’s edit screen, and with Save As Template on a recurring invoice inside a sales contract folder.
Templates are read in two places, and neither is the Sales Invoice applet: no sales invoice is ever started from a template there. They are read by the Sales Invoice Template tab on this applet’s create screen, and by a sales contract template that links one: when a document selling a contract item is finalised, a background job builds each new contract’s recurring series from the linked template (see the automatic path).
Use Template on the create screen does three things:
- It sets the company, branch, location, reference, currency and remarks from the template. The customer stays whatever you picked, because the template has none.
- It adds the template’s lines to whatever lines are already there. Press it twice and every line is there twice.
- It brings the lines in without their amounts. Quantity, unit price, unit discount and tax code arrive, but the line amounts and tax amounts do not, so the Lines tab total reads 0.00. The series is saved exactly as shown, and every invoice it generates copies those amounts. Opening a line and saving it from the line edit screen calculates its amounts. GadgetSphere Distribution’s monthly device-rental template for a corporate client — 40 ultraportable laptops at RM 85 — arrives as 40 × RM 85 with a total of 0.00 until each line has been opened and saved.
The contract route is different: it copies the template’s stored amounts as they were when the template was saved. Nothing reprices a template, so a template saved before a price change keeps billing the old price.
Lifecycle and effects
What the applet writes
Create, save and delete act on the pending recurring record; attachments go up with the document, and a delete carries the scope you chose in the dialog (this invoice, this and following, all).
What is saved is a set of pending occurrences, not live sales invoices. Every occurrence of a series is tagged with the same series identifiers, which is how “this and following” and “all invoices” find their siblings.
The two stages
Stage 1 — expansion, at save time, synchronously. On save, BigLedger parses the recurrence rule, iterates it, and creates one pending occurrence per date immediately.
- If the rule is infinite, expansion stops at 101 occurrences — the first and 100 more — with no warning.
- If there is no rule, the fallback is
FREQ=DAILY;INTERVAL=1;COUNT=8— eight daily copies. - The Recurring tick box is never read by the backend. Expansion runs unconditionally on every save; the tick box is only read back to show the form. Nothing on the server consults it.
Saving here without ticking Recurring still creates a series. Because the expander always runs and the null-rule fallback is eight daily occurrences, a document saved with the Recurring box unticked and no rule produces eight pending daily invoices, not one.
There is a second trap in the same area: unticking Recurring on a document that already has a rule does not clear it. The form keeps the old rule, start date and end date whenever the new values are empty, so unticking the box changes nothing.
Stage 2 — generation, asynchronously, by the scheduled run. The recurring generation run picks up every pending occurrence dated up to one day ahead that has not yet been generated — however old — creates a sales invoice from each, and then marks the occurrence as generated with a link to the invoice it produced. Three things follow from that one rule:
- An invoice can appear the day before its date. A run this afternoon picks up tomorrow’s occurrence.
- The first run after the schedule is switched on catches up everything. Every occurrence whose date has passed and was never generated becomes an invoice in that one run, each dated on its original date — last quarter’s included. Before switching the schedule on, delete the past occurrences nobody should be billed for.
- A failure is silent and repeats. If the sales invoice’s own checks refuse an occurrence, the run only writes a server log line. The occurrence stays pending, is retried on every run, and nothing tells you.
What the run creates is a draft, not a posted invoice. The generated sales invoice copies the occurrence’s customer, lines, prices, tax codes and amounts exactly as they were saved — nothing reprices it from the pricebook — and it is numbered on creation. The run sets no posting status, so the invoice lands as a draft, and creating it starts none of the posting work: no journal, no stock movement, no receivable, no e-Invoice. All of that happens only when somebody finalises it in Sales Invoice (Internal).
So the billing run is still a person’s job. On each billing date, whoever does billing opens the Sales Invoice listing, filters to drafts dated that day, checks each against the contract — quantity, price, reference for the period — and finalises it. They know they are done when the number of drafts they finalised equals the number of series due that day, counted from their own contract list — this listing cannot tell them which occurrences have been generated. A series with no draft on its date is either waiting for the run or failing silently; if it is still missing the next day, open the occurrence here and check its customer and items. Check the first generated invoice of every new series the day it appears.
An occurrence therefore has exactly two states in practice: not yet generated, and generated. Neither is settable from the applet.
Posting proof block — for the document each occurrence becomes:
- Server document type:
INTERNAL_SALES_INVOICE. - Quantity signum: −1. Amount signum: +1. The same pair is enforced on every pending line when the series is saved.
- Dr/Cr equation: the
SALESposting group — Dr Debtor, Cr Sales, Cr Output Tax — applied to the generated invoice, not to the pending row. - GL precedence: line GL → header GL → item-company link → company default, on the generated invoice.
- Stock processor: a quantity signum of −1 takes stock out — again on the generated invoice, when it is finalised.
- What VOID reverses: not applicable here. There is no VOID in this applet; voiding is done on the generated sales invoice in its own applet.
Editing and deleting a series
Saving or deleting opens a scope dialog offering “This invoice”, “This and following invoices” and “All invoices”. The choice decides how far the change reaches. Six update cases exist; two are worth knowing:
- Changing the rule with “This invoice” splits that occurrence out into a new series of its own.
- Changing the rule with “This and following invoices” permanently deletes the remaining future occurrences, terminates the old rule at that date and creates a fresh series.
The dialog is a scope picker, not a guard, and it does not know which occurrences have already been invoiced: neither Save nor Delete checks whether an occurrence already has its generated invoice, so All invoices (and This and following invoices, for past occurrences in its range) rewrites or soft-deletes occurrences that were already turned into invoices. The invoices themselves are untouched — only the occurrence record changes — so a report that walks from the series to its invoices loses the link. Change a running series from the first ungenerated occurrence onward, not from the start.
The errors you can see afterwards are
"recurring_group_guid_01 is null in request body", "recurring_update_type is null in request body",
"Invalid recurring_update_type", "Recurring event not found" and "Invalid recurrence rule format: …".
What it does not do
It does not e-mail anything. There is no e-mail control or template in the applet, and nothing on the recurring path sends one. A sales-invoice e-mail notification exists elsewhere in the platform; the recurring path does not use it.
Related applets
- Sales Invoice (Internal) — where each generated occurrence lands, and the only place it can be finalised, posted, printed or voided.
- Sales Contract Applet — the other producer of recurring sales invoices; a contract folder holds its own.
- Customer Applet — the account each series bills.
- Pricebook, Tax Configuration — prices and tax codes on the lines.
- Chart of Accounts — the GL codes the generated invoice posts to.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Saving one invoice produced eight | Expansion always runs, and with no recurrence rule it falls back to eight daily occurrences | Delete the extra occurrences with All invoices. Always set a recurrence rule before saving — and change at least one thing in the recurrence editor, because an untouched editor writes no rule |
| Unticking Recurring did not stop the series | The form keeps the previous rule, start date and end date whenever the new values are empty | Delete the series and create the document in Sales Invoice (Internal) instead |
| A “forever” rule stopped after 101 invoices | Infinite rules are capped at the first occurrence plus 100 more, with no warning | Create a new series when the first runs out |
| There is no Final button | Correct — there is none on the edit screen or the listing | Finalise the generated invoice in the Sales Invoice applet |
| “recurring_update_type is null in request body” | The scope dialog was confirmed without choosing one of the three radio options; it has no default | Re-open the dialog and pick a scope |
| Closing the scope dialog with the × throws an error | The × closes the dialog without a choice and the screen does not expect that | Use Cancel rather than the × |
| Create/Save stays greyed out with no message | Branch, Location or Entity ID is empty, or there are no lines; Branch and Location show no error message | Fill branch, location and customer, and add at least one line |
| Credit Terms cannot be edited | The control is disabled and never re-enabled | Set credit terms on the generated invoice or on the customer record |
| Nothing is ever generated | The recurring generation run is not scheduled for the tenant | Look in the Scheduler applet first: if RECURRING_GENERIC_DOCUMENT_PROCESSOR is in the Select Processor picker, the schedule is yours to create — a daily expression is the usual one, and its properties must name the sales-invoice document type (a docType of internal-sales-invoices); without it the run stops with an invalid-type error and generates nothing, and the Scheduler still shows it as run. Before switching it on, delete past occurrences nobody should be billed for — the first run generates all of them. If it is not in the picker, that half is ours (what to send). |
| Old-dated invoices appeared all at once | The first run after the schedule was switched on generated every past occurrence that had never been generated, each on its original date | They are drafts, so nothing has posted: delete the ones nobody should be billed for in Sales Invoice (Internal), then delete their past occurrences here |
| An invoice appeared the day before its date | The run takes every occurrence dated up to one day ahead | Expected. Finalise it on or after its date if that matters to the customer |
| One series never produces its invoice, the others do | The sales invoice’s checks refuse that occurrence; the run logs it and retries on every run without telling anyone | Open the occurrence and check its customer, items and tax codes; delete and re-create the series if they cannot be fixed |
| Pick Pack Queue / File Import / Line Items are missing | Those screens are switched off in this applet | They do not exist in this applet |