Keep sales PDF item rows from splitting across a page break - #41061
Open
TuVanDev wants to merge 1 commit into
Open
Keep sales PDF item rows from splitting across a page break#41061TuVanDev wants to merge 1 commit into
TuVanDev wants to merge 1 commit into
Conversation
Removes the hardcoded 'shift' => 5 from the invoice, shipment and bundle item renderers so drawLineBlocks() measures the real block height, and stops the resulting page break from firing for a block that cannot fit on an empty page. Extends ACP2E-4630, which removed the hardcoded shift from the credit memo renderer only.
|
Hi @TuVanDev. Thank you for your contribution!
Allowed build names are:
You can find more information about the builds here For more details, review the Code Contributions documentation. |
5 tasks
Contributor
|
@magento create issue |
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description (*)
AbstractPdf::drawLineBlocks()has a block-level page-break check that is meant to move a whole item block to the next page when it no longer fits in the space left on the current one:shiftis documented on the method as "full line height (optional)", and when it is absentdrawLineBlocks()computes it from the block's own lines. Every core item renderer, however, passes a hardcoded'shift' => 5:Magento\Sales\Model\Order\Pdf\Items\Invoice\DefaultInvoiceMagento\Sales\Model\Order\Pdf\Items\Shipment\DefaultShipmentMagento\Bundle\Model\Sales\Order\Pdf\Items\InvoiceMagento\Bundle\Model\Sales\Order\Pdf\Items\ShipmentMagento\Bundle\Model\Sales\Order\Pdf\Items\CreditmemoWith
shift = 5the check is effectively dead: it only fires in the last 20pt of a page. An item block that does not fit in the remaining space is therefore started anyway and broken mid-block bycorrectText(), so a single item row is split across the page boundary. The product-name and option lines end up on one page while that same item's SKU, qty, price, tax and subtotal columns are drawn on the next one, where the numeric columns then line up against the wrong name fragment.Magento\Sales\Model\Order\Pdf\Items\Creditmemo\DefaultCreditmemono longer has the hardcoded value: it was removed as part of ACP2E-4630 (commit 545981c), which fixed the related overlapping-text defect by returning the new page out ofcorrectText()/correctLines(). This pull request finishes that work for the remaining five renderers.Removing
'shift' => 5on its own is not enough, because a block taller than one usable page then makes the check true even at the top of a fresh page:newPage()starts drawing at y=800 and the guard is< 15, so a block over ~785pt (less the table-header row) can never satisfy it. The break fires, the page that was just created is left with nothing but its table header, and the block overflows across the boundary anyway. Two additions prevent that:fitsOnEmptyPage()suppresses the break when the block cannot fit on an empty page. Breaking gains nothing there, it only leaves the rest of the current page empty.createPage()records the Y coordinate each new page starts drawing at, sofitsOnEmptyPage()compares against the real top of the current page (a table header lowers it) rather than an assumed one. For a page created elsewhere, such as the first page of each document built ingetPdf(), only the un-lowered coordinatenewPage()sets is known, and that is used instead.Together these make an empty page structurally impossible: on a page that has nothing drawn on it yet
$this->yequals that page's recorded top, so$this->y - $shift < 15and$shift <= $pageTop - 15are exact negations of each other and the break cannot fire.That also removes a latent empty-page case in the credit memo renderer, which has had the computed
shiftsince ACP2E-4630 but no such guard: an item whose option block is taller than a page currently gets pushed to a fresh page, leaving the credit memo's first page empty below its table header, and still overflows. Measured locally at 3 pages before this change and 2 after.The two literals the check depends on (
800fromnewPage()and15) are now named constants, since the new guard has to agree with both.Related Pull Requests
Extends ACP2E-4630 (commit 545981c), which fixed the overlapping-text half of this code path and removed the hardcoded
shiftfrom the credit memo renderer only.Fixed Issues (if relevant)
None linked. Found while investigating multi-page invoice PDFs on 2.4.7-p10.
Manual testing scenarios (*)
Verified on 2.4.7-p10 with the ACP2E-4630 change applied, over real invoices, packing slips, credit memos, order prints and a 5-invoice mass action, plus synthetic option blocks sized just under and just over one page:
The remaining split on a block taller than a page is unavoidable: it cannot fit anywhere, so it is drawn from where it stands instead of costing an extra page. Single-page documents draw exactly the same text at exactly the same coordinates as before. Page counts rise on documents whose items were previously being cut in half, which is what the check is for: the extra pages buy back the item rows that were being broken.
Magento\Sales\Test\Unit\Model\Order\Pdf\AbstractTest::testDrawLineBlocksBreaksPageOnlyForABlockThatFitscovers both halves of the new guard. It fails on 2.4-develop as it stands today (Zend_Pdf::newPage(...) was not expected to be called) and passes with this change.Questions or comments
PAGE_TOP_Yis kept private and used only insideAbstractPdf. The three concrete PDF models (Invoice,Shipment,Creditmemo) overridenewPage()and set$this->y = 800themselves; making the constant protected and using it there too would be a reasonable follow-up, but it is outside the scope of this fix.Contribution checklist (*)
Resolved issues: