Skip to content

Peppol Reporting

Arun Kumar edited this page Mar 4, 2024 · 7 revisions

Peppol Reporting

Business Message Envelope/SBDH

Peppol Business Message Envelope specification SBDH v2.0.1 is basic building block or supporting specification of Peppol Reporting. This is used to pass C1 Country code from C2 to C3 via SBDH header (StandardBusinessDocumentHeader/BusinessScope/Scope[Type=”COUNTRY_C1”]). Oxalis is supporting this specification since version Oxalis 6.1.1/Oxalis-AS4 6.1.1

Reporting Specification

Peppol “Transaction Statistics Reporting” and Peppol “End User Statistics Reporting” is mandatory from 1st January 2024. Current Transaction Statistics Reporting(TSR) specification version is 1.0.2 and End User Statistics Reporting(EUSR) specification version is 1.1.1.

To support Peppol Reporting, Peppol AP/SP need to perform following activities:

  • Data Gathering/Collection
  • Data Preparation/Aggregation
  • Report Validation
  • Data Transmission

Data Gathering or Collection

Input required to implement peppol reporting i.e., “data gathering/collection” is available either in SBDH header or AS4 transmission message except C4 country code. AP service provider must store all relevant information of Peppol incoming and outgoing messages. Historically AP service providers developed their own way to store transaction data which they used to report transactions to Peppol Authority. Originally Oxalis did provided support for storing Transaction statistics, but it was later moved to legacy component and no longer maintained.

For data collection, AP service provider need data storage so that this data can be used for data aggregation during report generation process. Best way to store data is to store it in some relational or NoSQL database. There are plenty of options here: Oracle, MS SQL Server, MySQL, H2 database, MongoDB etc…

AP service provider can capture data from SBDH & AS4 message transmission by creating Oxalis plugin and store required information in the database of choice.

Data collection fields/column

  1. ExchangeTime”: Message exchange time in UTC, precision up to second – Available in AS4 Transmission message “eb:UserMessage/eb:MessageInfo/eb:Timestamp” – Column/Field used in both TSR, EUSR
  2. Direction”: Direction of exchange (incoming or outgoing) – Column/Field used in both TSR, EUSR
  3. C2SeatID”: Peppol Seat ID of C2 – “For outgoing (sending), C2SeatID can be extracted from the CN of the Peppol Service Provider certificate used for signing the AS4 message and for incoming (receiving), C2SeatID can be deduced from the Peppol signing certificate that is part of the received AS4 message (X.509 Certificate Subject CN value)” – Column/Field used in TSR only
  4. C3SeatID”: Peppol Seat ID of C3 – “For outgoing (sending), C3SeatID can be deduced from the Peppol certificate extracted from the SMP query, used for the encryption of the AS4 message” and incoming (receiving), C3SeatID is a constant value, typically extracted from the CN of the Peppol Service Provider certificate used for decrypting the received AS4 Message (X.509 Certificate Subject CN value) and for – Column/Field used in TSR only
  5. DocType ID”: Document Type ID of exchanged message – ”Available in AS4 User Message (eb:UserMessage/eb:CollaborationInfo/eb:Action) and in the SBDH :StandardBusinessDocumentHeader/BusinessScope/Scope[Type=”DOCUMENTID”]” – Column/Field used in both TSR, EUSR
  6. Process ID”: Process ID of exchanged message – ”Available in AS4 User Message: eb:UserMessage/eb:CollaborationInfo/eb:Service(incl. @type) and in the SBDH: StandardBusinessDocumentHeader/BusinessScope/Scope[Type=“PROCESSID”]”– Column/Field used in both TSR, EUSR
  7. TransportProtocol”: Transport Protocol used during exchange – ”Default value peppol-transport-as4-v2_0” – Column/Field used in TSR only
  8. C1Country”: The Country code of Sender End User – ”Available in SBDH header _StandardBusinessDocumentHeader/BusinessScope/Scope[Type=”COUNTRY_C1”] _” – Column/Field used in both TSR, EUSR
  9. C4Country”: The Country code of Receiver End User – ”There is no “field” in the transmitted data to hold the C4 country code, C3 must retrieved it from SP based on its KYC. If the specific Receiver has a Business Card for the Peppol Directory, then the Country Code required for reporting should match the Country Code of the Business Card” – Column/Field used in both TSR, EUSR
  10. End User ID”: This is implementation specific to each Service Provider and used to aggregate data - Column/Field used in EUSR only

