This is an automated email from the ASF dual-hosted git repository.
arunpati pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
The following commit(s) were added to refs/heads/trunk by this push:
new 11ad4c1fdb Improved: View combined PDF of selected orders from Find
Orders (OFBIZ-13598) (#2025)
11ad4c1fdb is described below
commit 11ad4c1fdb295aa483eca8634a30bf06c4c54ad5
Author: Arun Patidar <[email protected]>
AuthorDate: Wed Sep 16 15:06:22 2026 +0530
Improved: View combined PDF of selected orders from Find Orders
(OFBIZ-13598) (#2025)
Implements
[OFBIZ-13598](https://issues.apache.org/jira/browse/OFBIZ-13598): adds a
**View PDF** mass action to the Find Orders screen that opens one
combined PDF containing all selected orders in a new browser tab. The
existing Print (PDF) and Create File actions are unchanged.
## Changes
- **OrderEvents.java**: new `viewOrdersPdf` event — loops the selected
`orderIdList`, renders the existing `OrderPrintScreens.xml#OrderPDF`
screen per order through the existing ScreenRenderer + FOP pipeline,
merges the results with PDFBox `PDFMergerUtility` (already an OFBiz
dependency), and streams the combined PDF inline as `application/pdf`.
The screen location is hardcoded (not taken from a request parameter) to
avoid a screen-injection vector. Per-order permission checks apply,
since `OrderViewWebSecure.groovy` runs inside each render.
- **controller.xml**: new `orders.pdf` request-map for the event
(`auth=true`, success response `type=none`).
- **FindOrders.ftl**: new **View PDF** option in the mass action
dropdown, submitted with `target=_blank` so the PDF opens in a new tab
and the Find Orders results stay intact.
- **OrderUiLabels.xml**: new `OrderViewOrdersPdf` label ("View PDF",
English).
---
applications/order/config/OrderUiLabels.xml | 3 +
.../org/apache/ofbiz/order/order/OrderEvents.java | 80 ++++++++++++++++++++++
applications/order/template/order/FindOrders.ftl | 3 +
.../order/webapp/ordermgr/WEB-INF/controller.xml | 6 ++
4 files changed, 92 insertions(+)
diff --git a/applications/order/config/OrderUiLabels.xml
b/applications/order/config/OrderUiLabels.xml
index a7256a6235..01a8d00bcc 100644
--- a/applications/order/config/OrderUiLabels.xml
+++ b/applications/order/config/OrderUiLabels.xml
@@ -15187,6 +15187,9 @@
<value xml:lang="zh-CN">查看订单历史</value>
<value xml:lang="zh-TW">檢視訂單歷史</value>
</property>
+ <property key="OrderViewOrdersPdf">
+ <value xml:lang="en">View PDF</value>
+ </property>
<property key="OrderViewPermissionError">
<value xml:lang="ar">ليس لديك صلاحية مشاهدة هذه الصفحة (تحتاج إلى
"ORDERMGR_VIEW" أو "ORDERMGR_PURCHASE_VIEW" أو "ORDERMGR_ADMIN").</value>
<value xml:lang="de">Sie haben keine Leseberechtigung für diese Seite
("ORDERMGR_VIEW", "ORDERMGR_PURCHASE_VIEW" oder "ORDERMGR_ADMIN"
benötigt).</value>
diff --git
a/applications/order/src/main/java/org/apache/ofbiz/order/order/OrderEvents.java
b/applications/order/src/main/java/org/apache/ofbiz/order/order/OrderEvents.java
index 02a4cd4880..6c0d319a9e 100644
---
a/applications/order/src/main/java/org/apache/ofbiz/order/order/OrderEvents.java
+++
b/applications/order/src/main/java/org/apache/ofbiz/order/order/OrderEvents.java
@@ -18,30 +18,54 @@
*******************************************************************************/
package org.apache.ofbiz.order.order;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.stream.StreamSource;
+
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.apache.commons.io.IOUtils;
+import org.apache.fop.apps.Fop;
+import org.apache.fop.apps.MimeConstants;
import org.apache.ofbiz.base.util.Debug;
import org.apache.ofbiz.base.util.GeneralException;
import org.apache.ofbiz.base.util.UtilHttp;
+import org.apache.ofbiz.base.util.UtilMisc;
+import org.apache.ofbiz.base.util.UtilValidate;
+import org.apache.ofbiz.base.util.collections.MapStack;
import org.apache.ofbiz.content.data.DataResourceWorker;
import org.apache.ofbiz.entity.Delegator;
import org.apache.ofbiz.entity.GenericValue;
import org.apache.ofbiz.entity.util.EntityQuery;
+import org.apache.ofbiz.security.Security;
import org.apache.ofbiz.service.GenericServiceException;
import org.apache.ofbiz.service.LocalDispatcher;
import org.apache.ofbiz.service.ServiceUtil;
+import org.apache.ofbiz.webapp.view.ApacheFopWorker;
+import org.apache.ofbiz.widget.renderer.ScreenRenderer;
+import org.apache.ofbiz.widget.renderer.ScreenStringRenderer;
+import org.apache.ofbiz.widget.renderer.VisualTheme;
+import org.apache.ofbiz.widget.renderer.fo.FoFormRenderer;
+import org.apache.ofbiz.widget.renderer.macro.MacroScreenRenderer;
+import org.apache.pdfbox.io.RandomAccessReadBuffer;
+import org.apache.pdfbox.multipdf.PDFMergerUtility;
+import org.xml.sax.SAXException;
+
+import freemarker.template.TemplateException;
/**
* Order Events
@@ -49,6 +73,62 @@ import org.apache.ofbiz.service.ServiceUtil;
public class OrderEvents {
private static final String MODULE = OrderEvents.class.getName();
+ private static final String ORDER_PDF_SCREEN =
"component://order/widget/ordermgr/OrderPrintScreens.xml#OrderPDF";
+
+ /**
+ * Streams one combined PDF for all selected orders to the browser, used
by the
+ * Find Orders "View PDF" mass action.
+ */
+ public static String viewOrdersPdf(HttpServletRequest request,
HttpServletResponse response) {
+ String[] orderIds = request.getParameterValues("orderIdList");
+ Delegator delegator = (Delegator) request.getAttribute("delegator");
+ LocalDispatcher dispatcher = (LocalDispatcher)
request.getAttribute("dispatcher");
+ Security security = (Security) request.getAttribute("security");
+ GenericValue userLogin = (GenericValue)
request.getSession().getAttribute("userLogin");
+ Locale locale = UtilHttp.getLocale(request);
+ VisualTheme visualTheme = UtilHttp.getVisualTheme(request);
+
+ try {
+ ScreenStringRenderer foScreenRenderer = new
MacroScreenRenderer(visualTheme.getModelTheme().getType("screenfop"),
+
visualTheme.getModelTheme().getScreenRendererLocation("screenfop"));
+ PDFMergerUtility merger = new PDFMergerUtility();
+ int orderCount = 0;
+ for (String orderId : orderIds != null ? orderIds : new String[0])
{
+ if (UtilValidate.isEmpty(orderId)) {
+ continue;
+ }
+ Writer writer = new StringWriter();
+ ScreenRenderer screens = new ScreenRenderer(writer,
MapStack.create(), foScreenRenderer);
+ screens.populateBasicContext(UtilMisc.toMap("orderId",
(Object) orderId), delegator, dispatcher, security, locale, userLogin);
+ screens.getContext().put("formStringRenderer", new
FoFormRenderer());
+ screens.render(ORDER_PDF_SCREEN);
+
+ ByteArrayOutputStream orderPdf = new ByteArrayOutputStream();
+ Fop fop = ApacheFopWorker.createFopInstance(orderPdf,
MimeConstants.MIME_PDF);
+ ApacheFopWorker.transform(new StreamSource(new
StringReader(writer.toString())), null, fop);
+ merger.addSource(new
RandomAccessReadBuffer(orderPdf.toByteArray()));
+ orderCount++;
+ }
+ if (orderCount == 0) {
+ request.setAttribute("_ERROR_MESSAGE_", "No orders selected.");
+ return "error";
+ }
+ ByteArrayOutputStream mergedPdf = new ByteArrayOutputStream();
+ merger.setDestinationStream(mergedPdf);
+
merger.mergeDocuments(org.apache.pdfbox.io.IOUtils.createMemoryOnlyStreamCache());
+
+ response.setContentType("application/pdf");
+ response.setHeader("Content-Disposition", "inline;
filename=\"orders.pdf\"");
+ response.setContentLength(mergedPdf.size());
+ mergedPdf.writeTo(response.getOutputStream());
+ } catch (GeneralException | IOException | SAXException |
ParserConfigurationException | TemplateException e) {
+ String errMsg = "Error rendering orders PDF: " + e.toString();
+ Debug.logError(e, errMsg, MODULE);
+ request.setAttribute("_ERROR_MESSAGE_", errMsg);
+ return "error";
+ }
+ return "success";
+ }
public static String downloadDigitalProduct(HttpServletRequest request,
HttpServletResponse response) {
HttpSession session = request.getSession();
diff --git a/applications/order/template/order/FindOrders.ftl
b/applications/order/template/order/FindOrders.ftl
index 7380d190eb..86c5c13a18 100644
--- a/applications/order/template/order/FindOrders.ftl
+++ b/applications/order/template/order/FindOrders.ftl
@@ -48,6 +48,8 @@ function setServiceName(selection) {
}
function runAction() {
var form = document.massOrderChangeForm;
+ // the combined orders PDF opens in a new tab, all other actions submit as
usual
+ form.target = form.action.indexOf("orders.pdf") >= 0 ? '_blank' : '';
form.submit();
}
@@ -470,6 +472,7 @@ document.lookuporder.orderId.focus();
<option
value="<@ofbizUrl>massQuickShipOrders?hideFields=${hideFields}${ampersand}${paramList}</@ofbizUrl>">${uiLabelMap.OrderQuickShipEntireOrder}</option>
<option
value="<@ofbizUrl>massPrintOrders?hideFields=${hideFields}${ampersand}${paramList}</@ofbizUrl>">${uiLabelMap.CommonPrint}</option>
<option
value="<@ofbizUrl>massCreateFileForOrders?hideFields=${hideFields}${ampersand}${paramList}</@ofbizUrl>">${uiLabelMap.ContentCreateFile}</option>
+ <option
value="<@ofbizUrl>orders.pdf</@ofbizUrl>">${uiLabelMap.OrderViewOrdersPdf}</option>
</select>
<#if printers?has_content>
<select name="printerName">
diff --git a/applications/order/webapp/ordermgr/WEB-INF/controller.xml
b/applications/order/webapp/ordermgr/WEB-INF/controller.xml
index 71bb387e82..1a25f2bb09 100644
--- a/applications/order/webapp/ordermgr/WEB-INF/controller.xml
+++ b/applications/order/webapp/ordermgr/WEB-INF/controller.xml
@@ -158,6 +158,12 @@ under the License.
<response name="success" type="request-redirect" value="findorders"/>
<response name="error" type="view" value="findorders"/>
</request-map>
+ <request-map uri="orders.pdf">
+ <security https="true" auth="true"/>
+ <event type="java" path="org.apache.ofbiz.order.order.OrderEvents"
invoke="viewOrdersPdf"/>
+ <response name="success" type="none"/>
+ <response name="error" type="view" value="findorders"/>
+ </request-map>
<!-- Delivery Info Requests, intended for sales orders but can be used for
purchase orders as well -->
<request-map uri="OrderDeliveryScheduleInfo">