fmard/pdf-api
0
1<!DOCTYPE html>2<html lang="en">3<head>4 <meta charset="UTF-8">5 <title>Snagging List - {{ project_name | default("Green Valley Residence") }}</title>6 <style>7 * { margin: 0; padding: 0; box-sizing: border-box; }8 body {9 font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;10 color: #333;11 font-size: 14px;12 line-height: 1.6;13 padding: 40px;14 }15 .header {16 display: flex;17 justify-content: space-between;18 align-items: flex-start;19 margin-bottom: 30px;20 padding-bottom: 20px;21 border-bottom: 3px solid #4f46e5;22 }23 .company-info h1 {24 font-size: 24px;25 color: #4f46e5;26 margin-bottom: 5px;27 }28 .company-info p { color: #666; font-size: 13px; }29 .doc-meta { text-align: right; }30 .doc-meta h2 { font-size: 18px; color: #333; margin-bottom: 5px; }31 .doc-meta p { font-size: 13px; color: #666; }32 .info-grid {33 display: grid;34 grid-template-columns: repeat(2, 1fr);35 gap: 12px;36 margin-bottom: 25px;37 }38 .info-item {39 padding: 12px 15px;40 background-color: #f9fafb;41 border-radius: 6px;42 }43 .info-item .label {44 font-size: 11px;45 text-transform: uppercase;46 color: #999;47 letter-spacing: 0.5px;48 }49 .info-item .value { font-weight: 600; color: #333; }50 .section-title {51 font-size: 16px;52 color: #4f46e5;53 margin-bottom: 12px;54 margin-top: 25px;55 padding-bottom: 6px;56 border-bottom: 2px solid #e5e7eb;57 }58 .summary-bar {59 display: flex;60 gap: 20px;61 margin-bottom: 25px;62 }63 .summary-item {64 padding: 12px 20px;65 border-radius: 6px;66 text-align: center;67 flex: 1;68 }69 .summary-item .count { font-size: 24px; font-weight: bold; }70 .summary-item .desc { font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; }71 .summary-open { background: #fef2f2; color: #dc2626; }72 .summary-progress { background: #fffbeb; color: #d97706; }73 .summary-closed { background: #f0fdf4; color: #16a34a; }74 table {75 width: 100%;76 border-collapse: collapse;77 margin-bottom: 25px;78 font-size: 12px;79 }80 thead th {81 background-color: #4f46e5;82 color: white;83 padding: 10px 8px;84 text-align: left;85 font-size: 11px;86 text-transform: uppercase;87 letter-spacing: 0.5px;88 }89 tbody td {90 padding: 10px 8px;91 border-bottom: 1px solid #eee;92 }93 tbody tr:nth-child(even) { background-color: #f9fafb; }94 .severity-high {95 background: #fef2f2; color: #dc2626;96 padding: 2px 8px; border-radius: 3px; font-size: 11px; font-weight: bold;97 }98 .severity-medium {99 background: #fffbeb; color: #d97706;100 padding: 2px 8px; border-radius: 3px; font-size: 11px; font-weight: bold;101 }102 .severity-low {103 background: #f0fdf4; color: #16a34a;104 padding: 2px 8px; border-radius: 3px; font-size: 11px; font-weight: bold;105 }106 .status-open { color: #dc2626; font-weight: bold; }107 .status-progress { color: #d97706; font-weight: bold; }108 .status-closed { color: #16a34a; font-weight: bold; }109 .signature-section {110 display: flex;111 justify-content: space-between;112 margin-top: 40px;113 padding-top: 20px;114 }115 .signature-box { width: 30%; text-align: center; }116 .signature-line {117 border-top: 1px solid #333;118 margin-top: 50px;119 padding-top: 8px;120 font-size: 12px;121 }122 </style>123</head>124<body>125 <div class="header">126 <div class="company-info">127 <h1>{{ company_name | default("BuildRight Construction") }}</h1>128 <p>{{ company_address | default("Jl. Sudirman Kav. 52, Jakarta 12190") }}</p>129 <p>{{ company_phone | default("+62 21 555 0200") }}</p>130 </div>131 <div class="doc-meta">132 <h2>SNAGGING LIST</h2>133 <p><strong>Ref:</strong> {{ reference | default("SNG-2024-0015") }}</p>134 <p><strong>Date:</strong> {{ inspection_date | default("2024-02-10") }}</p>135 <p><strong>Revision:</strong> {{ revision | default("Rev 2") }}</p>136 </div>137 </div>138 139 <div class="info-grid">140 <div class="info-item">141 <div class="label">Project</div>142 <div class="value">{{ project_name | default("Green Valley Residence - Phase 2") }}</div>143 </div>144 <div class="info-item">145 <div class="label">Block / Unit</div>146 <div class="value">{{ unit | default("Block C, Unit 12") }}</div>147 </div>148 <div class="info-item">149 <div class="label">Inspected By</div>150 <div class="value">{{ inspector | default("Ir. Ahmad Prasetyo") }}</div>151 </div>152 <div class="info-item">153 <div class="label">Contractor</div>154 <div class="value">{{ contractor | default("PT Mega Konstruksi") }}</div>155 </div>156 </div>157 158 <div class="summary-bar">159 <div class="summary-item summary-open">160 <div class="count">{{ open_count | default("8") }}</div>161 <div class="desc">Open</div>162 </div>163 <div class="summary-item summary-progress">164 <div class="count">{{ progress_count | default("3") }}</div>165 <div class="desc">In Progress</div>166 </div>167 <div class="summary-item summary-closed">168 <div class="count">{{ closed_count | default("14") }}</div>169 <div class="desc">Closed</div>170 </div>171 </div>172 173 <h3 class="section-title">Defects / Punch List Items</h3>174 <table>175 <thead>176 <tr>177 <th>No.</th>178 <th>Location</th>179 <th>Description</th>180 <th>Severity</th>181 <th>Responsible</th>182 <th>Target Date</th>183 <th>Status</th>184 </tr>185 </thead>186 <tbody>187 {% for item in items | default([188 {"no": "1", "location": "Master Bedroom", "description": "Crack on ceiling plaster (approx 30cm)", "severity": "high", "responsible": "Plastering team", "target": "2024-02-15", "status": "open"},189 {"no": "2", "location": "Kitchen", "description": "Cabinet door misaligned, gap visible", "severity": "medium", "responsible": "Carpentry team", "target": "2024-02-14", "status": "progress"},190 {"no": "3", "location": "Living Room", "description": "Scratch on marble floor tile near entrance", "severity": "medium", "responsible": "Flooring team", "target": "2024-02-16", "status": "open"},191 {"no": "4", "location": "Bathroom 1", "description": "Grout missing between wall tiles (row 3)", "severity": "low", "responsible": "Tiling team", "target": "2024-02-13", "status": "closed"},192 {"no": "5", "location": "Bathroom 2", "description": "Shower drain slow, possible blockage", "severity": "high", "responsible": "Plumbing team", "target": "2024-02-12", "status": "progress"},193 {"no": "6", "location": "Staircase", "description": "Handrail loose at 2nd floor landing", "severity": "high", "responsible": "Metalwork team", "target": "2024-02-14", "status": "open"},194 {"no": "7", "location": "Garage", "description": "Paint peeling on ceiling (water damage?)", "severity": "medium", "responsible": "Painting team", "target": "2024-02-17", "status": "open"},195 {"no": "8", "location": "Garden", "description": "Drainage slope insufficient near retaining wall", "severity": "high", "responsible": "Landscaping team", "target": "2024-02-18", "status": "open"}196 ]) %}197 <tr>198 <td>{{ item.no }}</td>199 <td>{{ item.location }}</td>200 <td>{{ item.description }}</td>201 <td><span class="severity-{{ item.severity }}">{{ item.severity | upper }}</span></td>202 <td>{{ item.responsible }}</td>203 <td>{{ item.target }}</td>204 <td><span class="status-{{ item.status }}">{{ item.status | capitalize }}</span></td>205 </tr>206 {% endfor %}207 </tbody>208 </table>209 210 <h3 class="section-title">Notes</h3>211 <div style="background: #f9fafb; padding: 15px; border-radius: 6px; border-left: 4px solid #4f46e5; margin-bottom: 30px;">212 <p>{{ notes | default("All high-severity items must be rectified before handover inspection scheduled for 2024-02-20. Contractor to provide photographic evidence of completion for each item. Re-inspection to be scheduled within 3 working days of reported completion.") }}</p>213 </div>214 215 <div class="signature-section">216 <div class="signature-box">217 <div class="signature-line">218 {{ inspector | default("Ir. Ahmad Prasetyo") }}<br>219 <small>Inspector</small>220 </div>221 </div>222 <div class="signature-box">223 <div class="signature-line">224 {{ contractor_rep | default("Pak Hendra") }}<br>225 <small>Contractor Representative</small>226 </div>227 </div>228 <div class="signature-box">229 <div class="signature-line">230 {{ client_rep | default("Mr. Tanaka") }}<br>231 <small>Client Representative</small>232 </div>233 </div>234 </div>235</body>236</html>237 