Rebuild the Classic template on the engine with A4/Letter and a template harness

Classic now renders through buildRenderModel, computeFrame, the template
and renderCore, with S.No and HSN/SAC columns, GST slots only through
checked Slot components, taxable value, reverse-charge line, cancelled tag,
continuation band and Page n of N. Letter absorbs its height deficit in
elastic gaps. A harness runs 15 fixtures on A4 and Letter plus an item
sweep and asserts zero audit errors, repeated headers, no split blocks,
rupee extraction and deterministic output. The legacy InvoiceDocument is
removed.
This commit is contained in:
2026-10-04 05:31:14 +05:30
parent 8d4f8e666b
commit a014a907e4
40 changed files with 2185 additions and 832 deletions
+38
View File
@@ -0,0 +1,38 @@
export interface LogoPlacementInput {
/** Width / height of the image (use the trimmed ink aspect once the logo pipeline provides it). */
aspect: number;
/** The largest box the logo may fill, pt. */
box: { w: number; h: number };
/** Width of the column the logo and the text beside it share. */
availableWidth: number;
/** Narrowest the text may get beside the logo before the logo moves above it. */
minTextWidth: number;
/** Space between logo and text when side by side. Default 14. */
gap?: number;
}
export interface LogoPlacement {
w: number;
h: number;
/** True when the logo goes above the text instead of beside it. */
stacked: boolean;
}
export const LOGO_GAP = 14;
/**
* Fits the logo inside `box` by its aspect (contain), then decides whether it still leaves the text
* `minTextWidth` beside it. Same maths as the Phase 0 planLogo.
*/
export function computeLogoPlacement({ aspect, box, availableWidth, minTextWidth, gap = LOGO_GAP }: LogoPlacementInput): LogoPlacement {
const a = Number.isFinite(aspect) && aspect > 0 ? aspect : box.w / box.h;
const h = Math.min(box.h, box.w / a);
const w = h * a;
return { w, h, stacked: availableWidth - w - gap < minTextWidth };
}
/*
* Seam for reference templates: slots.generated.ts (measured placeholder boxes, see
* scripts/logo/measure-placeholders.mjs) will supply a template's `logo.box` and may refine the fit.
* Until it exists, every template declares its box by hand in its TemplateDefinition.
*/