Skip to main content

Free text invoice posted

Fires when a free text invoice (an invoice not tied to a sales order) is posted in Accounts receivable. At posting time a CustInvoiceJour record (the customer invoice journal header) is inserted; when that record has no associated sales order, this event publishes the invoice header details so downstream billing, collections and reporting systems can react to the new customer invoice. A free text credit note (a free text invoice with a negative total) is posted the same way and also raises this event, with a negative amount.

Event classMGCLatticeFreeTextInvoicePostedBusinessEvent
Contract classMGCLatticeFreeTextInvoicePostedBusinessEventContract
CategoryAccounts receivable
ModuleModuleAxapta::Customer
Label IDsFreeTextInvoicePostedBusinessEventName / FreeTextInvoicePostedBusinessEventDescription
TriggerCustInvoiceJour.insert() -> fires when !this.SalesId (no sales order, i.e. a free text invoice) and the header is not pro forma

Trigger / Hook​

  • Extension class: MGCLatticeCustInvoiceJour_Table_Extension, [ExtensionOf(tableStr(CustInvoiceJour))]
  • CoC method signature: void insert()
  • Firing condition: after next insert(), the event fires only when !this.SalesId is true - the invoice journal header has no sales order, which distinguishes a free text invoice from a sales order invoice - and the header is not flagged pro forma. Apart from pro forma, the guard is only "no sales order": any other CustInvoiceJour header inserted without a SalesId would raise it too. Headers written with doInsert(), or by set-based inserts run with skipDataMethods(true), do not.
  • Pro forma: printing a pro forma free text invoice (CustPrintOutInvoice.createProforma()) inserts a real header flagged pro forma (with a temporary invoice number such as #5637171234) and deletes it after printing. That header is not a posted invoice and does not raise this event.
  • Amounts: standard free text invoice posting (CustPostInvoice) sets the header totals from the invoice's calculated totals before it inserts the header, so the payload carries the final posted amount.
  • This event and Sales order invoice posted are mutually exclusive for any one invoice header (that event requires a SalesId).
  • Timing: send() writes the event to the business events commit log inside the posting transaction, and delivery happens asynchronously after commit, so a posting that fails and rolls back never delivers.
  • Enablement gate: BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticeFreeTextInvoicePostedBusinessEvent)) must return true (the event is activated for the current legal entity) before the event is constructed and sent.
  • Trigger method body (verbatim from the extension source):
void insert()
{
next insert();

if (!this.SalesId && !this.isProforma())
{
if (BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticeFreeTextInvoicePostedBusinessEvent)))
{
MGCLatticeFreeTextInvoicePostedBusinessEvent::newFromCustInvoiceJour(this).send();
}
}
}

Payload Contract​

One row per [DataMember], in declaration order. All sources are fields on the inserted CustInvoiceJour record, mapped in initialize().

JSON fieldDisplay labelType / EDTSourceNotes
legalEntityLegal EntityDataAreaIdCustInvoiceJour.DataAreaIdCompany/legal entity of the invoice journal, in lower case (for example usmf).
invoiceIdInvoice IDInvoiceIdCustInvoiceJour.InvoiceIdPosted invoice number.
invoiceAccountInvoice AccountCustInvoiceAccountCustInvoiceJour.InvoiceAccountInvoice account (customer billed).
invoiceDateInvoice DateInvoiceDateCustInvoiceJour.InvoiceDateInvoice date of the posted invoice. A date, serialized in the \/Date(milliseconds)\/ form (midnight UTC).
invoiceAmountInvoice AmountAmountCurCustInvoiceJour.InvoiceAmountTotal invoice amount in the invoice (transaction) currency named by currencyCode; negative for a credit note.
invoiceAmountMSTInvoice Amount MSTAmountMSTCustInvoiceJour.InvoiceAmountMSTThe same total in the legal entity's accounting currency.
currencyCodeCurrency CodeCurrencyCodeCustInvoiceJour.CurrencyCodeTransaction currency of the invoice and of invoiceAmount.
crossReferencesCross referencesList of MGCLatticeCrossReferenceEventContractMGCLatticeCrossReferenceEventHelper::listForFreeTextInvoice(CustInvoiceJour)Keys external systems hold for the free text invoice the journal was posted from: one { externalSystem, externalKey } object per external system, ordered by external system, historical keys included; [] when it has none. See Cross-reference keys. The keys are the free text invoice's, not the journal's.

Every Lattice event also carries the Lattice ordering and correlation envelope, inherited from MGCLatticeBusinessEventContractBase: eventSequence (Int64 - increasing across the whole catalog and all companies, allocated when the event is raised inside the business transaction, not when it commits; it orders the events of one business record, gaps are permanent and normal, and it must not be used to re-sequence the whole stream), correlationId (String, always Scope:Key - groups emissions that belong to one logical run; an event that joins no run carries Event: followed by a lower-case GUID unique to this emission) and schemaVersion (Int - the payload shape version; 1 for this contract). D365 F&O also adds its standard envelope fields to every business event payload: BusinessEventId, BusinessEventLegalEntity, ContextRecordSubject, ControlNumber, EventId, EventTime, EventTimeIso8601, InitiatingUserAADObjectId, MajorVersion, MinorVersion, and ParentContextRecordSubjects. Do not rely on the order of members in the delivered JSON.

Example Payload​

{
"BusinessEventId": "MGCLatticeFreeTextInvoicePostedBusinessEvent",
"ControlNumber": 5637148612,
"EventId": "1F3D8C2A-6B94-4E21-9A77-2C0E5D8F4B10",
"EventTime": "\/Date(1790264919000)\/",
"EventTimeIso8601": "2026-09-24T15:48:39.4697237Z",
"MajorVersion": 0,
"MinorVersion": 0,
"BusinessEventLegalEntity": "USMF",
"ContextRecordSubject": "",
"InitiatingUserAADObjectId": "{8B95911F-6BBF-FFCE-7321-A0857390AE19}",
"ParentContextRecordSubjects": [],
"eventSequence": 48301,
"correlationId": "Event:7b6e0f3d-9a12-4c58-b7e4-21d8f5a3c690",
"schemaVersion": 1,
"legalEntity": "usmf",
"invoiceId": "FTI-00042",
"invoiceAccount": "US-004",
"invoiceDate": "\/Date(1790208000000)\/",
"invoiceAmount": 1250.00,
"invoiceAmountMST": 1250.00,
"currencyCode": "USD",
"crossReferences": [
{
"externalSystem": "BILLING",
"externalKey": "INV-55120"
}
]
}

Activation​

In the D365FO client, go to System administration > Setup > Business events > Business events catalog. Find the event by name ("Free text invoice posted") or by filtering the Category column to Accounts receivable, select it, and use Activate to bind it to a configured endpoint (for example, an Azure Service Bus queue, Event Grid topic, or HTTPS webhook).