Sample Inbound reporting fields code snippet

// SampleReceiptPersister class which extends network.oxalis.api.persist.ReceiptPersister

@Singleton @Type("SampleReceiptPersister") public class SampleReceiptPersister implements ReceiptPersister {

private static final Logger LOGGER = LoggerFactory.getLogger(SampleReceiptPersister.class);
private final X509Certificate myAccessPointCertificate;

//Additional variable below if required


@Inject
public SampleReceiptPersister (@Named("inbound") Path inboundFolder, 
	X509Certificate myAccessPointCertificate, EvidenceFactory evidenceFactory) {
this.inboundFolder = inboundFolder;
this.myAccessPointCertificate = myAccessPointCertificate;
this.evidenceFactory = evidenceFactory;
}


@Override
public void persist(InboundMetadata inboundMetadata, Path payloadPath) throws IOException {


//Other code omitted below and above, only reporting specific code for illustration purpose

LOGGER.debug("##############################  Inbound reporting fields start ###############################################");
    LOGGER.debug("ExchangeTime:" + inboundMetadata.getTimestamp());  //exchange time in UTC, precision up to second
    LOGGER.debug("direction:" + "IN");
    LOGGER.debug("C2SeatID:" + CertificateUtils.extractCommonName(inboundMetadata.getCertificate()));
    LOGGER.debug("C3SeatID:" + CertificateUtils.extractCommonName(myAccessPointCertificate));
    LOGGER.debug("DocTypeIDValue:" + inboundMetadata.getHeader().getDocumentType().getIdentifier());
    LOGGER.debug("DocTypeIDScheme:" + inboundMetadata.getHeader().getDocumentType().getScheme().getIdentifier());
    LOGGER.debug("ProcessIDValue:" + inboundMetadata.getHeader().getProcess().getIdentifier());
    LOGGER.debug("processIDScheme:" + inboundMetadata.getHeader().getProcess().getScheme().getIdentifier());
    LOGGER.debug("TransportProtocol:" + inboundMetadata.getProtocol().getIdentifier());
    LOGGER.debug("C1CountryCode:" + inboundMetadata.getHeader().getC1CountryIdentifier());
    LOGGER.debug("C4CountryCode:" + retrieveC4CC()); //C3 AP must retrieved it from SP based on its KYC. Use additional header fields to retrieve that
    LOGGER.debug("EndUserID:" + retrieveC4EndUserId()); //C3 AP must retrieved it from SP based on its KYC. Use additional header fields to retrieve that
LOGGER.debug("##############################  Inbound reporting fields end ###############################################");

// Additional receipt and reporting data persistance logic below. 


}

}

Sample Outbound reporting fields code snippet

