fmard/pdf-api
0
1<!DOCTYPE html>2<html lang="en">3<head>4 <meta charset="UTF-8">5 <title>Quotation - {{ quotation_number | default('QT-0001') }}</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 padding: 40px;11 color: #1f2937;12 font-size: 13px;13 line-height: 1.5;14 }15 .header {16 display: flex;17 justify-content: space-between;18 align-items: flex-start;19 margin-bottom: 40px;20 padding-bottom: 20px;21 border-bottom: 3px solid #4f46e5;22 }23 .company-info h1 {24 font-size: 22px;25 color: #4f46e5;26 margin-bottom: 4px;27 }28 .company-info p { color: #6b7280; font-size: 12px; }29 .doc-title {30 text-align: right;31 }32 .doc-title h2 {33 font-size: 28px;34 color: #4f46e5;35 text-transform: uppercase;36 letter-spacing: 2px;37 }38 .doc-title p { color: #6b7280; margin-top: 4px; font-size: 12px; }39 .parties {40 display: flex;41 justify-content: space-between;42 margin-bottom: 30px;43 }44 .party-block h4 {45 font-size: 11px;46 text-transform: uppercase;47 color: #6b7280;48 margin-bottom: 6px;49 letter-spacing: 0.5px;50 }51 .party-block p { font-size: 13px; }52 .meta-info {53 display: flex;54 gap: 40px;55 margin-bottom: 30px;56 padding: 12px 16px;57 background: #f9fafb;58 border-radius: 6px;59 }60 .meta-info div span { display: block; font-size: 11px; color: #6b7280; text-transform: uppercase; }61 .meta-info div strong { font-size: 13px; }62 table {63 width: 100%;64 border-collapse: collapse;65 margin-bottom: 20px;66 }67 thead th {68 background: #4f46e5;69 color: #ffffff;70 padding: 10px 12px;71 text-align: left;72 font-size: 11px;73 text-transform: uppercase;74 letter-spacing: 0.5px;75 }76 thead th:last-child, thead th:nth-child(3), thead th:nth-child(4) { text-align: right; }77 tbody td {78 padding: 10px 12px;79 border-bottom: 1px solid #e5e7eb;80 }81 tbody td:last-child, tbody td:nth-child(3), tbody td:nth-child(4) { text-align: right; }82 tbody tr:nth-child(even) { background: #f9fafb; }83 .totals {84 display: flex;85 justify-content: flex-end;86 margin-bottom: 30px;87 }88 .totals-table { width: 280px; }89 .totals-table .row {90 display: flex;91 justify-content: space-between;92 padding: 6px 0;93 border-bottom: 1px solid #e5e7eb;94 }95 .totals-table .row.grand-total {96 border-bottom: none;97 border-top: 2px solid #4f46e5;98 padding-top: 10px;99 font-size: 16px;100 font-weight: 700;101 color: #4f46e5;102 }103 .notes { margin-top: 20px; }104 .notes h4 { font-size: 12px; color: #6b7280; text-transform: uppercase; margin-bottom: 6px; }105 .notes p { font-size: 12px; color: #374151; }106 .terms { margin-top: 16px; padding-top: 16px; border-top: 1px solid #e5e7eb; }107 .terms h4 { font-size: 12px; color: #6b7280; text-transform: uppercase; margin-bottom: 6px; }108 .terms p { font-size: 11px; color: #6b7280; }109 </style>110</head>111<body>112 <div class="header">113 <div class="company-info">114 <h1>{{ company_name | default('Your Company Name') }}</h1>115 <p>{{ company_address | default('123 Business Street, City, Country') }}</p>116 </div>117 <div class="doc-title">118 <h2>Quotation</h2>119 <p>#{{ quotation_number | default('QT-0001') }}</p>120 </div>121 </div>122 123 <div class="parties">124 <div class="party-block">125 <h4>Quotation To</h4>126 <p><strong>{{ client_name | default('Client Name') }}</strong></p>127 <p>{{ client_address | default('Client Address') }}</p>128 </div>129 </div>130 131 <div class="meta-info">132 <div><span>Date</span><strong>{{ date | default('2025-01-01') }}</strong></div>133 <div><span>Valid Until</span><strong>{{ valid_until | default('2025-02-01') }}</strong></div>134 <div><span>Quotation #</span><strong>{{ quotation_number | default('QT-0001') }}</strong></div>135 </div>136 137 <table>138 <thead>139 <tr>140 <th>#</th>141 <th>Description</th>142 <th>Qty</th>143 <th>Unit Price</th>144 <th>Amount</th>145 </tr>146 </thead>147 <tbody>148 {% set ns = namespace(subtotal=0) %}149 {% for item in items | default([{'description': 'Sample Item', 'quantity': 1, 'unit_price': 100}]) %}150 {% set line_total = item.quantity * item.unit_price %}151 {% set ns.subtotal = ns.subtotal + line_total %}152 <tr>153 <td>{{ loop.index }}</td>154 <td>{{ item.description }}</td>155 <td>{{ item.quantity }}</td>156 <td>{{ "{:,.2f}".format(item.unit_price) }}</td>157 <td>{{ "{:,.2f}".format(line_total) }}</td>158 </tr>159 {% endfor %}160 </tbody>161 </table>162 163 {% set discount = ns.subtotal * (discount_percent | default(0)) / 100 %}164 {% set after_discount = ns.subtotal - discount %}165 {% set tax = after_discount * (tax_rate | default(0)) / 100 %}166 {% set grand_total = after_discount + tax %}167 168 <div class="totals">169 <div class="totals-table">170 <div class="row"><span>Subtotal</span><span>{{ "{:,.2f}".format(ns.subtotal) }}</span></div>171 {% if discount_percent | default(0) > 0 %}172 <div class="row"><span>Discount ({{ discount_percent }}%)</span><span>-{{ "{:,.2f}".format(discount) }}</span></div>173 {% endif %}174 {% if tax_rate | default(0) > 0 %}175 <div class="row"><span>Tax ({{ tax_rate }}%)</span><span>{{ "{:,.2f}".format(tax) }}</span></div>176 {% endif %}177 <div class="row grand-total"><span>Total</span><span>{{ "{:,.2f}".format(grand_total) }}</span></div>178 </div>179 </div>180 181 {% if notes | default('') %}182 <div class="notes">183 <h4>Notes</h4>184 <p>{{ notes }}</p>185 </div>186 {% endif %}187 188 {% if terms | default('') %}189 <div class="terms">190 <h4>Terms & Conditions</h4>191 <p>{{ terms }}</p>192 </div>193 {% endif %}194</body>195</html>