Extending it

Adding a document type

Six steps, following the example model in the product repository. It invents a format called SIMPLEDI and a goods received note in it, so nothing here can affect a real partner.

The example sends a goods received note when a vendor product receipt is posted, and reads one that arrives. It is a real document type, complete with acknowledgements, in a format nobody else uses. Read it as the shape of the work rather than as something to install.

1. A model of your own

Create a model that references LunoLakeEDI and the application packages you need. Do not make it a friend of ours: the example is not, on purpose, so that it can only reach what is published. If your model needs friendship, the thing you are reaching for should be published instead, and that is worth a conversation with us.

2. Extend the two enums

A format, if yours is new, and a document type. Both are extensible enums, and both are extended in your model.

Choose the element names carefully. The name is what binds your handler to the type, and it is what is recorded against every message of that type from then on.

3. The handler

One class, decorated with the type it answers for. Two methods are required; the rest have defaults that are correct for most types.

[LunoLakeEDIDocumentTypeAttribute(enumLiteralStr(LunoLakeEDIDocumentType, SIMPLEDI_GRN))]
public final class LunoLakeEDIExampleGrnHandler extends LunoLakeEDIOutboundDocumentTypeHandler
{
    public LunoLakeEDIDocumentFormat documentFormat()
    {
        return LunoLakeEDIDocumentFormat::SIMPLEDI;
    }

    public LunoLakeEDIBusinessProcess businessProcess(LunoLakeEDIDirection _direction)
    {
        return _direction == LunoLakeEDIDirection::Outbound
            ? LunoLakeEDIBusinessProcess::PurchaseOrderPackingSlip
            : LunoLakeEDIBusinessProcess::SalesOrderPackingSlip;
    }
}
The two required answers: which format it belongs to, and where it sits in the order flow.

The business process is answered per direction because the same document is a different thing depending on which end you are. We booked goods in, so outbound it is the purchase packing slip; the partner shipped them, so inbound it is the sales one.

4. Building the outbound document

For a type you send, one more method: the report contract that the Electronic Reporting format runs against. This is the method that decides what data the document is built from.

public SrsReportDataContract buildOutboundContract(TableId _sourceTableId, RefRecId _sourceRecId)
{
    VendPackingSlipJour jour;
    select firstonly jour
        where jour.RecId == _sourceRecId;

    if (!jour.RecId)
    {
        throw error(strFmt("@LunoLakeEDIExample:ErrReceiptJournalMissing", _sourceRecId));
    }

    Args args = new Args();
    args.record(jour);

    SrsReportDataContract reportContract = PurchPackingSlipController::newDataContract(args);

    PurchPackingSlipContract rdpContract = reportContract.parmRdpContract() as PurchPackingSlipContract;
    if (!rdpContract)
    {
        throw error("@LunoLakeEDIExample:ErrReceiptContract");
    }

    rdpContract.parmRecordId(jour.RecId);
    rdpContract.parmTableId(tableNum(VendPackingSlipJour));

    return reportContract;
}
Reads the posted receipt, and hands the data provider the record it expects.

5. Triggering it from a posting

Nothing sends the document until something says a document should exist. That is an ordinary data event handler on the journal your document is built from, calling the published enqueue seam.

[DataEventHandler(tableStr(VendPackingSlipJour), DataEventType::Inserted)]
public static void onVendPackingSlipJourInserted(Common _sender, DataEventArgs _args)
{
    VendPackingSlipJour jour = _sender as VendPackingSlipJour;
    if (!jour)
    {
        return;
    }

    LunoLakeEDIOutboundTriggers::enqueueSource(
        jour.TableId,
        jour.RecId,
        LunoLakeEDIDocumentType::SIMPLEDI_GRN,
        jour.company(),
        LunoLakeEDIAccountModule::Vendor,
        jour.OrderAccount);
}
Does nothing, silently, when the vendor has no partner link or no agreement. Receipts that are not EDI post normally.

The company argument matters. A company-specific journal knows its own legal entity, and that is what the partner link is keyed on. A global journal table does not, and you have to resolve the company from the row instead of assuming the one you are standing in.

6. The reporting configurations

Four, over two data models: a format and a model mapping for export, and a format and a model mapping for import. The outbound agreement binds the export format mapping; the inbound agreement binds the import model mapping. Which is which matters, and Electronic reporting covers it.

Then set it up like any other

From here your type is a type. Add an outbound agreement with the format mapping, an inbound agreement with the model mapping, and it appears in the queue, in the message log and on the tracker with everything else. There is no separate place where extended types live.

Before going near a partner, run the diagnostic that checks for duplicate registrations, and write the tests in Testing an extension. A handler that is not found fails in a way that looks like a configuration problem, and you will spend an afternoon on it.