private void outboundReportData(Tracer tracer, TransmissionRequest transmissionRequest, TransmissionResponse transmissionResponse) {

    //Other code omitted below and above, only reporting specific code for illustration purpose

LOGGER.debug("##############################  Outbound reporting fields start ###############################################");
    LOGGER.debug("ExchangeTime:" + transmissionResponse.getTimestamp()); //exchange time in UTC, precision up to second
    LOGGER.debug("direction:" + "OUT");
    LOGGER.debug("C2SeatID:" + sendingAccessPointCommonName); //Sending Access Point common name set via variable 
    LOGGER.debug("C3SeatID:" + CertificateUtils.extractCommonName(transmissionRequest.getEndpoint().getCertificate()));
    LOGGER.debug("DocTypeIDValue:" + transmissionResponse.getHeader().getDocumentType().getIdentifier());
    LOGGER.debug("DocTypeIDScheme:" + transmissionResponse.getHeader().getDocumentType().getScheme().getIdentifier());
    LOGGER.debug("ProcessIDValue:" + transmissionResponse.getHeader().getProcess().getIdentifier());
    LOGGER.debug("processIDScheme:" + transmissionResponse.getHeader().getProcess().getScheme().getIdentifier());
    LOGGER.debug("TransportProtocol:" + transmissionRequest.getEndpoint().getTransportProfile().getIdentifier());
    LOGGER.debug("C1CountryCode:" + transmissionResponse.getHeader().getC1CountryIdentifier());
    LOGGER.debug("C4CountryCode:" + ""); //C4 AP must send it empty because receiver (c4) country code is Not known to sending side
    LOGGER.debug("EndUserID:" + retrieveC1EndUserId()); //C2 AP must retrieved it from SP based on its KYC. Use additional header fields to retrieve that
LOGGER.debug("##############################  Outbound reporting fields end ###############################################");

    // Additional logic    

}

Data Preparation or Aggregation

For specific reporting period(i.e., from 1st till last day of month), SP need to prepare data by aggregating it. Data aggregation feature is solely dependent on database that SP is/will be using.

Report Validation

Validation of any document was never ever part of Oxalis codebase. Oxalis Community/Maintainer took strategic decision in the past that Oxalis will Not provide validation support and SP must rely on their own way of validating outgoing documents. So, it is out of scope at this moment, unless OMT decide to support this in near future.

Data Transmission

Oxalis 6.3.0 & above and Oxalis-AS4 6.3.0 Release & above can be used to transmit both EUSR and TSR reports to OpenPeppol Operating Office (OO) AP.

Important checkpoints during transmission of reports

Transaction Statistics Report The steps to transmit a TSR are:

  • Create the TSR XML representation, based on the Peppol TSR specification
  • Validate the TSR against the TSR Schematron
  • Send the message to the OpenPeppol Access Point via the Peppol eDelivery network
  • Ensure you receive a positive transport level acknowledgement

End User Statistics Report The steps to transmit an EUSR are:

  • Create the EUSR XML representation based on the Peppol EUSR specification
  • Validate the EUSR against the EUSR Schematron
  • Send the message to the OpenPeppol Access Point via the Peppol eDelivery network
  • Ensure you receive a positive transport level acknowledgement

Monthly Reporting Period

The Reporting Period is set as 1 month. Every report of a month MUST be reported within 15 calendar days of the next month.

On the 11th day the SP will receive a reminder by mail if the EUSR and/or the TSR is not yet received. On the 16th day the SP will receive a mail regarding non-compliance if the EUSR and/or the TSR was not received. The sending email address is reporting@peppol.eu – please make sure your email service can receive emails from that email address and neither blocks them nor marks them as spam or junk.

Special Considerations on data transmission

  • The receiving Peppol ID of OpenPeppol is 9925:be0848934496
  • Both TSR and EUSR needs to be wrapped in an SBDH envelope.
  • The Sender Country Code in the SBDH needs to be Country Code of the country where the SP is domiciled that is reporting the data.
  • Handling missing country codes: If the country code is missing or an invalid code is used, the incoming message will be non-compliant, because it does not respect the mandatory SBDH specification. Receiving Service Providers at Corner 3 may reject non-compliant messages or choose to process them and forward the included business documents to their customers for reasons of business continuity. If not rejected, messages with a missing C1 country code MUST be counted for TSR using the special country code “ZZ”. This only applies to the TSR. For EUSR all country codes must be known to the SP based on the End User Identification.
  • Invalid reports will not be processed by OpenPeppol. The SP is informed by mail what the errors are in the received invalid reports. The sending email address is reporting@peppol.eu – please make sure your email service can receive emails from that email address and neither blocks them nor marks them as spam or junk.

Reference