p4-hotfixes #10
405
pdf/template.js
405
pdf/template.js
@@ -1,281 +1,274 @@
|
||||
/**
|
||||
* Builds the full HTML string for a CPAS violation PDF document.
|
||||
* Matches the styling of the original HTML violation form.
|
||||
*/
|
||||
/** PDF template with MPM logo from /static/mpm-logo.png */
|
||||
|
||||
const TIERS = [
|
||||
{ min: 0, max: 4, label: 'Tier 0-1 — Elite Standing', color: '#28a745' },
|
||||
{ min: 5, max: 9, label: 'Tier 1 — Realignment', color: '#856404' },
|
||||
{ min: 10, max: 14, label: 'Tier 2 — Administrative Lockdown', color: '#d9534f' },
|
||||
{ min: 15, max: 19, label: 'Tier 3 — Verification', color: '#d9534f' },
|
||||
{ min: 20, max: 24, label: 'Tier 4 — Risk Mitigation', color: '#c0392b' },
|
||||
{ min: 25, max: 29, label: 'Tier 5 — Final Decision', color: '#c0392b' },
|
||||
{ min: 30, max: 999,label: 'Tier 6 — Separation', color: '#721c24' },
|
||||
{ min: 0, max: 4, label: 'Tier 0-1 — Elite Standing', color: '#28a745' },
|
||||
{ min: 5, max: 9, label: 'Tier 1 — Realignment', color: '#856404' },
|
||||
{ min: 10, max: 14, label: 'Tier 2 — Administrative Lockdown', color: '#d9534f' },
|
||||
{ min: 15, max: 19, label: 'Tier 3 — Verification', color: '#d9534f' },
|
||||
{ min: 20, max: 24, label: 'Tier 4 — Risk Mitigation', color: '#c0392b' },
|
||||
{ min: 25, max: 29, label: 'Tier 5 — Final Decision', color: '#c0392b' },
|
||||
{ min: 30, max: 999,label: 'Tier 6 — Separation', color: '#721c24' },
|
||||
];
|
||||
|
||||
function getTier(points) {
|
||||
return TIERS.find(t => points >= t.min && points <= t.max) || TIERS[0];
|
||||
return TIERS.find(t => points >= t.min && points <= t.max) || TIERS[0];
|
||||
}
|
||||
|
||||
function formatDate(d) {
|
||||
if (!d) return '—';
|
||||
const dt = new Date(d + 'T12:00:00');
|
||||
return dt.toLocaleDateString('en-US', {
|
||||
weekday: 'long', year: 'numeric', month: 'long', day: 'numeric',
|
||||
timeZone: 'America/Chicago'
|
||||
});
|
||||
if (!d) return '—';
|
||||
const dt = new Date(d + 'T12:00:00');
|
||||
return dt.toLocaleDateString('en-US', {
|
||||
weekday: 'long', year: 'numeric', month: 'long', day: 'numeric',
|
||||
timeZone: 'America/Chicago'
|
||||
});
|
||||
}
|
||||
|
||||
function formatDateTime(d, t) {
|
||||
const date = formatDate(d);
|
||||
return t ? `${date} at ${t}` : date;
|
||||
const date = formatDate(d);
|
||||
return t ? `${date} at ${t}` : date;
|
||||
}
|
||||
|
||||
function row(label, value) {
|
||||
return `
|
||||
<tr>
|
||||
<td style="font-weight:600; color:#555; width:200px; padding:8px 12px; border-bottom:1px solid #eee; white-space:nowrap;">${label}</td>
|
||||
<td style="padding:8px 12px; border-bottom:1px solid #eee; color:#222;">${value || '—'}</td>
|
||||
</tr>`;
|
||||
return `
|
||||
<tr>
|
||||
<td style="font-weight:600; color:#555; width:200px; padding:8px 12px; border-bottom:1px solid #eee; white-space:nowrap;">${label}</td>
|
||||
<td style="padding:8px 12px; border-bottom:1px solid #eee; color:#222;">${value || '—'}</td>
|
||||
</tr>`;
|
||||
}
|
||||
|
||||
function buildHtml(v, score) {
|
||||
const activePts = score.active_points || 0;
|
||||
const tier = getTier(activePts);
|
||||
const newTotal = activePts + v.points;
|
||||
const newTier = getTier(newTotal);
|
||||
const tierChange = tier.label !== newTier.label;
|
||||
const activePts = score.active_points || 0;
|
||||
const tier = getTier(activePts);
|
||||
const newTotal = activePts + v.points;
|
||||
const newTier = getTier(newTotal);
|
||||
const tierChange = tier.label !== newTier.label;
|
||||
|
||||
const generatedAt = new Date().toLocaleString('en-US', {
|
||||
timeZone: 'America/Chicago',
|
||||
dateStyle: 'full', timeStyle: 'short'
|
||||
});
|
||||
const generatedAt = new Date().toLocaleString('en-US', {
|
||||
timeZone: 'America/Chicago',
|
||||
dateStyle: 'full', timeStyle: 'short'
|
||||
});
|
||||
|
||||
return `<!DOCTYPE html>
|
||||
return `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body { font-family: 'Segoe UI', Arial, sans-serif; font-size: 13px; color: #222; background: #fff; }
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body { font-family: 'Segoe UI', Arial, sans-serif; font-size: 13px; color: #222; background: #fff; }
|
||||
|
||||
.header { background: linear-gradient(135deg, #2c3e50, #34495e); color: white; padding: 28px 32px; }
|
||||
.header h1 { font-size: 22px; letter-spacing: 0.5px; }
|
||||
.header p { font-size: 12px; opacity: 0.8; margin-top: 4px; }
|
||||
.header {
|
||||
background: linear-gradient(135deg, #000000, #111217);
|
||||
color: white;
|
||||
padding: 22px 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.header-left { display: flex; align-items: center; }
|
||||
.logo {
|
||||
height: 28px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
.header h1 { font-size: 20px; letter-spacing: 0.5px; }
|
||||
.header p { font-size: 11px; opacity: 0.85; margin-top: 3px; }
|
||||
|
||||
.doc-id { float: right; text-align: right; font-size: 11px; opacity: 0.75; }
|
||||
.doc-id { text-align: right; font-size: 11px; opacity: 0.8; }
|
||||
|
||||
.section { margin: 20px 0; }
|
||||
.section-title {
|
||||
font-size: 14px; font-weight: 700; color: white;
|
||||
background: #34495e; padding: 8px 14px;
|
||||
border-radius: 4px 4px 0 0; margin-bottom: 0;
|
||||
}
|
||||
table { width: 100%; border-collapse: collapse; border: 1px solid #ddd; border-top: none; }
|
||||
.section { margin: 20px 0; }
|
||||
.section-title {
|
||||
font-size: 14px; font-weight: 700; color: white;
|
||||
background: #000000; padding: 8px 14px;
|
||||
border-radius: 4px 4px 0 0; margin-bottom: 0;
|
||||
}
|
||||
table { width: 100%; border-collapse: collapse; border: 1px solid #ddd; border-top: none; }
|
||||
|
||||
.score-box {
|
||||
display: flex; gap: 20px; flex-wrap: wrap;
|
||||
background: #f8f9fa; border: 1px solid #ddd;
|
||||
border-radius: 6px; padding: 16px 20px; margin: 20px 0;
|
||||
}
|
||||
.score-cell { flex: 1; min-width: 120px; text-align: center; }
|
||||
.score-num { font-size: 28px; font-weight: 800; }
|
||||
.score-lbl { font-size: 11px; color: #666; margin-top: 2px; }
|
||||
.score-box {
|
||||
display: flex; gap: 20px; flex-wrap: wrap;
|
||||
background: #f8f9fa; border: 1px solid #ddd;
|
||||
border-radius: 6px; padding: 16px 20px; margin: 20px 0;
|
||||
}
|
||||
.score-cell { flex: 1; min-width: 120px; text-align: center; }
|
||||
.score-num { font-size: 28px; font-weight: 800; }
|
||||
.score-lbl { font-size: 11px; color: #666; margin-top: 2px; }
|
||||
|
||||
.tier-badge {
|
||||
display: inline-block; padding: 5px 14px;
|
||||
border-radius: 14px; font-size: 12px; font-weight: 700;
|
||||
border: 2px solid currentColor;
|
||||
}
|
||||
.tier-change {
|
||||
background: #fff3cd; border: 2px solid #ffc107;
|
||||
border-radius: 6px; padding: 12px 16px; margin: 16px 0;
|
||||
font-size: 12px; color: #856404;
|
||||
}
|
||||
.tier-badge {
|
||||
display: inline-block; padding: 5px 14px;
|
||||
border-radius: 14px; font-size: 12px; font-weight: 700;
|
||||
border: 2px solid currentColor;
|
||||
}
|
||||
.tier-change {
|
||||
background: #fff3cd; border: 2px solid #ffc107;
|
||||
border-radius: 6px; padding: 12px 16px; margin: 16px 0;
|
||||
font-size: 12px; color: #856404;
|
||||
}
|
||||
|
||||
.points-display {
|
||||
background: #fff3cd; border: 2px solid #ffc107;
|
||||
border-radius: 6px; padding: 16px; margin: 16px 0; text-align: center;
|
||||
}
|
||||
.points-display .pts { font-size: 36px; font-weight: 800; color: #667eea; }
|
||||
.points-display .lbl { font-size: 12px; color: #666; }
|
||||
.points-display {
|
||||
background: #fff3cd; border: 2px solid #ffc107;
|
||||
border-radius: 6px; padding: 16px; margin: 16px 0; text-align: center;
|
||||
}
|
||||
.points-display .pts { font-size: 36px; font-weight: 800; color: #d4af37; }
|
||||
.points-display .lbl { font-size: 12px; color: #666; }
|
||||
|
||||
.sig-section { margin-top: 40px; page-break-inside: avoid; }
|
||||
.sig-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; margin-top: 24px; }
|
||||
.sig-block { border-top: 1.5px solid #333; padding-top: 8px; min-height: 60px; }
|
||||
.sig-label { font-size: 11px; color: #555; font-weight: 600; }
|
||||
.sig-date-block { border-top: 1.5px solid #333; padding-top: 8px; min-height: 50px; margin-top: 32px; }
|
||||
.sig-section { margin-top: 40px; page-break-inside: avoid; }
|
||||
.sig-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; margin-top: 24px; }
|
||||
.sig-block { border-top: 1.5px solid #333; padding-top: 8px; min-height: 60px; }
|
||||
.sig-label { font-size: 11px; color: #555; font-weight: 600; }
|
||||
.sig-date-block { border-top: 1.5px solid #333; padding-top: 8px; min-height: 50px; margin-top: 32px; }
|
||||
|
||||
.footer-bar {
|
||||
margin-top: 40px; padding: 10px 0;
|
||||
border-top: 2px solid #2c3e50;
|
||||
font-size: 10px; color: #888; text-align: center;
|
||||
}
|
||||
.confidential {
|
||||
background: #f8d7da; border: 1px solid #f5c6cb;
|
||||
border-radius: 4px; padding: 6px 12px;
|
||||
font-size: 11px; color: #721c24; font-weight: 600;
|
||||
text-align: center; margin-bottom: 16px;
|
||||
}
|
||||
.notice {
|
||||
background: #e7f3ff; border-left: 4px solid #2196F3;
|
||||
padding: 10px 14px; margin: 16px 0; font-size: 12px;
|
||||
}
|
||||
.policy-context {
|
||||
background: #f8f9fa; border-left: 3px solid #667eea;
|
||||
padding: 12px 16px; margin: 12px 0; font-size: 12px; color: #444;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.footer-bar {
|
||||
margin-top: 40px; padding: 10px 0;
|
||||
border-top: 2px solid #000000;
|
||||
font-size: 10px; color: #888; text-align: center;
|
||||
}
|
||||
.confidential {
|
||||
background: #f8d7da; border: 1px solid #f5c6cb;
|
||||
border-radius: 4px; padding: 6px 12px;
|
||||
font-size: 11px; color: #721c24; font-weight: 600;
|
||||
text-align: center; margin-bottom: 16px;
|
||||
}
|
||||
.notice {
|
||||
background: #e7f3ff; border-left: 4px solid #2196F3;
|
||||
padding: 10px 14px; margin: 16px 0; font-size: 12px;
|
||||
}
|
||||
.policy-context {
|
||||
background: #f8f9fa; border-left: 3px solid #667eea;
|
||||
padding: 12px 16px; margin: 12px 0; font-size: 12px; color: #444;
|
||||
border-radius: 4px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Header -->
|
||||
<div class="header">
|
||||
<div class="doc-id">
|
||||
Document ID: CPAS-${v.id.toString().padStart(5,'0')}<br />
|
||||
Generated: ${generatedAt}
|
||||
<div class="header-left">
|
||||
<img src="/static/mpm-logo.png" class="logo" />
|
||||
<div>
|
||||
<h1>CPAS Individual Violation Record</h1>
|
||||
<p>Message Point Media — Comprehensive Professional Accountability System</p>
|
||||
</div>
|
||||
<h1>CPAS Individual Violation Record</h1>
|
||||
<p>Message Point Media — Confidential HR Document</p>
|
||||
</div>
|
||||
<div class="doc-id">
|
||||
Document ID: CPAS-${v.id.toString().padStart(5,'0')}<br />
|
||||
Generated: ${generatedAt}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="padding: 0 4px;">
|
||||
|
||||
<div class="confidential" style="margin-top:16px;">
|
||||
⚠ CONFIDENTIAL — For authorized HR and management use only
|
||||
⚠ CONFIDENTIAL — For authorized HR and management use only
|
||||
</div>
|
||||
|
||||
<!-- Employee Information -->
|
||||
<div class="section">
|
||||
<div class="section-title">Employee Information</div>
|
||||
<table>
|
||||
${row('Employee Name', `<strong>${v.employee_name}</strong>`)}
|
||||
${row('Department', v.department)}
|
||||
${row('Supervisor', v.supervisor)}
|
||||
${row('Witness / Documenting Officer', v.witness_name)}
|
||||
</table>
|
||||
<div class="section-title">Employee Information</div>
|
||||
<table>
|
||||
${row('Employee Name', `<strong>${v.employee_name}</strong>`)}
|
||||
${row('Department', v.department)}
|
||||
${row('Supervisor', v.supervisor)}
|
||||
${row('Witness / Documenting Officer', v.witness_name)}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Violation Details -->
|
||||
<div class="section">
|
||||
<div class="section-title">Violation Details</div>
|
||||
<table>
|
||||
${row('Violation Type', `<strong>${v.violation_name}</strong>`)}
|
||||
${row('Category', v.category)}
|
||||
${row('Policy Reference', 'Chapter 4, Section 5 — Comprehensive Professional Accountability System (CPAS)')}
|
||||
${row('Incident Date / Time', formatDateTime(v.incident_date, v.incident_time))}
|
||||
${v.location ? row('Location / Context', v.location) : ''}
|
||||
${row('Submitted By', v.submitted_by || 'System')}
|
||||
</table>
|
||||
|
||||
${v.details ? `
|
||||
<div class="section-title">Violation Details</div>
|
||||
<table>
|
||||
${row('Violation Type', `<strong>${v.violation_name}</strong>`)}
|
||||
${row('Category', v.category)}
|
||||
${row('Policy Reference', 'Chapter 4, Section 5 — Comprehensive Professional Accountability System (CPAS)')}
|
||||
${row('Incident Date / Time', formatDateTime(v.incident_date, v.incident_time))}
|
||||
${v.location ? row('Location / Context', v.location) : ''}
|
||||
${row('Submitted By', v.submitted_by || 'System')}
|
||||
</table>
|
||||
${v.details ? `
|
||||
<div class="policy-context">
|
||||
<strong>Incident Details:</strong><br />
|
||||
${v.details}
|
||||
<strong>Incident Details:</strong><br />
|
||||
${v.details}
|
||||
</div>` : ''}
|
||||
</div>
|
||||
|
||||
<!-- CPAS Point Assessment -->
|
||||
<div class="section">
|
||||
<div class="section-title">CPAS Point Assessment</div>
|
||||
|
||||
<div class="points-display">
|
||||
<div class="pts">${v.points}</div>
|
||||
<div class="lbl">Points Assessed — This Violation</div>
|
||||
<div class="section-title">CPAS Point Assessment</div>
|
||||
<div class="points-display">
|
||||
<div class="pts">${v.points}</div>
|
||||
<div class="lbl">Points Assessed — This Violation</div>
|
||||
</div>
|
||||
<div class="score-box">
|
||||
<div class="score-cell">
|
||||
<div class="score-num" style="color:${tier.color};">${activePts}</div>
|
||||
<div class="score-lbl">Active Points (Prior)</div>
|
||||
<div style="margin-top:6px;">
|
||||
<span class="tier-badge" style="color:${tier.color};">${tier.label}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="score-box">
|
||||
<div class="score-cell">
|
||||
<div class="score-num" style="color:${tier.color};">${activePts}</div>
|
||||
<div class="score-lbl">Active Points (Prior)</div>
|
||||
<div style="margin-top:6px;">
|
||||
<span class="tier-badge" style="color:${tier.color};">${tier.label}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="score-cell" style="font-size:28px; font-weight:300; color:#ccc; line-height:1.8;">+</div>
|
||||
<div class="score-cell">
|
||||
<div class="score-num" style="color:#667eea;">${v.points}</div>
|
||||
<div class="score-lbl">Points — This Violation</div>
|
||||
</div>
|
||||
<div class="score-cell" style="font-size:28px; font-weight:300; color:#ccc; line-height:1.8;">=</div>
|
||||
<div class="score-cell">
|
||||
<div class="score-num" style="color:${newTier.color};">${newTotal}</div>
|
||||
<div class="score-lbl">New Active Total</div>
|
||||
<div style="margin-top:6px;">
|
||||
<span class="tier-badge" style="color:${newTier.color};">${newTier.label}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="score-cell" style="font-size:28px; font-weight:300; color:#ccc; line-height:1.8;">+</div>
|
||||
<div class="score-cell">
|
||||
<div class="score-num" style="color:#d4af37;">${v.points}</div>
|
||||
<div class="score-lbl">Points — This Violation</div>
|
||||
</div>
|
||||
|
||||
${tierChange ? `
|
||||
<div class="score-cell" style="font-size:28px; font-weight:300; color:#ccc; line-height:1.8;">=</div>
|
||||
<div class="score-cell">
|
||||
<div class="score-num" style="color:${newTier.color};">${newTotal}</div>
|
||||
<div class="score-lbl">New Active Total</div>
|
||||
<div style="margin-top:6px;">
|
||||
<span class="tier-badge" style="color:${newTier.color};">${newTier.label}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
${tierChange ? `
|
||||
<div class="tier-change">
|
||||
<strong>⚠ Tier Escalation:</strong> This violation advances the employee from
|
||||
<strong>${tier.label}</strong> to <strong>${newTier.label}</strong>.
|
||||
Review associated tier consequences per the Employee Handbook.
|
||||
<strong>⚠ Tier Escalation:</strong> This violation advances the employee from
|
||||
<strong>${tier.label}</strong> to <strong>${newTier.label}</strong>.
|
||||
</div>` : ''}
|
||||
</div>
|
||||
|
||||
<!-- CPAS Tier Reference -->
|
||||
<div class="section">
|
||||
<div class="section-title">CPAS Tier Reference</div>
|
||||
<table>
|
||||
<tr style="background:#f8f9fa;">
|
||||
<th style="padding:7px 12px; text-align:left; font-size:12px;">Points</th>
|
||||
<th style="padding:7px 12px; text-align:left; font-size:12px;">Tier</th>
|
||||
</tr>
|
||||
${TIERS.map(t => `
|
||||
<tr style="${newTotal >= t.min && newTotal <= t.max ? 'background:#fff3cd; font-weight:700;' : ''}">
|
||||
<td style="padding:6px 12px; border-bottom:1px solid #eee; font-size:12px;">${t.min === 30 ? '30+' : t.min + '–' + t.max}</td>
|
||||
<td style="padding:6px 12px; border-bottom:1px solid #eee; font-size:12px; color:${t.color};">${t.label}</td>
|
||||
</tr>`).join('')}
|
||||
</table>
|
||||
<div class="section-title">CPAS Tier Reference</div>
|
||||
<table>
|
||||
<tr style="background:#f8f9fa;">
|
||||
<th style="padding:7px 12px; text-align:left; font-size:12px;">Points</th>
|
||||
<th style="padding:7px 12px; text-align:left; font-size:12px;">Tier</th>
|
||||
</tr>
|
||||
${TIERS.map(t => `
|
||||
<tr style="${newTotal >= t.min && newTotal <= t.max ? 'background:#fff3cd; font-weight:700;' : ''}">
|
||||
<td style="padding:6px 12px; border-bottom:1px solid #eee; font-size:12px;">${t.min === 30 ? '30+' : t.min + '–' + t.max}</td>
|
||||
<td style="padding:6px 12px; border-bottom:1px solid #eee; font-size:12px; color:${t.color};">${t.label}</td>
|
||||
</tr>`).join('')}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Notice -->
|
||||
<div class="notice">
|
||||
<strong>Employee Notice:</strong> CPAS points remain active for a rolling 90-day period from the date of each incident.
|
||||
Accumulation of points may result in tier escalation and associated consequences as outlined in the Employee Handbook,
|
||||
Chapter 4, Section 5. This document should be reviewed with the employee and signed by all parties.
|
||||
<strong>Employee Notice:</strong> CPAS points remain active for a rolling 90-day period from the date of each incident.
|
||||
Accumulation of points may result in tier escalation and associated consequences as outlined in the Employee Handbook.
|
||||
</div>
|
||||
|
||||
<!-- Signatures — EXPANDED VERTICAL SPACING -->
|
||||
<div class="sig-section">
|
||||
<div class="section-title" style="background:#34495e; color:white; padding:8px 14px; border-radius:4px; font-size:14px; font-weight:700;">Acknowledgement & Signatures</div>
|
||||
<div style="padding: 16px 0;">
|
||||
<p style="font-size:12px; color:#555; margin-bottom:28px; line-height:1.6;">
|
||||
By signing below, the employee acknowledges receipt of this violation record.
|
||||
Acknowledgement does not imply agreement. The employee may submit a written
|
||||
response within 5 business days.
|
||||
</p>
|
||||
<div class="sig-grid">
|
||||
<div>
|
||||
<div class="sig-block">
|
||||
<div class="sig-label">Employee Signature</div>
|
||||
</div>
|
||||
<div class="sig-date-block">
|
||||
<div class="sig-label">Date</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="sig-block">
|
||||
<div class="sig-label">Supervisor / Documenting Officer Signature</div>
|
||||
</div>
|
||||
<div class="sig-date-block">
|
||||
<div class="sig-label">Date</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section-title" style="background:#000000;">Acknowledgement & Signatures</div>
|
||||
<div style="padding: 16px 0;">
|
||||
<p style="font-size:12px; color:#555; margin-bottom:28px; line-height:1.6;">
|
||||
By signing below, the employee acknowledges receipt of this violation record.
|
||||
Acknowledgement does not imply agreement. The employee may submit a written
|
||||
response within 5 business days.
|
||||
</p>
|
||||
<div class="sig-grid">
|
||||
<div>
|
||||
<div class="sig-block"><div class="sig-label">Employee Signature</div></div>
|
||||
<div class="sig-date-block"><div class="sig-label">Date</div></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="sig-block"><div class="sig-label">Supervisor / Documenting Officer Signature</div></div>
|
||||
<div class="sig-date-block"><div class="sig-label">Date</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer-bar">
|
||||
CPAS Violation Record — Document ID: CPAS-${v.id.toString().padStart(5,'0')} |
|
||||
${v.employee_name} | Incident: ${v.incident_date} |
|
||||
Message Point Media Internal Use Only
|
||||
CPAS Violation Record — Document ID: CPAS-${v.id.toString().padStart(5,'0')} |
|
||||
${v.employee_name} | Incident: ${v.incident_date} |
|
||||
Message Point Media Internal Use Only
|
||||
</div>
|
||||
|
||||
</div><!-- /padding -->
|
||||
</div>
|
||||
</body>
|
||||
</html>`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user