mirror of
https://github.com/kbenestad/reimburse.git
synced 2026-06-18 08:04:31 +00:00
Polish BPSOS PDF line layout: cleaner, less busy
- Header divider (under Staff/Period/Currency) now matches grand-total rule thickness (3pt instead of 1.5pt) - ITEM / PROJECT / TRAVEL label rendered at body font size (sz) for stronger visual weight - Thin grey rule drawn above every vendor line (including first in an item); replaces the between-lines-only separator - Foreign currency amount moved to line 1, left of the bold base amount, in muted grey — removes it from line 3 - Line 3 right side now shows only the FX rate (e.g. THB 34.05000 per USD) since the amount is already on line 1 - Receipt line shows plain "See page N for receipt" with no prefix, or wraps the no-receipt explanation directly with no heading label - Vendor and description rendered as plain text (no box or background)
This commit is contained in:
parent
ed7ea2c4de
commit
b6497c4d0a
1 changed files with 24 additions and 25 deletions
|
|
@ -948,14 +948,14 @@ async function generatePDF() {
|
|||
y -= lh + 6;
|
||||
|
||||
// Divider
|
||||
pg.drawLine({start:{x:M.left,y}, end:{x:M.left+W,y}, thickness:1.5, color:accent});
|
||||
pg.drawLine({start:{x:M.left,y}, end:{x:M.left+W,y}, thickness:3, color:accent});
|
||||
y -= lh;
|
||||
|
||||
// Items
|
||||
state.items.forEach(item => {
|
||||
// Item header
|
||||
needSpace(lh * 6); // need room for at least header + one line
|
||||
pg.drawText('ITEM / PROJECT / TRAVEL', {x:M.left, y, size:szSm, font:fontBold, color:accent});
|
||||
pg.drawText('ITEM / PROJECT / TRAVEL', {x:M.left, y, size:sz, font:fontBold, color:accent});
|
||||
const subStr = `Subtotal: ${baseCur} ${fmtAmt(item._subtotal)}`;
|
||||
const subW = fontBold.widthOfTextAtSize(subStr, sz);
|
||||
pg.drawText(subStr, {x:M.left+W-subW, y, size:sz, font:fontBold, color:accent});
|
||||
|
|
@ -966,58 +966,57 @@ async function generatePDF() {
|
|||
// Lines
|
||||
item.lines.forEach((ln, li) => {
|
||||
needSpace(lh * 8);
|
||||
if (li > 0 && !justBroke) {
|
||||
y -= 4;
|
||||
pg.drawLine({start:{x:M.left,y}, end:{x:M.left+W,y}, thickness:0.3, color:lineCol});
|
||||
y -= 8;
|
||||
|
||||
// Thin grey rule above each vendor line
|
||||
if (!justBroke) {
|
||||
if (li > 0) y -= 6;
|
||||
pg.drawLine({start:{x:M.left, y:y+lh+1}, end:{x:M.left+W, y:y+lh+1}, thickness:0.3, color:lineCol});
|
||||
}
|
||||
|
||||
const boxW = W * 0.65; // width of vendor / description boxes
|
||||
const boxH = lh; // box height matches line height
|
||||
const boxFill = rgb(0.97, 0.97, 0.97);
|
||||
const boxW = W * 0.65; // text width for vendor / description
|
||||
|
||||
// Line 1: [Vendor box] LCC amount
|
||||
// Line 1: Vendor FXC amount LCC amount
|
||||
const baseAmt = (() => { const a=parseFloat(ln.amount)||0, r=parseFloat(ln.fxRate)||1; return r>0?a/r:0; })();
|
||||
const baseAmtStr = `${baseCur} ${fmtAmt(baseAmt)}`;
|
||||
const baseAmtW = fontBold.widthOfTextAtSize(baseAmtStr, sz);
|
||||
pg.drawRectangle({x:M.left, y:y-2, width:boxW, height:boxH, borderColor:lineCol, borderWidth:0.5, color:boxFill});
|
||||
pg.drawText(truncate(ln.vendor||'–', fontBody, sz, boxW-8), {x:M.left+4, y, size:sz, font:fontBody, color:black});
|
||||
pg.drawText(truncate(ln.vendor||'–', fontBody, sz, boxW-4), {x:M.left, y, size:sz, font:fontBody, color:black});
|
||||
if (ln.currency && ln.currency !== baseCur) {
|
||||
const fxAmtStr = `${ln.currency} ${fmtAmt(ln.amount)}`;
|
||||
const fxAmtW = fontBody.widthOfTextAtSize(fxAmtStr, szSm);
|
||||
pg.drawText(fxAmtStr, {x:M.left+W-baseAmtW-fxAmtW-6, y, size:szSm, font:fontBody, color:gray});
|
||||
}
|
||||
pg.drawText(baseAmtStr, {x:M.left+W-baseAmtW, y, size:sz, font:fontBold, color:black});
|
||||
y -= boxH + 4;
|
||||
y -= lh + 2;
|
||||
|
||||
// Line 2: [Description box] Date: YYYY-MM-DD
|
||||
// Line 2: Description Date: YYYY-MM-DD
|
||||
const dateInPeriod = isDateInPeriod(ln.date);
|
||||
const dateColor = dateInPeriod ? black : rgb(0.9, 0.33, 0);
|
||||
const dateStr = `Date: ${ln.date||'–'}${dateInPeriod ? '' : ' (!)'}`;
|
||||
const dateStrW = fontBody.widthOfTextAtSize(dateStr, szSm);
|
||||
pg.drawRectangle({x:M.left, y:y-2, width:boxW, height:boxH, borderColor:lineCol, borderWidth:0.5, color:boxFill});
|
||||
pg.drawText(truncate(ln.description||'–', fontBody, sz, boxW-8), {x:M.left+4, y, size:sz, font:fontBody, color:black});
|
||||
pg.drawText(truncate(ln.description||'–', fontBody, sz, boxW-4), {x:M.left, y, size:sz, font:fontBody, color:black});
|
||||
pg.drawText(dateStr, {x:M.left+W-dateStrW, y, size:szSm, font:fontBody, color:dateColor});
|
||||
y -= boxH + 4;
|
||||
y -= lh + 2;
|
||||
|
||||
// Line 3: Receipt: … (left, backfilled) FXC amount – FXC rate per LCC (right)
|
||||
// Line 3: Receipt ref (backfilled) or explanation FXC rate detail (right)
|
||||
if (ln.currency && ln.currency !== baseCur) {
|
||||
const fxDetail = `${ln.currency} ${fmtAmt(ln.amount)} – ${ln.currency} ${parseFloat(ln.fxRate||'0').toFixed(5)} per ${baseCur}`;
|
||||
const fxDetail = `${ln.currency} ${parseFloat(ln.fxRate||'0').toFixed(5)} per ${baseCur}`;
|
||||
const fxDetailW = fontBody.widthOfTextAtSize(fxDetail, szSm);
|
||||
pg.drawText(fxDetail, {x:M.left+W-fxDetailW, y, size:szSm, font:fontBody, color:gray});
|
||||
}
|
||||
if (ln.hasReceipt && ln.receipts.length > 0) {
|
||||
ln.receipts.forEach((r, ri) => {
|
||||
const key = `${ln.id}-${ri}`;
|
||||
receiptRefs.push({pageIdx: pages.length-1, x:M.left, y, key, prefix:'Receipt: '});
|
||||
receiptRefs.push({pageIdx: pages.length-1, x:M.left, y, key, prefix:''});
|
||||
y -= lh;
|
||||
});
|
||||
} else if (!ln.hasReceipt) {
|
||||
pg.drawText('Receipt: No receipt', {x:M.left, y, size:sz, font:fontBody, color:black});
|
||||
y -= lh;
|
||||
const explLines = wrapText(ln.noReceiptExplanation||'–', fontBody, szSm, boxW);
|
||||
const explLines = wrapText(ln.noReceiptExplanation||'–', fontBody, szSm, W * 0.6);
|
||||
explLines.forEach(line => {
|
||||
needSpace(lh);
|
||||
pg.drawText(` ${line}`, {x:M.left, y, size:szSm, font:fontBody, color:gray});
|
||||
pg.drawText(line, {x:M.left, y, size:szSm, font:fontBody, color:gray});
|
||||
y -= lh;
|
||||
});
|
||||
} else {
|
||||
pg.drawText('Receipt: –', {x:M.left, y, size:sz, font:fontBody, color:gray});
|
||||
y -= lh;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue