fix(reports): collapse sig-row to one bordered table — kill duplicate borders

User reported "multiple unwanted vertical lines in the boxes" on the
portrait BoL. Pixel analysis confirmed it: previous design had 3
separate `<div class="sig-box">` each with its own 1px border, with a
4-8px gap between adjacent boxes — visually those adjacent borders
read as a doubled / "duplicate" line between cells.

Fix: replace 3-box layout with a single `<table class="bordered
sig-table">` containing 3 td cells. With border-collapse: collapse,
adjacent cells share their border — so the row now shows 4 vertical
lines (1 outer left + 2 internal dividers + 1 outer right) instead
of 6 close-together border lines.

- Dropped `.sig-box` class entirely (no per-box border anymore)
- Added `.sig-table` + `.sig-cell` with explicit 1px borders so the
  layout works without depending on `.bordered` class inheritance
- Applied to both portrait + landscape variants
- Landscape sig-row was still using the OLD Bootstrap row+col-4
  layout (never got replaced earlier) — also migrated to the new
  table layout

Verified: page count unchanged (portrait 1, landscape 1), all
labels and content present, structure clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-04-19 08:14:07 -04:00
parent 8b20853ac7
commit cb9baa03ad
7 changed files with 113 additions and 37 deletions

View File

@@ -0,0 +1,25 @@
env = env # noqa
import re
rep = env.ref('fusion_plating_reports.action_report_fp_bol_portrait')
dlv = env['fusion.plating.delivery'].search([], order='id desc', limit=1)
html, _ = rep.with_context(force_report_rendering=True
)._render_qweb_html(rep.report_name, [dlv.id])
out = html.decode() if isinstance(html, bytes) else str(html)
# Pull the sig-table block + a bit before
m = re.search(r'(<div class="fp-keep-together".*?</div>)\s*</div>\s*</div>\s*</t>',
out, re.S)
if m:
print('=== fp-keep-together block ===')
print(m.group(1)[:3000])
else:
# Fallback — just find the sig-table
m2 = re.search(r'(<table class="sig-table".*?</table>)', out, re.S)
if m2:
print('=== sig-table block ===')
print(m2.group(1))
# Also dump the relevant CSS rules
print('\n=== relevant css ===')
for rule in re.findall(r'\.fp-report\s+\.(?:sig-|fp-keep)[^{]*\{[^}]*\}', out):
print(rule)

View File

@@ -0,0 +1,8 @@
env = env # noqa
rep = env.ref('fusion_plating_reports.action_report_fp_bol_portrait')
dlv = env['fusion.plating.delivery'].search([], order='id desc', limit=1)
pdf, _ = rep.with_context(force_report_rendering=True
)._render_qweb_pdf(rep.report_name, [dlv.id])
with open('/tmp/bol_portrait.pdf', 'wb') as f:
f.write(pdf)
print(f'wrote {len(pdf)/1024:.1f} KB')

View File

@@ -0,0 +1,33 @@
# Stress-test the BoL with progressively longer notes
env = env # noqa
import re
rep = env.ref('fusion_plating_reports.action_report_fp_bol_landscape')
dlv = env['fusion.plating.delivery'].search([], order='id desc', limit=1)
orig_notes = dlv.notes
print(f'baseline (current notes={len(orig_notes or "") } chars)')
scenarios = [
('empty notes', '', 1),
('one short line', '<p>Handle with care.</p>', 1),
('three lines', '<p>Line 1</p><p>Line 2</p><p>Line 3</p>', 1),
('ten lines', ''.join(f'<p>Special instruction line {i}: handle with care, fragile, do not stack.</p>' for i in range(10)), 1),
('paragraph block', '<p>' + ('Long instructions filling the cargo description box. ' * 30) + '</p>', 1),
('huge block', '<p>' + ('Very long instructions. ' * 80) + '</p>', 1),
]
print(f'\n{"scenario":<22} {"chars":<8} {"pages":<6} signature row intact?')
print('-' * 70)
for label, notes, _ in scenarios:
dlv.write({'notes': notes})
pdf, _e = rep.with_context(force_report_rendering=True
)._render_qweb_pdf(rep.report_name, [dlv.id])
n_pages = len(re.findall(rb'/Type\s*/Page[^s]', pdf))
# Save last for inspection
with open(f'/tmp/bol_stress_{label.replace(" ","_")}.pdf', 'wb') as f:
f.write(pdf)
# Quick "intact" heuristic: if it's >1 page and the size is small,
# likely overflowed. Real check is in pypdf locally.
print(f'{label:<22} {len(notes):<8} {n_pages:<6} (PDF saved)')
# Restore
dlv.write({'notes': orig_notes or False})
print('\noriginal notes restored')

View File

@@ -0,0 +1,22 @@
env = env # noqa
import re
rep = env.ref('fusion_plating_reports.action_report_fp_bol_portrait')
dlv = env['fusion.plating.delivery'].search([], order='id desc', limit=1)
html, _ = rep.with_context(force_report_rendering=True
)._render_qweb_html(rep.report_name, [dlv.id])
out = html.decode() if isinstance(html, bytes) else str(html)
# Extract the sig-table block + 200 chars before and after
m = re.search(r'(.{0,400})(<table class="bordered sig-table".*?</table>)(.{0,200})', out, re.S)
if m:
print('=== before ===')
print(m.group(1)[-300:])
print('=== sig-table ===')
print(m.group(2))
else:
print('NOT FOUND. Looking for any sig-table:')
for m in re.finditer(r'<table[^>]*sig[^>]*>', out):
print(' ', m.group(0))
# Also search for the labels
for label in ['Shipper (Signature', 'sig-cell', 'sig-table', 'sig-box']:
i = out.find(label)
print(f' {label!r}: pos={i}')