diff --git a/org.idempiere.test/src/org/idempiere/test/jasper/AR_Invoice.jrxml b/org.idempiere.test/src/org/idempiere/test/jasper/AR_Invoice.jrxml
new file mode 100644
index 0000000000..175623e2b3
--- /dev/null
+++ b/org.idempiere.test/src/org/idempiere/test/jasper/AR_Invoice.jrxml
@@ -0,0 +1,867 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ "+ $F{description})]]>
+
+
+
+
+
+
+
+
+
+
+
+ CUSTOMER: " + $F{custnum}) +
+($F{documentno} == null ? "" : "
INVOICE: " + $F{documentno}) +
+($F{dateinvoiced} == null ? "" : "
DATE: " + DATEFORMAT($F{dateinvoiced},"dd-MM-yyyy"))]]>
+
+
+
+
+
+
+
+
+
+
+ " + $F{custname2})]]>
+
+
+
+
+
+
+
+
+
+
+
+
+ " + $F{address2}) +
+($F{address3} == null ? "" : "
" + $F{address3}) +
+($F{address4} == null ? "" : "
" + $F{address4})]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/org.idempiere.test/src/org/idempiere/test/jasper/PrintWithinProcess.java b/org.idempiere.test/src/org/idempiere/test/jasper/PrintWithinProcess.java
new file mode 100644
index 0000000000..a28b8b9e7a
--- /dev/null
+++ b/org.idempiere.test/src/org/idempiere/test/jasper/PrintWithinProcess.java
@@ -0,0 +1,148 @@
+/***********************************************************************
+ * This file is part of iDempiere ERP Open Source *
+ * http://www.idempiere.org *
+ * *
+ * Copyright (C) Contributors *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU General Public License *
+ * as published by the Free Software Foundation; either version 2 *
+ * of the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
+ * MA 02110-1301, USA. *
+ **********************************************************************/
+package org.idempiere.test.jasper;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.adempiere.exceptions.AdempiereException;
+import org.adempiere.util.ProcessUtil;
+import org.compiere.model.MInvoice;
+import org.compiere.model.MProcess;
+import org.compiere.model.PO;
+import org.compiere.model.Query;
+import org.compiere.process.ProcessInfo;
+import org.compiere.util.Env;
+import org.compiere.util.Trx;
+import org.idempiere.test.AbstractTestCase;
+import org.junit.jupiter.api.Test;
+
+/**
+ *
+ */
+public class PrintWithinProcess extends AbstractTestCase {
+
+ /**
+ *
+ */
+ public PrintWithinProcess() {
+ }
+
+ @Test
+ public void testPrintWithLocalFile() {
+ Properties ctx = Env.getCtx();
+ String trxName = getTrxName();
+
+ MProcess process = null;
+ try {
+ String fileName = putResourceInTempFolder("org/idempiere/test/jasper/AR_Invoice.jrxml");
+ process = new MProcess(ctx, 0, trxName);
+ process.set_ValueNoCheck("AD_Client_ID", 0);
+ process.setAD_Org_ID(0);
+ process.setJasperReport("file://" + fileName);
+ process.setName("Test Invoice Jasper");
+ process.setValue("Test_Invoice_Jasper");
+ process.saveCrossTenantSafeEx();
+ commit();
+
+ List invoices = new Query(ctx, MInvoice.Table_Name, "C_Invoice_ID IN (?,?)", trxName)
+ .setClient_ID()
+ .setOnlyActiveRecords(true)
+ .setParameters(103, 109)
+ .list();
+ for (MInvoice invoice : invoices) {
+ invoice.setDescription("Test Printing within a Process");
+ invoice.saveEx();
+ }
+
+ ProcessInfo pi = new ProcessInfo (process.getName(), process.getAD_Process_ID());
+ pi.setClassName(ProcessUtil.JASPER_STARTER_CLASS);
+ pi.setAD_User_ID(getAD_User_ID());
+ pi.setAD_Client_ID(getAD_Client_ID());
+ pi.setPrintPreview(false);
+ pi.setIsBatch(true);
+ Trx trx = Trx.get(trxName, false);
+
+ List pdfList = new ArrayList();
+ for (MInvoice invoice : invoices) {
+ pi.setRecord_ID(invoice.getC_Invoice_ID());
+ ProcessUtil.startJavaProcess(Env.getCtx(), pi, trx, false);
+ assertFalse(pi.isError(), pi.getSummary());
+ assertFalse(pi.getPDFReport() == null);
+ pdfList.add(pi.getPDFReport());
+ }
+ assertFalse(pdfList.isEmpty());
+ } finally {
+ rollback();
+ if (process != null) {
+ int oldRole = Env.getAD_Role_ID(ctx);
+ try {
+ PO.setCrossTenantSafe();
+ Env.setContext(ctx, Env.AD_ROLE_ID, 0); // to allow deleting process
+ process.deleteEx(true);
+ } finally {
+ Env.setContext(ctx, Env.AD_ROLE_ID, oldRole);
+ PO.clearCrossTenantSafe();
+ }
+ }
+ commit();
+ }
+ }
+
+ private String putResourceInTempFolder(String resource) {
+ URL url = getClass().getClassLoader().getResource(resource);
+ if (url != null) {
+ String localFileName = url.toString().substring(url.toString().lastIndexOf(File.separator)+1);
+ String extension = localFileName.substring(localFileName.lastIndexOf("."));
+ File tmpOutputFile = null;
+ try (InputStream inputStream = url.openStream()) {
+ if (inputStream != null) {
+ File tmpdir = Files.createTempDirectory("test_jasper_" + Env.getContext(Env.getCtx(), Env.AD_SESSION_ID)).toFile();
+ tmpOutputFile = File.createTempFile(localFileName.substring(0, localFileName.lastIndexOf(".")), extension, tmpdir);
+ try (OutputStream out = new FileOutputStream(tmpOutputFile);) {
+ if (out != null) {
+ byte buf[] = new byte[1024];
+ int len;
+ while ((len = inputStream.read(buf)) > 0) {
+ out.write(buf, 0, len);
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ throw new AdempiereException(e);
+ }
+ return tmpOutputFile.getAbsolutePath();
+ }
+ throw new AdempiereException("Resource " + resource + " not found");
+ }
+
+}