diff --git a/phoss-ap-api/src/main/java/com/helger/phoss/ap/api/IOutboundTransactionManager.java b/phoss-ap-api/src/main/java/com/helger/phoss/ap/api/IOutboundTransactionManager.java
index 7b710ae1..101e6573 100644
--- a/phoss-ap-api/src/main/java/com/helger/phoss/ap/api/IOutboundTransactionManager.java
+++ b/phoss-ap-api/src/main/java/com/helger/phoss/ap/api/IOutboundTransactionManager.java
@@ -83,6 +83,12 @@ public interface IOutboundTransactionManager
* @param sPayloadMimeType
* MIME type for binary payloads (e.g. {@code application/pdf}). May be null
* for XML payloads.
+ * @param sCustom1
+ * First optional custom field (max 255 characters). May be null.
+ * @param sCustom2
+ * Second optional custom field (max 255 characters). May be null.
+ * @param sCustom3
+ * Third optional custom field (max 255 characters). May be null.
* @return The ID of the created transaction. Only null if insertion fails.
*/
@Nullable
@@ -103,7 +109,10 @@ String create (@NonNull ETransactionType eTransactionType,
@Nullable String sSbdhStandard,
@Nullable String sSbdhTypeVersion,
@Nullable String sSbdhType,
- @Nullable String sPayloadMimeType);
+ @Nullable String sPayloadMimeType,
+ @Nullable String sCustom1,
+ @Nullable String sCustom2,
+ @Nullable String sCustom3);
/**
* Look up a transaction by its unique ID.
diff --git a/phoss-ap-api/src/main/java/com/helger/phoss/ap/api/dto/OutboundS3SubmitRequest.java b/phoss-ap-api/src/main/java/com/helger/phoss/ap/api/dto/OutboundS3SubmitRequest.java
index 65cd4bc9..ce429077 100644
--- a/phoss-ap-api/src/main/java/com/helger/phoss/ap/api/dto/OutboundS3SubmitRequest.java
+++ b/phoss-ap-api/src/main/java/com/helger/phoss/ap/api/dto/OutboundS3SubmitRequest.java
@@ -84,6 +84,15 @@ public class OutboundS3SubmitRequest
example = "application/pdf")
private String payloadMimeType;
+ @Schema (description = "Optional custom field 1 (max 255 characters). Stored with the transaction and returned by the status APIs.")
+ private String custom1;
+
+ @Schema (description = "Optional custom field 2 (max 255 characters). Stored with the transaction and returned by the status APIs.")
+ private String custom2;
+
+ @Schema (description = "Optional custom field 3 (max 255 characters). Stored with the transaction and returned by the status APIs.")
+ private String custom3;
+
/** @return the sender participant ID */
public String getSenderID ()
{
@@ -278,4 +287,49 @@ public void setPayloadMimeType (final String s)
{
payloadMimeType = s;
}
+
+ /** @return the optional custom field 1 */
+ public String getCustom1 ()
+ {
+ return custom1;
+ }
+
+ /**
+ * @param s
+ * The custom field 1 to set.
+ */
+ public void setCustom1 (final String s)
+ {
+ custom1 = s;
+ }
+
+ /** @return the optional custom field 2 */
+ public String getCustom2 ()
+ {
+ return custom2;
+ }
+
+ /**
+ * @param s
+ * The custom field 2 to set.
+ */
+ public void setCustom2 (final String s)
+ {
+ custom2 = s;
+ }
+
+ /** @return the optional custom field 3 */
+ public String getCustom3 ()
+ {
+ return custom3;
+ }
+
+ /**
+ * @param s
+ * The custom field 3 to set.
+ */
+ public void setCustom3 (final String s)
+ {
+ custom3 = s;
+ }
}
diff --git a/phoss-ap-api/src/main/java/com/helger/phoss/ap/api/dto/OutboundTransactionResponse.java b/phoss-ap-api/src/main/java/com/helger/phoss/ap/api/dto/OutboundTransactionResponse.java
index 38a5073d..5747ed3c 100644
--- a/phoss-ap-api/src/main/java/com/helger/phoss/ap/api/dto/OutboundTransactionResponse.java
+++ b/phoss-ap-api/src/main/java/com/helger/phoss/ap/api/dto/OutboundTransactionResponse.java
@@ -87,6 +87,15 @@ public class OutboundTransactionResponse
nullable = true)
private String mlsStatus;
+ @Schema (description = "First optional custom field (max 255 characters); null if not set", nullable = true)
+ private String custom1;
+
+ @Schema (description = "Second optional custom field (max 255 characters); null if not set", nullable = true)
+ private String custom2;
+
+ @Schema (description = "Third optional custom field (max 255 characters); null if not set", nullable = true)
+ private String custom3;
+
/**
* Default constructor for JSON deserialization.
*/
@@ -119,6 +128,9 @@ public static OutboundTransactionResponse fromDomain (@NonNull final IOutboundTr
aResp.nextRetryDT = aTx.getNextRetryDT () != null ? aTx.getNextRetryDT ().toString () : null;
aResp.errorDetails = aTx.getErrorDetails ();
aResp.mlsStatus = aTx.getMlsStatus () != null ? aTx.getMlsStatus ().getID () : null;
+ aResp.custom1 = aTx.getCustom1 ();
+ aResp.custom2 = aTx.getCustom2 ();
+ aResp.custom3 = aTx.getCustom3 ();
return aResp;
}
@@ -346,4 +358,49 @@ public void setMlsStatus (final String s)
{
mlsStatus = s;
}
+
+ /** @return the first custom field */
+ public String getCustom1 ()
+ {
+ return custom1;
+ }
+
+ /**
+ * @param s
+ * The first custom field to set.
+ */
+ public void setCustom1 (final String s)
+ {
+ custom1 = s;
+ }
+
+ /** @return the second custom field */
+ public String getCustom2 ()
+ {
+ return custom2;
+ }
+
+ /**
+ * @param s
+ * The second custom field to set.
+ */
+ public void setCustom2 (final String s)
+ {
+ custom2 = s;
+ }
+
+ /** @return the third custom field */
+ public String getCustom3 ()
+ {
+ return custom3;
+ }
+
+ /**
+ * @param s
+ * The third custom field to set.
+ */
+ public void setCustom3 (final String s)
+ {
+ custom3 = s;
+ }
}
diff --git a/phoss-ap-api/src/main/java/com/helger/phoss/ap/api/model/IOutboundTransaction.java b/phoss-ap-api/src/main/java/com/helger/phoss/ap/api/model/IOutboundTransaction.java
index 5763ae29..2712ab3b 100644
--- a/phoss-ap-api/src/main/java/com/helger/phoss/ap/api/model/IOutboundTransaction.java
+++ b/phoss-ap-api/src/main/java/com/helger/phoss/ap/api/model/IOutboundTransaction.java
@@ -220,4 +220,22 @@ public interface IOutboundTransaction extends IHasID
*/
@Nullable
String getPayloadMimeType ();
+
+ /**
+ * @return The first optional custom field (max 255 characters), or null if not set.
+ */
+ @Nullable
+ String getCustom1 ();
+
+ /**
+ * @return The second optional custom field (max 255 characters), or null if not set.
+ */
+ @Nullable
+ String getCustom2 ();
+
+ /**
+ * @return The third optional custom field (max 255 characters), or null if not set.
+ */
+ @Nullable
+ String getCustom3 ();
}
diff --git a/phoss-ap-api/src/test/java/com/helger/phoss/ap/api/dto/OutboundS3SubmitRequestTest.java b/phoss-ap-api/src/test/java/com/helger/phoss/ap/api/dto/OutboundS3SubmitRequestTest.java
index 891ae057..e72bd51a 100644
--- a/phoss-ap-api/src/test/java/com/helger/phoss/ap/api/dto/OutboundS3SubmitRequestTest.java
+++ b/phoss-ap-api/src/test/java/com/helger/phoss/ap/api/dto/OutboundS3SubmitRequestTest.java
@@ -45,6 +45,9 @@ public void testDefaultConstructor ()
assertNull (a.getSbdhTypeVersion ());
assertNull (a.getSbdhType ());
assertNull (a.getPayloadMimeType ());
+ assertNull (a.getCustom1 ());
+ assertNull (a.getCustom2 ());
+ assertNull (a.getCustom3 ());
}
@Test
@@ -64,6 +67,9 @@ public void testSetters ()
a.setSbdhTypeVersion ("1.0");
a.setSbdhType ("type1");
a.setPayloadMimeType ("application/pdf");
+ a.setCustom1 ("c1");
+ a.setCustom2 ("c2");
+ a.setCustom3 ("c3");
assertEquals ("sender1", a.getSenderID ());
assertEquals ("receiver1", a.getReceiverID ());
@@ -78,5 +84,8 @@ public void testSetters ()
assertEquals ("1.0", a.getSbdhTypeVersion ());
assertEquals ("type1", a.getSbdhType ());
assertEquals ("application/pdf", a.getPayloadMimeType ());
+ assertEquals ("c1", a.getCustom1 ());
+ assertEquals ("c2", a.getCustom2 ());
+ assertEquals ("c3", a.getCustom3 ());
}
}
diff --git a/phoss-ap-api/src/test/java/com/helger/phoss/ap/api/dto/OutboundTransactionResponseTest.java b/phoss-ap-api/src/test/java/com/helger/phoss/ap/api/dto/OutboundTransactionResponseTest.java
index f6ea53d0..4aa4a986 100644
--- a/phoss-ap-api/src/test/java/com/helger/phoss/ap/api/dto/OutboundTransactionResponseTest.java
+++ b/phoss-ap-api/src/test/java/com/helger/phoss/ap/api/dto/OutboundTransactionResponseTest.java
@@ -60,6 +60,9 @@ public void testDefaultConstructor ()
assertNull (a.getNextRetryDT ());
assertNull (a.getErrorDetails ());
assertNull (a.getMlsStatus ());
+ assertNull (a.getCustom1 ());
+ assertNull (a.getCustom2 ());
+ assertNull (a.getCustom3 ());
}
@Test
@@ -81,6 +84,9 @@ public void testSettersAndGetters ()
a.setNextRetryDT ("2026-03-29T11:00:00Z");
a.setErrorDetails ("some error");
a.setMlsStatus ("received_ap");
+ a.setCustom1 ("c1");
+ a.setCustom2 ("c2");
+ a.setCustom3 ("c3");
assertEquals ("id1", a.getID ());
assertEquals ("business_document", a.getTransactionType ());
@@ -97,6 +103,9 @@ public void testSettersAndGetters ()
assertEquals ("2026-03-29T11:00:00Z", a.getNextRetryDT ());
assertEquals ("some error", a.getErrorDetails ());
assertEquals ("received_ap", a.getMlsStatus ());
+ assertEquals ("c1", a.getCustom1 ());
+ assertEquals ("c2", a.getCustom2 ());
+ assertEquals ("c3", a.getCustom3 ());
}
@Test
@@ -133,7 +142,10 @@ public void testFromDomainAllFieldsPopulated ()
null,
null,
null,
- null);
+ null,
+ "custom-a",
+ "custom-b",
+ "custom-c");
final OutboundTransactionResponse aResp = OutboundTransactionResponse.fromDomain (aTx);
assertNotNull (aResp);
@@ -152,6 +164,9 @@ public void testFromDomainAllFieldsPopulated ()
assertNotNull (aResp.getNextRetryDT ());
assertEquals ("err details", aResp.getErrorDetails ());
assertEquals ("received_ap", aResp.getMlsStatus ());
+ assertEquals ("custom-a", aResp.getCustom1 ());
+ assertEquals ("custom-b", aResp.getCustom2 ());
+ assertEquals ("custom-c", aResp.getCustom3 ());
}
@Test
@@ -186,6 +201,9 @@ public void testFromDomainNullableFieldsNull ()
null,
null,
null,
+ null,
+ null,
+ null,
null);
final OutboundTransactionResponse aResp = OutboundTransactionResponse.fromDomain (aTx);
@@ -228,7 +246,10 @@ private static IOutboundTransaction _createMock (@NonNull final String sID,
@Nullable final String sSbdhStandard,
@Nullable final String sSbdhTypeVersion,
@Nullable final String sSbdhType,
- @Nullable final String sPayloadMimeType)
+ @Nullable final String sPayloadMimeType,
+ @Nullable final String sCustom1,
+ @Nullable final String sCustom2,
+ @Nullable final String sCustom3)
{
return new IOutboundTransaction ()
{
@@ -260,6 +281,9 @@ private static IOutboundTransaction _createMock (@NonNull final String sID,
public String getSbdhTypeVersion () { return sSbdhTypeVersion; }
public String getSbdhType () { return sSbdhType; }
public String getPayloadMimeType () { return sPayloadMimeType; }
+ public String getCustom1 () { return sCustom1; }
+ public String getCustom2 () { return sCustom2; }
+ public String getCustom3 () { return sCustom3; }
};
}
}
diff --git a/phoss-ap-core/src/main/java/com/helger/phoss/ap/core/mls/MlsHandler.java b/phoss-ap-core/src/main/java/com/helger/phoss/ap/core/mls/MlsHandler.java
index aea09a47..1f2a2205 100644
--- a/phoss-ap-core/src/main/java/com/helger/phoss/ap/core/mls/MlsHandler.java
+++ b/phoss-ap-core/src/main/java/com/helger/phoss/ap/core/mls/MlsHandler.java
@@ -213,6 +213,11 @@ public static ESuccess triggerSendingInboundResultMls (@NonNull final IInboundTr
final String sSbdhType = null;
final String sPayloadMimeType = null;
+ // Custom fields do not apply to system-generated MLS responses
+ final String sCustom1 = null;
+ final String sCustom2 = null;
+ final String sCustom3 = null;
+
// Create outbound transaction
final String sMlsTxID = aOutboundMgr.create (ETransactionType.MLS_RESPONSE,
aMLSSenderPID.getURIEncoded (),
@@ -231,7 +236,10 @@ public static ESuccess triggerSendingInboundResultMls (@NonNull final IInboundTr
sSbdhStandard,
sSbdhTypeVersion,
sSbdhType,
- sPayloadMimeType);
+ sPayloadMimeType,
+ sCustom1,
+ sCustom2,
+ sCustom3);
final var aMlsTx = aOutboundMgr.getByID (sMlsTxID);
if (aMlsTx == null)
{
diff --git a/phoss-ap-core/src/main/java/com/helger/phoss/ap/core/outbound/OutboundOrchestrator.java b/phoss-ap-core/src/main/java/com/helger/phoss/ap/core/outbound/OutboundOrchestrator.java
index df38ce5e..47cb7ff1 100644
--- a/phoss-ap-core/src/main/java/com/helger/phoss/ap/core/outbound/OutboundOrchestrator.java
+++ b/phoss-ap-core/src/main/java/com/helger/phoss/ap/core/outbound/OutboundOrchestrator.java
@@ -141,6 +141,12 @@ private OutboundOrchestrator ()
* @param sPayloadMimeType
* Optional payload MIME type (e.g. "application/pdf"). May be null for XML
* payloads.
+ * @param sCustom1
+ * First optional custom field (max 255 characters). May be null.
+ * @param sCustom2
+ * Second optional custom field (max 255 characters). May be null.
+ * @param sCustom3
+ * Third optional custom field (max 255 characters). May be null.
* @return The created {@link IOutboundTransaction} or null if the document could not
* be stored or verification failed.
*/
@@ -157,7 +163,10 @@ public static IOutboundTransaction submitRawDocument (@NonNull final String sLog
@Nullable final String sSbdhStandard,
@Nullable final String sSbdhTypeVersion,
@Nullable final String sSbdhType,
- @Nullable final String sPayloadMimeType)
+ @Nullable final String sPayloadMimeType,
+ @Nullable final String sCustom1,
+ @Nullable final String sCustom2,
+ @Nullable final String sCustom3)
{
LOGGER.info (sLogPrefix + "Submitting raw document with SBDH Instance ID '" + sSbdhInstanceID + "'");
@@ -263,7 +272,10 @@ public static IOutboundTransaction submitRawDocument (@NonNull final String sLog
sSbdhStandard,
sSbdhTypeVersion,
sSbdhType,
- sPayloadMimeType);
+ sPayloadMimeType,
+ sCustom1,
+ sCustom2,
+ sCustom3);
for (final var aHandler : APCoreMetaManager.getAllLifecycleHandlers ())
aHandler.onOutboundDocumentAccepted (sTransactionID,
aSenderID.getURIEncoded (),
@@ -285,13 +297,22 @@ public static IOutboundTransaction submitRawDocument (@NonNull final String sLog
* The input stream containing the complete pre-built SBD. May not be null.
* @param sMlsTo
* Optional MLS "To" address. May be null.
+ * @param sCustom1
+ * First optional custom field (max 255 characters). May be null.
+ * @param sCustom2
+ * Second optional custom field (max 255 characters). May be null.
+ * @param sCustom3
+ * Third optional custom field (max 255 characters). May be null.
* @return The created {@link IOutboundTransaction} or null if the SBD could not be
* parsed.
*/
@Nullable
public static IOutboundTransaction submitPrebuiltSBD (@NonNull final String sLogPrefix,
@NonNull final InputStream aSbdIS,
- @Nullable final String sMlsTo)
+ @Nullable final String sMlsTo,
+ @Nullable final String sCustom1,
+ @Nullable final String sCustom2,
+ @Nullable final String sCustom3)
{
LOGGER.info (sLogPrefix + "Submitting pre-built SBD");
@@ -403,7 +424,10 @@ public static IOutboundTransaction submitPrebuiltSBD (@NonNull final String sLog
sSbdhStandard,
sSbdhTypeVersion,
sSbdhType,
- sPayloadMimeType);
+ sPayloadMimeType,
+ sCustom1,
+ sCustom2,
+ sCustom3);
for (final var aHandler : APCoreMetaManager.getAllLifecycleHandlers ())
aHandler.onOutboundDocumentAccepted (sTransactionID,
aSbdData.getSenderURIEncoded (),
diff --git a/phoss-ap-core/src/main/java/com/helger/phoss/ap/core/reporting/APPeppolReportHelper.java b/phoss-ap-core/src/main/java/com/helger/phoss/ap/core/reporting/APPeppolReportHelper.java
index 0c4af928..79eb5de0 100644
--- a/phoss-ap-core/src/main/java/com/helger/phoss/ap/core/reporting/APPeppolReportHelper.java
+++ b/phoss-ap-core/src/main/java/com/helger/phoss/ap/core/reporting/APPeppolReportHelper.java
@@ -309,6 +309,10 @@ public static ESuccess createAndSendPeppolReports (@NonNull final YearMonth aYea
final String sSbdhTypeVersion = null;
final String sSbdhType = null;
final String sPayloadMimeType = null;
+ // Custom fields do not apply to system-generated Peppol Reporting documents
+ final String sCustom1 = null;
+ final String sCustom2 = null;
+ final String sCustom3 = null;
final IOutboundTransaction aTx = OutboundOrchestrator.submitRawDocument ("[PeppolReporting] ",
aSenderID,
aReceiverID,
@@ -321,7 +325,10 @@ public static ESuccess createAndSendPeppolReports (@NonNull final YearMonth aYea
sSbdhStandard,
sSbdhTypeVersion,
sSbdhType,
- sPayloadMimeType);
+ sPayloadMimeType,
+ sCustom1,
+ sCustom2,
+ sCustom3);
if (aTx == null)
throw new IllegalStateException ("Failed to submit Peppol Reporting document for transmission");
diff --git a/phoss-ap-db/src/main/java/com/helger/phoss/ap/db/OutboundTransactionManagerJdbc.java b/phoss-ap-db/src/main/java/com/helger/phoss/ap/db/OutboundTransactionManagerJdbc.java
index 4f239be7..b12b792e 100644
--- a/phoss-ap-db/src/main/java/com/helger/phoss/ap/db/OutboundTransactionManagerJdbc.java
+++ b/phoss-ap-db/src/main/java/com/helger/phoss/ap/db/OutboundTransactionManagerJdbc.java
@@ -58,7 +58,8 @@ public class OutboundTransactionManagerJdbc extends AbstractAPJdbcManager implem
" c1_country_code, status, attempt_count, created_dt, completed_dt," +
" reporting_status, next_retry_dt, error_details, mls_to, mls_status," +
" mls_received_dt, mls_id, mls_inbound_transaction_id," +
- " sbdh_standard, sbdh_type_version, sbdh_type, payload_mime_type";
+ " sbdh_standard, sbdh_type_version, sbdh_type, payload_mime_type," +
+ " custom1, custom2, custom3";
private final String m_sTableName;
@@ -96,7 +97,10 @@ public String create (@NonNull final ETransactionType eTransactionType,
@Nullable final String sSbdhStandard,
@Nullable final String sSbdhTypeVersion,
@Nullable final String sSbdhType,
- @Nullable final String sPayloadMimeType)
+ @Nullable final String sPayloadMimeType,
+ @Nullable final String sCustom1,
+ @Nullable final String sCustom2,
+ @Nullable final String sCustom3)
{
final String sID = createUniqueRowID ();
@@ -106,7 +110,7 @@ public String create (@NonNull final ETransactionType eTransactionType,
" (" +
COLS +
")" +
- " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
+ " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
new ConstantPreparedStatementDataProvider (sID,
eTransactionType.getID (),
sSenderID,
@@ -135,7 +139,10 @@ public String create (@NonNull final ETransactionType eTransactionType,
sSbdhStandard,
sSbdhTypeVersion,
sSbdhType,
- sPayloadMimeType));
+ sPayloadMimeType,
+ sCustom1,
+ sCustom2,
+ sCustom3));
if (LOGGER.isDebugEnabled ())
LOGGER.debug ("Stored new outbound transaction in DB. " + nRowsAffected + " rows affected.");
diff --git a/phoss-ap-db/src/main/java/com/helger/phoss/ap/db/dto/OutboundTransactionRow.java b/phoss-ap-db/src/main/java/com/helger/phoss/ap/db/dto/OutboundTransactionRow.java
index 7e051019..39be08ef 100644
--- a/phoss-ap-db/src/main/java/com/helger/phoss/ap/db/dto/OutboundTransactionRow.java
+++ b/phoss-ap-db/src/main/java/com/helger/phoss/ap/db/dto/OutboundTransactionRow.java
@@ -67,6 +67,9 @@ public class OutboundTransactionRow implements IOutboundTransaction
private final String m_sSbdhTypeVersion;
private final String m_sSbdhType;
private final String m_sPayloadMimeType;
+ private final String m_sCustom1;
+ private final String m_sCustom2;
+ private final String m_sCustom3;
/**
* Construct an outbound transaction row from a JDBC result row.
@@ -104,6 +107,9 @@ public OutboundTransactionRow (@NonNull final DBResultRow aRow)
m_sSbdhTypeVersion = aRow.getAsString (25);
m_sSbdhType = aRow.getAsString (26);
m_sPayloadMimeType = aRow.getAsString (27);
+ m_sCustom1 = aRow.getAsString (28);
+ m_sCustom2 = aRow.getAsString (29);
+ m_sCustom3 = aRow.getAsString (30);
ValueEnforcer.notEmpty (m_sID, "ID");
ValueEnforcer.notNull (m_eTransactionType, "TransactionType");
ValueEnforcer.notEmpty (m_sSenderID, "SenderID");
@@ -326,4 +332,25 @@ public String getPayloadMimeType ()
{
return m_sPayloadMimeType;
}
+
+ /** {@inheritDoc} */
+ @Nullable
+ public String getCustom1 ()
+ {
+ return m_sCustom1;
+ }
+
+ /** {@inheritDoc} */
+ @Nullable
+ public String getCustom2 ()
+ {
+ return m_sCustom2;
+ }
+
+ /** {@inheritDoc} */
+ @Nullable
+ public String getCustom3 ()
+ {
+ return m_sCustom3;
+ }
}
diff --git a/phoss-ap-db/src/main/resources/db/phoss-ap-flyway-db2/V4__OutboundCustomFields.sql b/phoss-ap-db/src/main/resources/db/phoss-ap-flyway-db2/V4__OutboundCustomFields.sql
new file mode 100644
index 00000000..e8adc9c5
--- /dev/null
+++ b/phoss-ap-db/src/main/resources/db/phoss-ap-flyway-db2/V4__OutboundCustomFields.sql
@@ -0,0 +1,33 @@
+--
+-- Copyright (C) 2026 Philip Helger (www.helger.com)
+-- philip[at]helger[dot]com
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+-- Custom outbound transaction fields (issue #64)
+-- Three optional custom identifier fields, max 255 characters each.
+-- Existing rows default to NULL. Mirrored into the archive table.
+
+-- DB2 puts a table into REORG-pending state after ALTER TABLE ... ADD COLUMN,
+-- so a REORG is required before the table is fully usable (and before exceeding
+-- DB2's limit of 3 pending ALTERs per table).
+ALTER TABLE outbound_transaction ADD COLUMN custom1 VARCHAR(255);
+ALTER TABLE outbound_transaction ADD COLUMN custom2 VARCHAR(255);
+ALTER TABLE outbound_transaction ADD COLUMN custom3 VARCHAR(255);
+CALL SYSPROC.ADMIN_CMD('REORG TABLE outbound_transaction');
+
+ALTER TABLE outbound_transaction_archive ADD COLUMN custom1 VARCHAR(255);
+ALTER TABLE outbound_transaction_archive ADD COLUMN custom2 VARCHAR(255);
+ALTER TABLE outbound_transaction_archive ADD COLUMN custom3 VARCHAR(255);
+CALL SYSPROC.ADMIN_CMD('REORG TABLE outbound_transaction_archive');
diff --git a/phoss-ap-db/src/main/resources/db/phoss-ap-flyway-h2/V4__OutboundCustomFields.sql b/phoss-ap-db/src/main/resources/db/phoss-ap-flyway-h2/V4__OutboundCustomFields.sql
new file mode 100644
index 00000000..2c17e370
--- /dev/null
+++ b/phoss-ap-db/src/main/resources/db/phoss-ap-flyway-h2/V4__OutboundCustomFields.sql
@@ -0,0 +1,28 @@
+--
+-- Copyright (C) 2026 Philip Helger (www.helger.com)
+-- philip[at]helger[dot]com
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+-- Custom outbound transaction fields (issue #64)
+-- Three optional custom identifier fields, max 255 characters each.
+-- Existing rows default to NULL. Mirrored into the archive table.
+
+ALTER TABLE outbound_transaction ADD COLUMN custom1 VARCHAR(255);
+ALTER TABLE outbound_transaction ADD COLUMN custom2 VARCHAR(255);
+ALTER TABLE outbound_transaction ADD COLUMN custom3 VARCHAR(255);
+
+ALTER TABLE outbound_transaction_archive ADD COLUMN custom1 VARCHAR(255);
+ALTER TABLE outbound_transaction_archive ADD COLUMN custom2 VARCHAR(255);
+ALTER TABLE outbound_transaction_archive ADD COLUMN custom3 VARCHAR(255);
diff --git a/phoss-ap-db/src/main/resources/db/phoss-ap-flyway-mysql/V4__OutboundCustomFields.sql b/phoss-ap-db/src/main/resources/db/phoss-ap-flyway-mysql/V4__OutboundCustomFields.sql
new file mode 100644
index 00000000..b24a8194
--- /dev/null
+++ b/phoss-ap-db/src/main/resources/db/phoss-ap-flyway-mysql/V4__OutboundCustomFields.sql
@@ -0,0 +1,28 @@
+--
+-- Copyright (C) 2026 Philip Helger (www.helger.com)
+-- philip[at]helger[dot]com
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+-- Custom outbound transaction fields (issue #64)
+-- Three optional custom identifier fields, max 255 characters each.
+-- Existing rows default to NULL. Mirrored into the archive table.
+
+ALTER TABLE `outbound_transaction` ADD COLUMN `custom1` VARCHAR(255);
+ALTER TABLE `outbound_transaction` ADD COLUMN `custom2` VARCHAR(255);
+ALTER TABLE `outbound_transaction` ADD COLUMN `custom3` VARCHAR(255);
+
+ALTER TABLE `outbound_transaction_archive` ADD COLUMN `custom1` VARCHAR(255);
+ALTER TABLE `outbound_transaction_archive` ADD COLUMN `custom2` VARCHAR(255);
+ALTER TABLE `outbound_transaction_archive` ADD COLUMN `custom3` VARCHAR(255);
diff --git a/phoss-ap-db/src/main/resources/db/phoss-ap-flyway-postgresql/V4__OutboundCustomFields.sql b/phoss-ap-db/src/main/resources/db/phoss-ap-flyway-postgresql/V4__OutboundCustomFields.sql
new file mode 100644
index 00000000..2c17e370
--- /dev/null
+++ b/phoss-ap-db/src/main/resources/db/phoss-ap-flyway-postgresql/V4__OutboundCustomFields.sql
@@ -0,0 +1,28 @@
+--
+-- Copyright (C) 2026 Philip Helger (www.helger.com)
+-- philip[at]helger[dot]com
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+-- Custom outbound transaction fields (issue #64)
+-- Three optional custom identifier fields, max 255 characters each.
+-- Existing rows default to NULL. Mirrored into the archive table.
+
+ALTER TABLE outbound_transaction ADD COLUMN custom1 VARCHAR(255);
+ALTER TABLE outbound_transaction ADD COLUMN custom2 VARCHAR(255);
+ALTER TABLE outbound_transaction ADD COLUMN custom3 VARCHAR(255);
+
+ALTER TABLE outbound_transaction_archive ADD COLUMN custom1 VARCHAR(255);
+ALTER TABLE outbound_transaction_archive ADD COLUMN custom2 VARCHAR(255);
+ALTER TABLE outbound_transaction_archive ADD COLUMN custom3 VARCHAR(255);
diff --git a/phoss-ap-db/src/test/java/com/helger/phoss/ap/db/JdbcManagerIntegrationTest.java b/phoss-ap-db/src/test/java/com/helger/phoss/ap/db/JdbcManagerIntegrationTest.java
index 0c4f0d24..5baf080a 100644
--- a/phoss-ap-db/src/test/java/com/helger/phoss/ap/db/JdbcManagerIntegrationTest.java
+++ b/phoss-ap-db/src/test/java/com/helger/phoss/ap/db/JdbcManagerIntegrationTest.java
@@ -100,6 +100,9 @@ private static String _createOutboundTx ()
null,
null,
null,
+ null,
+ null,
+ null,
null);
}
@@ -135,6 +138,9 @@ public void testOutboundCreateAndGetByID ()
assertNull (aTx.getMlsReceivedDT ());
assertNull (aTx.getMlsID ());
assertNull (aTx.getMlsInboundTransactionID ());
+ assertNull (aTx.getCustom1 ());
+ assertNull (aTx.getCustom2 ());
+ assertNull (aTx.getCustom3 ());
}
@Test
@@ -165,6 +171,9 @@ public void testOutboundGetBySbdhInstanceID ()
null,
null,
null,
+ null,
+ null,
+ null,
null);
assertNotNull (sID);
@@ -201,6 +210,9 @@ public void testOutboundCreateWithMlsFields ()
null,
null,
null,
+ null,
+ null,
+ null,
null);
assertNotNull (sID);
@@ -231,6 +243,9 @@ public void testOutboundCreateMlsResponse ()
null,
null,
null,
+ null,
+ null,
+ null,
null);
assertNotNull (sID);
@@ -262,7 +277,10 @@ public void testOutboundCreateWithSbdhOverrides ()
"urn:peppol:doctype:pdf+xml",
"0",
"factur-x",
- "application/pdf");
+ "application/pdf",
+ null,
+ null,
+ null);
assertNotNull (sID);
final IOutboundTransaction aTx = aMgr.getByID (sID);
@@ -275,6 +293,40 @@ public void testOutboundCreateWithSbdhOverrides ()
assertEquals ("FR", aTx.getC1CountryCode ());
}
+ @Test
+ public void testOutboundCreateWithCustomFields ()
+ {
+ final IOutboundTransactionManager aMgr = APJdbcMetaManager.getOutboundTransactionMgr ();
+ final String sID = aMgr.create (ETransactionType.BUSINESS_DOCUMENT,
+ "iso6523-actorid-upis::9915:sender",
+ "iso6523-actorid-upis::9915:receiver",
+ "busdox-docid-qns::urn:test:invoice",
+ "cenbii-procid-ubl::urn:test:process",
+ _uniqueID (),
+ ESourceType.PAYLOAD_ONLY,
+ "/tmp/test-custom.sbd",
+ 768L,
+ "hashCustom0123456789012345678901234567890123456789012345678901",
+ "IT",
+ _now (),
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ "my-custom-1",
+ "my-custom-2",
+ "my-custom-3");
+ assertNotNull (sID);
+
+ final IOutboundTransaction aTx = aMgr.getByID (sID);
+ assertNotNull (aTx);
+ assertEquals ("my-custom-1", aTx.getCustom1 ());
+ assertEquals ("my-custom-2", aTx.getCustom2 ());
+ assertEquals ("my-custom-3", aTx.getCustom3 ());
+ }
+
@Test
public void testOutboundCreateWithoutSbdhOverrides ()
{
@@ -311,6 +363,9 @@ public void testOutboundCreatePrebuiltSBD ()
null,
null,
null,
+ null,
+ null,
+ null,
null);
assertNotNull (sID);
@@ -1073,7 +1128,10 @@ public void testOutboundGetBySbdhInstanceIDIncludingArchive ()
null,
null,
null,
- null);
+ null,
+ "archive-custom-1",
+ "archive-custom-2",
+ "archive-custom-3");
assertNotNull (sTxID);
// Active table only: both methods find the transaction
@@ -1092,6 +1150,10 @@ public void testOutboundGetBySbdhInstanceIDIncludingArchive ()
assertNotNull (aTxArchived);
assertEquals (sTxID, aTxArchived.getID ());
assertEquals (sSbdhID, aTxArchived.getSbdhInstanceID ());
+ // Custom fields must be mirrored into the archive table (issue #64)
+ assertEquals ("archive-custom-1", aTxArchived.getCustom1 ());
+ assertEquals ("archive-custom-2", aTxArchived.getCustom2 ());
+ assertEquals ("archive-custom-3", aTxArchived.getCustom3 ());
}
@Test
diff --git a/phoss-ap-db/src/test/java/com/helger/phoss/ap/db/dto/OutboundTransactionRowTest.java b/phoss-ap-db/src/test/java/com/helger/phoss/ap/db/dto/OutboundTransactionRowTest.java
index 3a3f8af4..80110592 100644
--- a/phoss-ap-db/src/test/java/com/helger/phoss/ap/db/dto/OutboundTransactionRowTest.java
+++ b/phoss-ap-db/src/test/java/com/helger/phoss/ap/db/dto/OutboundTransactionRowTest.java
@@ -51,7 +51,7 @@ private static DBResultRow _createValidRow ()
{
final OffsetDateTime aNow = APBasicMetaManager.getTimestampMgr ().getCurrentDateTimeUTC ();
- // 24 columns, matching OutboundTransactionRow constructor order
+ // 31 columns, matching OutboundTransactionRow constructor order
// 0 id
// 1 transactionType
// 2 senderID
@@ -76,6 +76,13 @@ private static DBResultRow _createValidRow ()
// 21 mlsReceivedDT (nullable)
// 22 mlsID (nullable)
// 23 mlsInboundTransactionID (nullable)
+ // 24 sbdhStandard (nullable)
+ // 25 sbdhTypeVersion (nullable)
+ // 26 sbdhType (nullable)
+ // 27 payloadMimeType (nullable)
+ // 28 custom1 (nullable)
+ // 29 custom2 (nullable)
+ // 30 custom3 (nullable)
return DBResultRowHelper.createRow ("tx-001",
ETransactionType.BUSINESS_DOCUMENT.getID (),
"iso6523-actorid-upis::sender",
@@ -105,6 +112,10 @@ private static DBResultRow _createValidRow ()
null,
null,
null,
+ null,
+ // 28 custom1, 29 custom2, 30 custom3
+ null,
+ null,
null);
}
@@ -134,6 +145,9 @@ public void testAllMandatoryFieldsMappedCorrectly ()
assertNull (aTx.getSbdhTypeVersion ());
assertNull (aTx.getSbdhType ());
assertNull (aTx.getPayloadMimeType ());
+ assertNull (aTx.getCustom1 ());
+ assertNull (aTx.getCustom2 ());
+ assertNull (aTx.getCustom3 ());
}
@Test
@@ -184,7 +198,10 @@ public void testAllFieldsPopulated ()
"sbdh-std",
"sbdh-type-ver",
"sbdh-type",
- "application/xml");
+ "application/xml",
+ "custom-1",
+ "custom-2",
+ "custom-3");
final OutboundTransactionRow aTx = new OutboundTransactionRow (aRow);
assertEquals ("tx-full", aTx.getID ());
@@ -205,5 +222,8 @@ public void testAllFieldsPopulated ()
assertEquals ("sbdh-type-ver", aTx.getSbdhTypeVersion ());
assertEquals ("sbdh-type", aTx.getSbdhType ());
assertEquals ("application/xml", aTx.getPayloadMimeType ());
+ assertEquals ("custom-1", aTx.getCustom1 ());
+ assertEquals ("custom-2", aTx.getCustom2 ());
+ assertEquals ("custom-3", aTx.getCustom3 ());
}
}
diff --git a/phoss-ap-dirsender/src/main/java/com/helger/phoss/ap/dirsender/DirectoryFileProcessor.java b/phoss-ap-dirsender/src/main/java/com/helger/phoss/ap/dirsender/DirectoryFileProcessor.java
index f8452f54..2b198da4 100644
--- a/phoss-ap-dirsender/src/main/java/com/helger/phoss/ap/dirsender/DirectoryFileProcessor.java
+++ b/phoss-ap-dirsender/src/main/java/com/helger/phoss/ap/dirsender/DirectoryFileProcessor.java
@@ -215,7 +215,8 @@ public static void processFile (@NonNull final File aWatchDir, @NonNull final Fi
final IOutboundTransaction aTx;
try (final InputStream aIS = FileHelper.getBufferedInputStream (aPendingFile))
{
- aTx = OutboundOrchestrator.submitPrebuiltSBD (sLogPrefix, aIS, null);
+ // Custom fields are not available for directory-based ingestion
+ aTx = OutboundOrchestrator.submitPrebuiltSBD (sLogPrefix, aIS, null, null, null, null);
}
catch (final Exception ex)
{
diff --git a/phoss-ap-webapp/src/main/java/com/helger/phoss/ap/webapp/controller/OutboundController.java b/phoss-ap-webapp/src/main/java/com/helger/phoss/ap/webapp/controller/OutboundController.java
index 6dd79672..c0c3c94a 100644
--- a/phoss-ap-webapp/src/main/java/com/helger/phoss/ap/webapp/controller/OutboundController.java
+++ b/phoss-ap-webapp/src/main/java/com/helger/phoss/ap/webapp/controller/OutboundController.java
@@ -21,6 +21,7 @@
import java.util.List;
import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
@@ -87,6 +88,38 @@ public class OutboundController
{
private static final Logger LOGGER = LoggerFactory.getLogger (OutboundController.class);
+ /** Maximum length of each custom field (issue #64). */
+ private static final int MAX_CUSTOM_FIELD_LENGTH = 255;
+
+ /**
+ * Validate that none of the optional custom fields exceeds the maximum length.
+ *
+ * @param sCustom1
+ * First custom field. May be null.
+ * @param sCustom2
+ * Second custom field. May be null.
+ * @param sCustom3
+ * Third custom field. May be null.
+ * @return A 400 Bad Request response describing the first offending field, or null
+ * if all fields are valid.
+ */
+ @Nullable
+ private static ResponseEntity _validateCustomFields (@Nullable final String sCustom1,
+ @Nullable final String sCustom2,
+ @Nullable final String sCustom3)
+ {
+ final String [] aValues = { sCustom1, sCustom2, sCustom3 };
+ for (int i = 0; i < aValues.length; ++i)
+ if (aValues[i] != null && aValues[i].length () > MAX_CUSTOM_FIELD_LENGTH)
+ return ResponseEntity.badRequest ()
+ .body (JsonValue.create ("The 'custom" +
+ (i + 1) +
+ "' field exceeds the maximum length of " +
+ MAX_CUSTOM_FIELD_LENGTH +
+ " characters").getAsJsonString ());
+ return null;
+ }
+
/**
* Submit a raw (payload-only) document for outbound sending via the Peppol network. The document
* payload is read from the HTTP request body. Peppol identifiers are parsed from the URL path
@@ -116,6 +149,12 @@ public class OutboundController
* Optional SBDH type.
* @param sPayloadMimeType
* Optional payload MIME type.
+ * @param sCustom1
+ * Optional custom field 1 (max 255 characters).
+ * @param sCustom2
+ * Optional custom field 2 (max 255 characters).
+ * @param sCustom3
+ * Optional custom field 3 (max 255 characters).
* @return The {@link Phase4PeppolSendingReport} as JSON on success, or an error response.
* @throws Exception
* On unexpected errors.
@@ -163,7 +202,13 @@ public ResponseEntity submitRawDocument (@Parameter (description = "Pep
@Parameter (description = "SBDH Type override (e.g., factur-x). Auto-derived from the document type when omitted.") @RequestParam (value = "sbdhType",
required = false) final String sSbdhType,
@Parameter (description = "MIME type for binary payloads (e.g., application/pdf). When set, the payload is wrapped in ; otherwise treated as XML.") @RequestParam (value = "payloadMimeType",
- required = false) final String sPayloadMimeType) throws Exception
+ required = false) final String sPayloadMimeType,
+ @Parameter (description = "Optional custom field 1 (max 255 characters). Stored with the transaction and returned by the status APIs.") @RequestParam (value = "custom1",
+ required = false) final String sCustom1,
+ @Parameter (description = "Optional custom field 2 (max 255 characters). Stored with the transaction and returned by the status APIs.") @RequestParam (value = "custom2",
+ required = false) final String sCustom2,
+ @Parameter (description = "Optional custom field 3 (max 255 characters). Stored with the transaction and returned by the status APIs.") @RequestParam (value = "custom3",
+ required = false) final String sCustom3) throws Exception
{
if (!APCoreConfig.isSendingEnabled ())
{
@@ -171,6 +216,10 @@ public ResponseEntity submitRawDocument (@Parameter (description = "Pep
return ResponseEntity.notFound ().build ();
}
+ final ResponseEntity aCustomErr = _validateCustomFields (sCustom1, sCustom2, sCustom3);
+ if (aCustomErr != null)
+ return aCustomErr;
+
final String sEffectiveSbdhInstanceID = StringHelper.isNotEmpty (sSbdhInstanceID) ? sSbdhInstanceID
: PeppolSBDHData.createRandomSBDHInstanceIdentifier ();
@@ -247,7 +296,10 @@ public ResponseEntity submitRawDocument (@Parameter (description = "Pep
sSbdhStandard,
sSbdhTypeVersion,
sSbdhType,
- sPayloadMimeType);
+ sPayloadMimeType,
+ sCustom1,
+ sCustom2,
+ sCustom3);
if (aTx == null)
{
return ResponseEntity.unprocessableContent ()
@@ -275,6 +327,12 @@ public ResponseEntity submitRawDocument (@Parameter (description = "Pep
* The HTTP servlet request containing the SBD payload.
* @param sMlsTo
* Optional MLS "To" address.
+ * @param sCustom1
+ * Optional custom field 1 (max 255 characters).
+ * @param sCustom2
+ * Optional custom field 2 (max 255 characters).
+ * @param sCustom3
+ * Optional custom field 3 (max 255 characters).
* @return The {@link Phase4PeppolSendingReport} as JSON on success, or an error response.
* @throws Exception
* On unexpected errors.
@@ -294,7 +352,13 @@ public ResponseEntity submitRawDocument (@Parameter (description = "Pep
@ApiResponse (responseCode = "422", description = "Sending failed — see the report body for details") })
public ResponseEntity submitPrebuiltSBD (@Parameter (hidden = true) @NonNull final HttpServletRequest aServletRequest,
@Parameter (description = "Alternative Peppol Participant ID to receive MLS responses") @RequestParam (value = "mlsTo",
- required = false) final String sMlsTo) throws Exception
+ required = false) final String sMlsTo,
+ @Parameter (description = "Optional custom field 1 (max 255 characters). Stored with the transaction and returned by the status APIs.") @RequestParam (value = "custom1",
+ required = false) final String sCustom1,
+ @Parameter (description = "Optional custom field 2 (max 255 characters). Stored with the transaction and returned by the status APIs.") @RequestParam (value = "custom2",
+ required = false) final String sCustom2,
+ @Parameter (description = "Optional custom field 3 (max 255 characters). Stored with the transaction and returned by the status APIs.") @RequestParam (value = "custom3",
+ required = false) final String sCustom3) throws Exception
{
if (!APCoreConfig.isSendingEnabled ())
{
@@ -302,11 +366,20 @@ public ResponseEntity submitPrebuiltSBD (@Parameter (hidden = true) @No
return ResponseEntity.notFound ().build ();
}
+ final ResponseEntity aCustomErr = _validateCustomFields (sCustom1, sCustom2, sCustom3);
+ if (aCustomErr != null)
+ return aCustomErr;
+
// Read the InputStream only once
try (final InputStream aIS = aServletRequest.getInputStream ())
{
// Store in DB
- final IOutboundTransaction aTx = OutboundOrchestrator.submitPrebuiltSBD ("[SubmitPrebuiltSBD] ", aIS, sMlsTo);
+ final IOutboundTransaction aTx = OutboundOrchestrator.submitPrebuiltSBD ("[SubmitPrebuiltSBD] ",
+ aIS,
+ sMlsTo,
+ sCustom1,
+ sCustom2,
+ sCustom3);
if (aTx == null)
{
return ResponseEntity.badRequest ()
@@ -343,6 +416,12 @@ public ResponseEntity submitPrebuiltSBD (@Parameter (hidden = true) @No
* Optional SBDH Instance ID. A random one is generated if not provided.
* @param sMlsTo
* Optional MLS "To" address.
+ * @param sCustom1
+ * Optional custom field 1 (max 255 characters).
+ * @param sCustom2
+ * Optional custom field 2 (max 255 characters).
+ * @param sCustom3
+ * Optional custom field 3 (max 255 characters).
* @return The {@link Phase4PeppolSendingReport} as JSON on success, or an error response.
* @throws Exception
* On unexpected errors.
@@ -377,7 +456,13 @@ public ResponseEntity submitAutoDetect (@Parameter (description = "Pepp
@Parameter (description = "Custom SBDH Instance Identifier. A random UUID-based identifier is generated when omitted.") @RequestParam (value = "sbdhInstanceID",
required = false) final String sSbdhInstanceID,
@Parameter (description = "Alternative Peppol Participant ID to receive MLS responses") @RequestParam (value = "mlsTo",
- required = false) final String sMlsTo) throws Exception
+ required = false) final String sMlsTo,
+ @Parameter (description = "Optional custom field 1 (max 255 characters). Stored with the transaction and returned by the status APIs.") @RequestParam (value = "custom1",
+ required = false) final String sCustom1,
+ @Parameter (description = "Optional custom field 2 (max 255 characters). Stored with the transaction and returned by the status APIs.") @RequestParam (value = "custom2",
+ required = false) final String sCustom2,
+ @Parameter (description = "Optional custom field 3 (max 255 characters). Stored with the transaction and returned by the status APIs.") @RequestParam (value = "custom3",
+ required = false) final String sCustom3) throws Exception
{
if (!APCoreConfig.isSendingEnabled ())
{
@@ -385,6 +470,10 @@ public ResponseEntity submitAutoDetect (@Parameter (description = "Pepp
return ResponseEntity.notFound ().build ();
}
+ final ResponseEntity aCustomErr = _validateCustomFields (sCustom1, sCustom2, sCustom3);
+ if (aCustomErr != null)
+ return aCustomErr;
+
final String sLogPrefix = "[SubmitAutoDetect] ";
final IIdentifierFactory aIF = APBasicMetaManager.getIdentifierFactory ();
@@ -477,7 +566,10 @@ public ResponseEntity submitAutoDetect (@Parameter (description = "Pepp
null,
null,
null,
- null);
+ null,
+ sCustom1,
+ sCustom2,
+ sCustom3);
if (aTx == null)
return ResponseEntity.badRequest ()
.body (JsonValue.create ("Failed to submit outbound transaction").getAsJsonString ());
@@ -547,6 +639,12 @@ public ResponseEntity submitFromS3 (@RequestBody final OutboundS3Submit
.getAsJsonString ());
}
+ final ResponseEntity aCustomErr = _validateCustomFields (aRequest.getCustom1 (),
+ aRequest.getCustom2 (),
+ aRequest.getCustom3 ());
+ if (aCustomErr != null)
+ return aCustomErr;
+
final String sEffectiveSbdhInstanceID = StringHelper.isNotEmpty (aRequest.getSbdhInstanceID ()) ? aRequest.getSbdhInstanceID ()
: PeppolSBDHData.createRandomSBDHInstanceIdentifier ();
@@ -658,7 +756,10 @@ public ResponseEntity submitFromS3 (@RequestBody final OutboundS3Submit
aRequest.getSbdhStandard (),
aRequest.getSbdhTypeVersion (),
aRequest.getSbdhType (),
- aRequest.getPayloadMimeType ());
+ aRequest.getPayloadMimeType (),
+ aRequest.getCustom1 (),
+ aRequest.getCustom2 (),
+ aRequest.getCustom3 ());
if (aTx == null)
{
return ResponseEntity.unprocessableContent ()