From 950628b540ed0d1ea615a873e83d598faf3fd478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Houssin?= Date: Wed, 19 Aug 2026 01:01:45 +0200 Subject: [PATCH] QUAL add hook printWebsitePageContent (#39576) * FIX avoid php warnings (#39556) * Fix help * Doc * FIX: Broken feature 'Generate Child Mo' (#39560) * Fix broken 'Generate Child Mo' * Fix phan * QUAL add hook printWebsitePageContent --------- Co-authored-by: Laurent Destailleur Co-authored-by: Francis Appels --- htdocs/core/lib/website2.lib.php | 12 ++++++++++++ htdocs/mrp/class/mo.class.php | 10 +++++++++- htdocs/mrp/mo_card.php | 4 ++++ scripts/invoices/rebuild_merge_pdf.php | 8 +++++++- 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/htdocs/core/lib/website2.lib.php b/htdocs/core/lib/website2.lib.php index 67de01dc874..582d4fb79f3 100644 --- a/htdocs/core/lib/website2.lib.php +++ b/htdocs/core/lib/website2.lib.php @@ -443,6 +443,18 @@ function dolSavePageContent($filetpl, Website $object, WebsitePage $objectpage, $tplcontent .= '$tmp = preg_replace("/__SEO_CANONICAL_LANG__/", (defined("__SEO_PAGE_LANG__") ? preg_replace(\'/\[_-\].*$/\', "", constant("__SEO_PAGE_LANG__")) : (empty($weblangs->shortlang) ? "'.$tmpshortlangcode.'" : $weblangs->shortlang)), $tmp);'."\n"; } + // Let modules rewrite the final page content (e.g. canonical/hreflang links, when a module + // implements its own URL rewriting scheme that core has no knowledge of). Runs on every + // request (not only at page compile time), so it applies no matter which code path last + // recompiled this page (website editor, inline AJAX edit, a module's own template reset...). + $tplcontent .= "// Let modules rewrite the final page content (hook)\n"; + $tplcontent .= 'global $hookmanager;'."\n"; + $tplcontent .= 'if (is_object($hookmanager)) {'."\n"; + $tplcontent .= ' $hookmanager->initHooks(array(\'websitepagecontent\'));'."\n"; + $tplcontent .= ' $parameters = array(\'tmp\' => &$tmp);'."\n"; + $tplcontent .= ' $hookmanager->executeHooks(\'printWebsitePageContent\', $parameters, $websitepage);'."\n"; + $tplcontent .= '}'."\n"; + $tplcontent .= "// Now output the generated page content\n"; $tplcontent .= 'dolWebsiteOutput($tmp, "html", '.((int) $objectpage->id).'); dolWebsiteIncrementCounter('.((int) $object->id).', "'.$objectpage->type_container.'", '.((int) $objectpage->id).');'."\n"; $tplcontent .= "// END PHP ?>\n"; diff --git a/htdocs/mrp/class/mo.class.php b/htdocs/mrp/class/mo.class.php index 60db6a5d20a..79a43226c6c 100644 --- a/htdocs/mrp/class/mo.class.php +++ b/htdocs/mrp/class/mo.class.php @@ -273,6 +273,14 @@ class Mo extends CommonObject */ public $tpl = array(); + /** + * @var int[] Ids of BOM lines (with a sub-BOM) that must not be flattened into their raw materials + * when generating the consume/produce lines, because the user asked to generate a child MO + * for them instead (see mo_card.php "Generate Child MO"). A single MoLine anchored on the + * sub-assembly product is created for these lines instead of recursing into the sub-BOM. + */ + public $noFlattenBomLineIds = array(); + /** * Constructor @@ -815,7 +823,7 @@ class Mo extends CommonObject $tmpproduct = new Product($this->db); $tmpproduct->fetch($line->fk_product); - if ($line->fk_bom_child > 0) { + if ($line->fk_bom_child > 0 && !in_array($line->id, $this->noFlattenBomLineIds)) { $bom = new BOM($this->db); $bom->fetch((int) $line->fk_bom_child); $error += $this->processBOM($user, $role, $bom, $quantity_line); diff --git a/htdocs/mrp/mo_card.php b/htdocs/mrp/mo_card.php index 3f1c5221884..76b012b242e 100644 --- a/htdocs/mrp/mo_card.php +++ b/htdocs/mrp/mo_card.php @@ -156,6 +156,10 @@ if (empty($reshook)) { // Create MO with Children if ($action == 'add' && empty($id) && !empty($TBomLineId) && $permissiontoadd) { $noback = 1; + // Sub-BOM lines the user checked "Generate Child MO" for must not be flattened into their + // raw materials on the parent MO: keep a single consume line anchored on the sub-assembly + // product instead, so it can be found below to create the child MO. + $object->noFlattenBomLineIds = array_map('intval', $TBomLineId); include DOL_DOCUMENT_ROOT.'/core/actions_addupdatedelete.inc.php'; $mo_parent = $object; diff --git a/scripts/invoices/rebuild_merge_pdf.php b/scripts/invoices/rebuild_merge_pdf.php index b5aba63b9ec..1f1f0be2da8 100755 --- a/scripts/invoices/rebuild_merge_pdf.php +++ b/scripts/invoices/rebuild_merge_pdf.php @@ -51,6 +51,8 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/invoice2.lib.php'; * @var DoliDB $db * @var HookManager $hookmanager * @var Translate $langs + * + * @var int $dolibarr_main_db_readonly */ // Load main language strings @@ -306,7 +308,11 @@ function rebuild_merge_pdf_usage() print "To exclude deposit invoices, use filter=nodeposit\n"; print "To exclude some thirdparties, use filter=excludethirdparties id1,id2...\n"; print "To limit to some thirdparties, use filter=onlythirdparties id1,id2...\n"; - print "To regenerate existing PDF, use regenerate=templatename or regeneratenomerge=templatename\n"; + print "\n"; + print "To regenerate existing PDF before merge, use regenerate=templatename\n"; + print "To regenerate existing PDF with no merge (regenerate only), use regeneratenomerge=templatename\n"; + print "To merge by reusing existing PDF (generation only for non already existing PDF), use regenerate=no or nothing\n"; + print "\n"; print "To generate documents in a given language, use lang=xx_XX\n"; print "To set prefix of generated file name, use prefix=myfileprefix\n"; print "\n";