Peppol Ap Admin Applet
Overview
The Peppol AP Admin Applet is the console for operating BigLedger’s own Peppol Access Point, not for a customer’s own Peppol traffic. Where the My Peppol Admin Applet is a tenant looking at its own outgoing and incoming documents, this applet is the access point looking at everything the network delivers to it — the inbox queue that every inbound AS4 message lands in, the history of what was delivered, the tenant-company receiver mappings that decide which customer a document is handed to, and the PINT Malaysia testbed used to prove conformance to OpenPeppol and MDEC.
It is an operations and accreditation tool. It creates no accounting entries, moves no stock, and has no document of its own that can be finalised or voided.
Where it fits
| Upstream | This applet | Downstream |
|---|---|---|
| Any Peppol access point on the network sending an AS4 message to a participant ID that resolves to BigLedger | Inbox Queue — one transient row per inbound message (bl_ppl_ap_inbox_queue) | PplApInboxQueueProcessor routes the document into the receiving tenant and deletes the queue row |
| The routed document | Inbox History (bl_ppl_ap_inbox_doc_hdr) — the retained access-point record | The tenant’s own External Reception screens in the My Peppol Admin Applet |
| Participant registrations created in My Peppol Admin Applet → Peppol Config → Registration | Registered Companies (bl_ppl_ap_tnt_comp_receiver_mapping) — the routing table, written by the registration service | Routing decisions for every inbound document |
| Sample XML supplied by OpenPeppol / MDEC for accreditation | Testbed → Validation Test, Testbed → Sending Test | Validation results, and (when the sending path works — see Troubleshooting) test transmissions through the access point |
Screens and menus
| Menu | Route | What it shows | Actions |
|---|---|---|---|
| Inbox Queue | peppol-testbed-receiving-test-queue | bl_ppl_ap_inbox_queue, newest first — Sender ID, Receiver ID, Organization ID, Document Creation Datetime, Document Creation Datetime UTC, Document Type ID, Process ID, Payload ID, Lookup Results Status, Lookup Results Endpoint URL, Lookup Results Duration, App Domain, App Mode | View only — click a row for the read-only Details tab |
| Inbox History | peppol-testbed-receiving-test-history | bl_ppl_ap_inbox_doc_hdr, same columns, newest first | View only |
| Registered Companies | registered-companies | bl_ppl_ap_tnt_comp_receiver_mapping for one selected tenant — Tenant Code, Tenant Comp Peppol ID, Comp Name, Comp Code, Created Date, Updated Date. A Tenant dropdown at the top lists every tenant on the platform; company name and code are resolved per row through the Company service | Pick a tenant; quick search; view only — the Edit screen has a SAVE button that does nothing (see Troubleshooting) |
| Testbed → Sending Test | peppol-testbed-sending-test | bl_ppl_ap_testbed_sending_doc_hdr — Test Name, Description | Create (choose one of the four PINT MY test cases, paste XML, Submit) |
| Testbed → Validation Test | peppol-testbed-validation-test | bl_ppl_ap_validation_test_hdr — Validation Test Name, Validation Test Code, Validation Test Description, Validation Test Date | Create; open a test, upload a ZIP of XML files, Run Checking, Send Only Valid XML; drill into one file to Revalidate or Send |
| Settings | settings/field-settings, settings/default-selection, plus the shared Webhook, Feature Visibility and Permission Set / User / Team / Role screens | See Configuration | — |
| Personalization | personalization/personal-default-selection, personalization/sidebar | Per-user defaults and sidebar | — |
The Registered Companies grid starts empty: its tenant code defaults to peppolap — the access point’s own tenant, which normally has no mappings of its own — and only fills in once a tenant is chosen from the dropdown.
Two things in the navigation do not do what their labels suggest. The Testbed parent entry (peppol-testbed) is a grouping node with no route of its own, so only its two children are reachable. And the Personalization menu lists a Field Settings item pointing at field-settings, which is not a child route of personalization — selecting it falls through to the applet’s 404 redirect (menu-items.ts vs app.routing.ts, commit 5f24872).
Inside the Inbox Queue listing there is an advanced-search box, but its onSearch handler is empty and the search model it is given is internalSalesOrderSearchModel, copied from the Sales Order applet. Typing in it has no effect. Submit / Export / Withdraw buttons appear in the template as commented-out markup on both the listing and the edit screen; they do not render.
Screenshots needed
No screenshots exist for this applet. A capture session should take: the Inbox Queue listing with rows; the Inbox Queue Details read-only tab; the Registered Companies listing; the Validation Test listing; Validation Test → upload ZIP; the Checking grid showing VALID and INVALID rows with an error message; and the Sending Test input form with the Test Name dropdown open. Because every row on these screens is a real trading party’s identifier, captures must come from a scratch tenant or be redacted before publishing.
Configuration
Before you can use it
| Prerequisite | Where | Why |
|---|---|---|
A session in the access-point tenant (peppolap) | Applet installation and login | The Inbox screens read bl_ppl_ap_inbox_queue and bl_ppl_ap_inbox_doc_hdr with the current tenant’s visa, and those tables are written in BigLedger’s access-point tenant — on an ordinary customer tenant both grids are empty. Registered Companies goes further: it uses a visa pinned to tenant code peppolap (AppConfig.peppolVisa), and the backend returns invalidTenantCode unless the caller is that tenant (TenantCodeConstants.peppolApTenantCode = "peppolap"). |
| A participant registration for each company that should receive documents | My Peppol Admin Applet → Peppol Config → Registration | PplApParticipantRegistrationService.insertIntoCompRcvrMapping writes the bl_ppl_ap_tnt_comp_receiver_mapping row from the registration header. There is no way to add a mapping by hand in this applet. |
| The AS4 receiving endpoint wired to the SPI | Platform configuration | PeppolIncomingSBDHandlerSPI.handleIncomingSBD is what creates the inbox-queue row; without it nothing arrives. |
| The inbox job processor enabled | BigLedger support | PplApInboxQueueProcessor is a PRIMARY processor queued RUN_NOW by the SPI. If it is not running, rows pile up in Inbox Queue and no tenant receives anything. |
| Server-side permissions assigned | Settings → Permission Set / Role Permission | Each screen’s data is behind its own permission constant — see below. |
Applet settings
There are no working applet settings. The classification is applet-local (the applet defines its own FieldConfigurationComponent rather than importing the shared one from blg-shared-utilities), and both local screens are inert:
- Settings → Field Settings renders eight slide toggles — Unit Discount, SST/VAT/GST, WHT, Blanket Order, Segment, G/L Dimension, Profit Center, Project — with no
formControlName, no form group and a SAVE button with no click handler. These are the labels of a sales-document settings screen and have nothing to do with Peppol. No exposed control found (routes and settings components checked at commit5f24872). - Settings → Default Selection and Personalization → Default Selection offer a Default Branch and a Default Location dropdown, and write
DEFAULT_BRANCH/DEFAULT_LOCATIONinto anAPPLET_SETTINGSextension object. Both components are routed directly inapp.routing.ts, so their@Input() appletSettings$and@Output() saveare never bound:appletContaineris undefined when a dropdown changes, and the SAVE button emits to nothing.
Neither key is read anywhere in the applet — a repo-wide grep for DEFAULT_BRANCH, DEFAULT_LOCATION, APPLET_SETTINGS and appletSettings at commit 5f24872 returns only the two settings components themselves. Nothing on any screen changes when they are set.
Settings in other applets that control this applet
| Setting | Where it is set | Effect here |
|---|---|---|
| Company Peppol participant ID and registration | My Peppol Admin Applet → Peppol Config → Registration; the same records appear in the Organisation Applet | Creates the receiver mapping row that makes a company routable, and so decides whether an inbound document reaches a tenant at all. |
Feature visibility / permissions
No client-side permission definitions are seeded for peppolApAdminApplet (0 rows in bl_applet_client_side_perm_dfn, checked 2026-09-14), and the applet reads no HIDE_* / SHOW_* keys, so the Feature Visibility screen has nothing to gate. Access is decided entirely server-side, per endpoint, from MyPeppolPermissions:
| Screen | Permission needed to read |
|---|---|
| Inbox Queue | API_TNT_DM_ERP_PPL_AP_INBOX_QUEUE_READ |
| Inbox History | API_TNT_DM_ERP_PEPPOL_AP_INBOX_DOC_HDR_READ |
| Registered Companies | No permission constant — PeppolApTntCompReceiverMappingController exposes only /{crossTenantCode}/cross-tenant-login-ep endpoints and gates them on the caller being the peppolap tenant, not on a permission |
| The Tenant dropdown on Registered Companies | Whatever the platform Tenant service requires; it is called with the current tenant’s visa, and an empty dropdown is the symptom of not having it |
| Sending Test | API_TNT_DM_ERP_PEPPOL_AP_TESTBED_SENDING_DOC_HDR_READ (create needs …_CREATE) |
| Validation Test listing and create | API_TNT_DM_ERP_PEPPOL_AP_VALIDATION_TEST_HDR_READ / …_CREATE |
| Uploaded file listing | API_TNT_DM_ERP_PEPPOL_AP_VALIDATION_TEST_FILE_ZIP_HELPER_READ |
| Run Checking and Revalidate | API_TNT_DM_ERP_PEPPOL_AP_VALIDATION_TEST_FILE_ZIP_HELPER_RUN_CHECKING_READ |
A role with none of these opens the applet and sees empty grids rather than an authorisation error.
Fields
Inbox Queue / Inbox History → Details — every control is readonly; this is a viewer, not a form.
| Field | Meaning |
|---|---|
| Sender ID | The sending participant’s Peppol ID, as it arrived in the SBDH |
| Receiver ID | The receiving participant’s Peppol ID — the value matched against the receiver mapping table |
| Organization ID | The organisation identifier carried in the envelope |
| Document Creation Datetime / … UTC | Creation timestamp as sent, and its UTC form |
| Document Type ID | The Peppol document-type identifier (which PINT profile and version) |
| Process ID | The Peppol process identifier |
| Payload ID | The unique payload identifier of the AS4 message |
| Lookup Results Status / Endpoint URL / Duration | Outcome of the SMP lookup performed for this message, the endpoint it resolved to, and how long it took |
| App Domain, App Mode | Which deployment and mode handled the message |
Registered Companies → Details — also entirely readonly: Tenant Code, Tenant Comp Peppol ID, Company Name, Company Code, Created Date, Updated Date.
Validation Test → Create
| Field | Meaning | Required | Notes |
|---|---|---|---|
| Validation Test Code | Short code for the test run | No validator | Stored in bl_ppl_ap_validation_test_hdr.code |
| Validation Test Name | Descriptive name | No validator | Stored in …hdr.name |
| Validation Test Description | Free text | No validator | Stored in …hdr.description |
Sending Test → Create
| Field | Meaning | Required | Notes |
|---|---|---|---|
| Test Name | One of four fixed PINT Malaysia test cases: PINT-TC-BISC1-1 (MY Invoice to MY recipient), -2 (MY Credit Note), -3 (MY Self Billing Invoice), -4 (MY Self Billing Credit Note) | No validator | The list is hard-coded in the component, not fetched |
| XML | The document to send, pasted as text | No validator |
Checking grid (Validation Test → open a test → open an uploaded ZIP): No., File Name, File Size, File Format, Validation Status, Validation Error, Error Message, User Error Message, Created Date, Updated Date — one row per XML file found in the ZIP (bl_ppl_ap_validation_test_file_zip_helper).
Lifecycle and effects
This is a master-data and operations applet. It has no server document type, no amount or quantity signum, no journal and no stock processor; nothing here is finalised or voided.
Receiving — what happens to an inbound document
- An AS4 message arrives.
PeppolIncomingSBDHandlerSPI.handleIncomingSBDparses the Standard Business Document and callsMyPeppolReceivingInboxService.insertIntoPplApInboxQueue, which writes onebl_ppl_ap_inbox_queuerow in the access point’s database, then queuesPplApInboxQueueProcessorwithExecutionStrategy.RUN_NOW. PplApInboxQueueProcessor.processEventcopies the queue row intobl_ppl_ap_inbox_doc_hdr(bl_ppl_ap_inbox_doc_hdr.fromBl_ppl_ap_inbox_queue) — this is the permanent access-point record shown in Inbox History.- It then reads
bl_ppl_ap_tnt_comp_receiver_mappingby the message’s receiver Peppol ID (PeppolApTntCompReceiverMappingUow.getByCompanyPeppolId). For every mapping found it opens that tenant’s database, creates abl_ppl_from_peppol_doc_hdr_queuerow from the inbox document header, and queuesFromPeppolDocHdrQueueProcessorinside that tenant. - Finally it permanently deletes the
bl_ppl_ap_inbox_queuerow (deletePermanent).
Two consequences follow directly, and they are the two facts an operator needs. Inbox Queue is transient — under normal operation it is empty, because rows are deleted microseconds after they are written; a row sitting in it means the processor has not run. And a receiver ID with no mapping is not an error — the loop simply finds nothing to iterate, the inbox document header is still written, and the message is silently not delivered to any tenant.
Registration — how a mapping appears
Registered Companies is written by PplApParticipantRegistrationService.insertIntoCompRcvrMapping, which copies the tenant GUID, tenant code, company GUID and participant ID from a bl_ppl_ap_participant_registration_hdr when a registration succeeds. The applet only reads the table.
Validation Test — what “Run Checking” actually checks
Run Checking calls GET …/ppl/ap/validation-test-file-helper/run-checking/{zip_hdr_guid}/backoffice-ep, which runs PeppolApValidationTestFileZipHelperService.validateAndUpdateZipHelper over every file extracted from the ZIP. For each file:
- the document type is inferred from the file name — a name containing
invoiceselects the invoice rules, a name containingcreditnotethe credit-note rules, anything else yields an empty type; - the XML is validated against the PINT UBL schematron for that type (
peppol/<doctype>/PINT-UBL-validation-preprocessed.sch) using the Ph schematron engine; - it is validated a second time against the Malaysian jurisdiction rules (
peppol/pint-my/1.0.0/xslt/billing/PINT-jurisdiction-aligned-rules.xslt), whose failed assertions are collected from the SVRL output; - one assertion is deliberately dropped before the verdict —
[ibr-119]-A time MUST be formatted hh:mm:ss with optional fractional seconds .sss and time zone expression (ibt-168).; - if nothing remains,
validation_statusis set toVALIDanderror_messagecleared; otherwiseINVALIDwith the collected texts. The row’supdated_dateis stamped either way.
Revalidate on a single file posts the XML to …/validate-document-one-by-one/backoffice-ep?docType=… and returns either the failure texts or the single token THIS_DOCUMENTS_IS_VALID.
Uploading a ZIP dispatches uploadAttachmentsInit, which calls PeppolAPTestbedValidationTestZipHdrService.addAttachment against the open validation test’s GUID. The success toast reads “Upload Image Successful” — a label inherited from the applet this screen was cloned from. Delete and download effects exist in the same file but are commented out, so the delete and download buttons on the uploaded-file screen dispatch actions nothing handles.
Sending — Send Only Valid XML and the per-file Send are described under Troubleshooting; at commit 5f24872 they call a URL the backend does not serve.
Related applets
- My Peppol Admin Applet — the tenant-side counterpart. Registrations made there create the receiver mappings listed here, and documents routed from here surface there under External Reception.
- My E-Invoice Admin Applet — the parallel LHDN pipeline; it shares the mandatory-field check but not this applet’s data.
- Organisation Applet — holds the company Peppol status and participant IDs that a registration is built from.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Rows accumulate in Inbox Queue instead of clearing | PplApInboxQueueProcessor is not running. The SPI queues it RUN_NOW; when it runs it deletes the row it processed, so a non-empty queue is by itself the symptom. | Ask support to check the job processor on the access-point tenant. The documents are not lost — they are re-processed when it resumes. |
| A document appears in Inbox History but the customer never received it | No bl_ppl_ap_tnt_comp_receiver_mapping row matches the message’s Receiver ID. The processor writes the history row first and then iterates an empty mapping list — nothing fails, nothing is delivered. | Check the receiver ID against Registered Companies. If it is missing, complete the participant registration for that company in the My Peppol Admin Applet; registration is what writes the mapping. |
| The same document is delivered to two tenants | getByCompanyPeppolId returns every mapping for that participant ID and the processor loops over all of them. A duplicate registration produces a duplicate delivery. | Remove the stale registration; there should be one mapping per participant ID. |
| Registered Companies → Edit → SAVE appears to do nothing | It does nothing. onSubmit() writes the form to the browser console and the rest of the handler is commented out; every field on the form is readonly anyway. | Do not try to correct a mapping here. Fix it at the registration. |
| Run Checking fails with a server error for a whole ZIP | The document type is taken from the file name. A file whose name contains neither invoice nor creditnote yields an empty type, the schematron resource path peppol//PINT-UBL-validation-preprocessed.sch does not resolve, and the resulting FileNotFoundException is rethrown as a RuntimeException that aborts the run for every file in the ZIP. | Name each file so it contains invoice or creditnote — for example PINT-MY-invoice-01.xml, PINT-MY-creditnote-01.xml — and upload again. |
A file is reported VALID although it has a malformed time | The [ibr-119] time-format assertion is removed from the result list before the verdict is decided. | Expected behaviour of this build; validate time formats separately if they matter to you. |
| Send Only Valid XML or the per-file Send returns a 404 | The front end calls …/ppl/ap/validation-test-file-helper/send-all/{guid}/backoffice-ep and …/send-valid-one/{guid}/backoffice-ep. The backend registers both of those only under …/ppl/ap/validation-test-file-**helper-sending**/…; the non-sending controller exposes only delete, read, run-checking and validate-document-one-by-one. The same wrong base path is in the applet’s own copy of the service and in blg-akaun-ts-lib. | Use the validation results only; sending from the testbed needs the front-end fix. Both calls also hard-code accesspoint_id=1001, which is not configurable from the UI. |
| Sending Test → Submit toasts Send Successfully but nothing is sent | The effect builds an eventcontainer variable it never assigns and POSTs that undefined body to the coupon event service — a leftover from the voucher applet this one was cloned from. No Peppol endpoint is called. | Treat the Sending Test screen as not implemented at commit 5f24872. |
| The Inbox Queue advanced search does nothing | onSearch is an empty method and the search model supplied is the Sales Order one. | Sort and filter with the grid’s own column filters instead. |
| Personalization → Field Settings shows the 404 page | The menu entry points at a route that is not registered under personalization. | Use Settings → Field Settings (which is itself inert — see Configuration). |