PluginProbe
Easy Invoice – Invoice Generator, PDF Quotes & Payments / 2.4.0
Easy Invoice – Invoice Generator, PDF Quotes & Payments v2.4.0
2.4.0 2.4.1 2.3.8 2.3.7 2.3.6 2.3.5 2.3.4 2.3.3 2.3.2 2.3.1 2.2.0 2.1.21 2.1.20 2.1.19 2.1.18 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.16 2.1.2 All 57 releases
easy-invoice / templates / quote-templates / modern.php

modern.php in Easy Invoice – Invoice Generator, PDF Quotes & Payments 2.4.0, at templates/quote-templates/modern.php

582 lines 24.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Modern Quote Template (Refactored to Minimal style)
4 * This file reuses the Minimal template structure and styling
5 */
6
7 if ( ! defined( 'ABSPATH' ) ) {
8 exit;
9 }
10 $text_settings = \EasyInvoice\Helpers\TemplateTextHelper::getQuoteTextSettings();
11 $company_info = \EasyInvoice\Helpers\TemplateTextHelper::getCompanyInfo();
12 // Ensure a formatter is available
13 if (!isset($formatter) || !$formatter) {
14 $formatter = new \EasyInvoice\Helpers\QuoteFormatter($quote ?? null);
15 }
16 ?>
17 <style>
18 /* Minimal-inspired Modern Template (blue accent only) */
19 :root {
20 --primary-color: #2563eb; /* blue-600 */
21 --primary-light: #3b82f6; /* blue-500 */
22 --primary-dark: #1e40af; /* blue-800 */
23 --secondary-color: #9ca3af;
24 --accent-color: #2563eb;
25 --success-color: #10b981;
26 --warning-color: #f59e0b;
27 --error-color: #ef4444;
28 --text-primary: #111827;
29 --text-secondary: #6b7280;
30 --text-muted: #9ca3af;
31 --border-color: #d1d5db;
32 --border-light: #e5e7eb;
33 --background-primary: #ffffff;
34 --background-secondary: #f9fafb;
35 --background-accent: #eef2ff; /* subtle blue tint */
36 --font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
37 --font-family-heading: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
38 --font-size-xs: 0.75rem; --font-size-sm: 0.875rem; --font-size-base: 1rem; --font-size-lg: 1.125rem; --font-size-xl: 1.25rem; --font-size-2xl: 1.5rem; --font-size-3xl: 1.875rem; --font-size-4xl: 2.25rem;
39 --spacing-1: 0.25rem; --spacing-2: 0.5rem; --spacing-3: 0.75rem; --spacing-4: 1rem; --spacing-5: 1.25rem; --spacing-6: 1.5rem; --spacing-8: 2rem; --spacing-10: 2.5rem; --spacing-12: 3rem; --spacing-16: 4rem; --spacing-20: 5rem;
40 --radius-sm: 0.25rem; --radius-md: 0.375rem; --radius-lg: 0.5rem; --radius-xl: 0.75rem; --radius-2xl: 1rem;
41 --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05); --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
42 }
43
44 .template-modern { font-family: var(--font-family); background: var(--background-primary); color: var(--text-primary); max-width: 800px; margin: 0 auto; padding: var(--spacing-8); line-height: 1.6; }
45 .template-modern .quote-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: var(--spacing-12); padding-bottom: var(--spacing-8); border-bottom: 1px solid var(--border-light); }
46 .template-modern .company-info { flex: 1; }
47 .template-modern .company-logo { margin-bottom: 0; }
48 .template-modern .logo-image { max-height: 60px; max-width: 200px; object-fit: contain; filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1)); }
49 .template-modern .company-name { font-family: var(--font-family-heading); font-size: var(--font-size-2xl); font-weight: 700; color: var(--text-primary); margin-bottom: var(--spacing-3); line-height: 1.2; }
50 .template-modern .company-details { color: var(--text-secondary); font-size: var(--font-size-sm); line-height: 1.5; }
51 .template-modern .quote-meta { text-align: right; min-width: 200px; }
52 .template-modern .quote-title { font-family: var(--font-family-heading); font-size: var(--font-size-2xl); font-weight: 700; color: var(--text-primary); margin-bottom: var(--spacing-2); }
53 .template-modern .meta-item { color: var(--text-secondary); font-size: var(--font-size-sm); }
54 .template-modern .meta-value { color: var(--text-primary); font-weight: 600; }
55 .template-modern .address-section { display: grid; grid-template-columns: 1fr 1fr; gap: var(--spacing-8); margin-bottom: var(--spacing-12); }
56 .template-modern .address-block h2 { font-family: var(--font-family-heading); font-size: var(--font-size-lg); font-weight: 600; color: var(--text-primary); margin-bottom: var(--spacing-4); text-transform: uppercase; letter-spacing: 0.05em; }
57 .template-modern .client-name { font-weight: 600; color: var(--text-primary); font-size: var(--font-size-base); margin-bottom: var(--spacing-2); }
58 .template-modern .address-content { color: var(--text-secondary); font-size: var(--font-size-sm); line-height: 1.5; }
59 .template-modern .quote-items { width: 100%; border-collapse: separate; border-spacing: 0; margin-bottom: var(--spacing-12); }
60 .template-modern .quote-items th { background: var(--background-secondary); color: var(--text-secondary); font-weight: 600; text-align: left; padding: var(--spacing-4) var(--spacing-5); font-size: var(--font-size-sm); text-transform: uppercase; letter-spacing: 0.05em; border-top: 1px solid var(--border-light); border-bottom: 1px solid var(--border-light); }
61 .template-modern .quote-items td { padding: var(--spacing-4) var(--spacing-5); border-bottom: 1px solid var(--border-light); vertical-align: top; }
62 .template-modern .item-name .item-title { font-weight: 600; color: var(--text-primary); margin-bottom: var(--spacing-1); }
63 .template-modern .item-description { color: var(--text-muted); font-size: var(--font-size-sm); line-height: 1.4; }
64 .template-modern .item-quantity, .template-modern .item-price, .template-modern .item-total { text-align: right; font-weight: 500; color: var(--text-primary); }
65 .template-modern .quote-totals { margin-left: auto; width: 360px; background: var(--background-secondary); padding: var(--spacing-6); border-radius: var(--radius-lg); border: 1px solid var(--border-color); }
66 .template-modern .quote-total-row { display: flex; justify-content: space-between; align-items: center; padding: var(--spacing-3) 0; border-bottom: 1px solid var(--border-light); }
67 .template-modern .quote-total-row:last-child { border-bottom: none; }
68 .template-modern .quote-total-label { font-weight: 500; color: var(--text-secondary); }
69 .template-modern .quote-total-value { font-weight: 600; color: var(--text-primary); }
70 .template-modern .quote-totals .quote-grand-total { font-size: var(--font-size-xl); font-weight: 700; color: var(--text-primary); border-top: 2px solid var(--border-light); padding-top: var(--spacing-4); margin-top: var(--spacing-4); }
71 .template-modern .quote-notes { margin-top: var(--spacing-12); padding: var(--spacing-6); background: var(--background-accent); border-radius: var(--radius-lg); border-left: 4px solid var(--primary-color); }
72 .template-modern .quote-terms { margin-top: var(--spacing-12); padding: var(--spacing-6); background: var(--background-secondary); border-radius: var(--radius-lg); border: 1px solid var(--border-color); }
73 .template-modern .quote-footer { margin-top: var(--spacing-12); padding: var(--spacing-6); text-align: center; background: var(--background-secondary); border-radius: var(--radius-lg); border: 1px solid var(--border-color); }
74 @media (max-width: 768px) { .template-modern { padding: var(--spacing-4);} .template-modern .quote-header { flex-direction: column; gap: var(--spacing-4);} .template-modern .address-section { grid-template-columns: 1fr; gap: var(--spacing-6);} .template-modern .quote-totals { width: 100%; } }
75
76 .template-modern .company-info {
77 display: flex;
78 flex-direction: column;
79 gap: var(--spacing-4);
80 }
81
82 .template-modern .company-logo {
83 margin-bottom: 0;
84 }
85
86 .template-modern .logo-image {
87 max-height: 60px;
88 max-width: 200px;
89 object-fit: contain;
90 filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.15));
91 }
92
93 .template-modern .company-name {
94 font-family: var(--font-family-heading);
95 font-size: var(--font-size-2xl);
96 font-weight: 700;
97 color: var(--text-primary);
98 margin-bottom: var(--spacing-3);
99 line-height: 1.2;
100 }
101
102 .template-modern .company-details {
103 color: var(--text-secondary);
104 font-size: var(--font-size-sm);
105 line-height: 1.5;
106 }
107
108 .template-modern .quote-meta {
109 display: flex;
110 flex-direction: column;
111 gap: var(--spacing-4);
112 background: var(--background-primary);
113 padding: var(--spacing-6);
114 border-radius: var(--radius-lg);
115 border: 1px solid var(--border-color);
116 box-shadow: var(--shadow-md);
117 min-width: 300px;
118 }
119
120 .template-modern .quote-title {
121 font-family: var(--font-family-heading);
122 font-size: var(--font-size-2xl);
123 font-weight: 700;
124 color: var(--primary-color);
125 margin-bottom: var(--spacing-4);
126 text-align: center;
127 text-transform: uppercase;
128 letter-spacing: -0.025em;
129 }
130
131 .template-modern .meta-item {
132 display: flex;
133 justify-content: space-between;
134 align-items: center;
135 padding: var(--spacing-3) 0;
136 border-bottom: 1px solid var(--border-light);
137 }
138
139 .template-modern .meta-item:last-child {
140 border-bottom: none;
141 }
142
143 .template-modern .meta-label {
144 font-size: var(--font-size-sm);
145 color: var(--text-secondary);
146 font-weight: 500;
147 }
148
149 .template-modern .meta-value {
150 font-size: var(--font-size-base);
151 color: var(--text-primary);
152 font-weight: 600;
153 }
154
155 /* Address Section */
156 .template-modern .address-section {
157 display: grid;
158 grid-template-columns: 1fr 1fr;
159 gap: var(--spacing-8);
160 margin-bottom: var(--spacing-12);
161 }
162
163 .template-modern .address-block {
164 background: var(--background-secondary);
165 padding: var(--spacing-6);
166 border-radius: var(--radius-lg);
167 border: 1px solid var(--border-color);
168 position: relative;
169 overflow: hidden;
170 }
171
172 .template-modern .address-block::before {
173 content: '';
174 position: absolute;
175 top: 0;
176 left: 0;
177 right: 0;
178 height: 3px;
179 background: var(--primary-color);
180 }
181
182 .template-modern .address-block h2 {
183 font-family: var(--font-family-heading);
184 font-size: var(--font-size-lg);
185 font-weight: 600;
186 color: var(--text-primary);
187 margin-bottom: var(--spacing-4);
188 text-transform: uppercase;
189 letter-spacing: 0.05em;
190 }
191
192 .template-modern .client-name {
193 font-weight: 600;
194 color: var(--text-primary);
195 font-size: var(--font-size-base);
196 margin-bottom: var(--spacing-2);
197 }
198
199 .template-modern .address-content {
200 color: var(--text-secondary);
201 font-size: var(--font-size-sm);
202 line-height: 1.5;
203 }
204
205 /* Quote Items Table */
206 .template-modern .quote-items {
207 width: 100%;
208 border-collapse: separate;
209 border-spacing: 0;
210 margin-bottom: var(--spacing-12);
211 background: var(--background-primary);
212 border-radius: var(--radius-xl);
213 overflow: hidden;
214 box-shadow: var(--shadow-xl);
215 border: 1px solid var(--border-color);
216 }
217
218 .template-modern .quote-items thead {
219 background: linear-gradient(135deg, var(--primary-light), var(--primary-color));
220 }
221 .template-modern .quote-items th {
222 background: transparent;
223 color: white;
224 font-weight: 600;
225 text-align: left;
226 padding: var(--spacing-5) var(--spacing-6);
227 font-size: var(--font-size-sm);
228 text-transform: uppercase;
229 letter-spacing: 0.05em;
230 }
231
232 .template-modern .quote-items td {
233 padding: var(--spacing-5) var(--spacing-6);
234 border-bottom: 1px solid var(--border-light);
235 vertical-align: top;
236 }
237
238 .template-modern .quote-items tr:last-child td {
239 border-bottom: none;
240 }
241
242 .template-modern .quote-items tr:hover {
243 background: var(--background-accent);
244 }
245
246 .template-modern .item-name .item-title {
247 font-weight: 600;
248 color: var(--text-primary);
249 margin-bottom: var(--spacing-1);
250 }
251
252 .template-modern .item-description {
253 color: var(--text-muted);
254 font-size: var(--font-size-sm);
255 line-height: 1.4;
256 font-weight: normal;
257 }
258
259 .template-modern .item-quantity,
260 .template-modern .item-price,
261 .template-modern .item-total {
262 text-align: right;
263 font-weight: 500;
264 color: var(--text-primary);
265 }
266
267 /* Quote Totals */
268 .template-modern .quote-totals {
269 margin-left: auto;
270 width: 420px;
271 background: #ffffff;
272 padding: var(--spacing-8);
273 border-radius: var(--radius-xl);
274 border: 1px solid var(--border-color);
275 box-shadow: var(--shadow-lg);
276 position: relative;
277 }
278
279 .template-modern .quote-totals::before { display: none; }
280
281 .template-modern .quote-total-row {
282 display: flex;
283 justify-content: space-between;
284 align-items: center;
285 padding: var(--spacing-3) 0;
286 border-bottom: 1px solid var(--border-light);
287 }
288
289 .template-modern .quote-total-row:last-child {
290 border-bottom: none;
291 }
292
293 .template-modern .quote-total-label {
294 font-weight: 500;
295 color: var(--text-secondary);
296 }
297
298 .template-modern .quote-total-value {
299 font-weight: 600;
300 color: var(--text-primary);
301 }
302
303 .template-modern .quote-totals .quote-grand-total {
304 font-size: var(--font-size-xl);
305 font-weight: 700;
306 color: var(--primary-color);
307 border-top: 2px solid var(--primary-color);
308 padding-top: var(--spacing-4);
309 margin-top: var(--spacing-4);
310 }
311
312 /* Notes Section */
313 .template-modern .quote-notes {
314 margin-top: var(--spacing-12);
315 padding: var(--spacing-8);
316 background: var(--background-accent);
317 border-radius: var(--radius-xl);
318 border-left: 4px solid var(--primary-color);
319 box-shadow: var(--shadow-md);
320 }
321
322 .template-modern .quote-notes h3 {
323 font-family: var(--font-family-heading);
324 font-size: var(--font-size-lg);
325 font-weight: 600;
326 color: var(--text-primary);
327 margin-bottom: var(--spacing-4);
328 }
329
330 .template-modern .notes-content {
331 color: var(--text-secondary);
332 line-height: 1.6;
333 }
334
335 /* Terms and Conditions Section */
336 .template-modern .quote-terms {
337 margin-top: var(--spacing-12);
338 padding: var(--spacing-8);
339 background: var(--background-secondary);
340 border-radius: var(--radius-xl);
341 border: 1px solid var(--border-color);
342 box-shadow: var(--shadow-md);
343 }
344
345 .template-modern .quote-terms h3 {
346 font-family: var(--font-family-heading);
347 font-size: var(--font-size-lg);
348 font-weight: 600;
349 color: var(--text-primary);
350 margin-bottom: var(--spacing-4);
351 }
352
353 .template-modern .terms-content {
354 color: var(--text-secondary);
355 line-height: 1.6;
356 }
357
358 /* Footer */
359 .template-modern .quote-footer {
360 margin-top: var(--spacing-12);
361 padding: var(--spacing-6);
362 text-align: center;
363 background: var(--background-secondary);
364 border-radius: var(--radius-lg);
365 border: 1px solid var(--border-color);
366 }
367
368 .template-modern .quote-footer p {
369 margin: 0;
370 color: var(--text-secondary);
371 font-size: var(--font-size-sm);
372 }
373
374 /* Responsive Design */
375 @media (max-width: 768px) {
376 .template-modern {
377 padding: var(--spacing-4);
378 }
379
380 .template-modern .quote-header {
381 grid-template-columns: 1fr;
382 gap: var(--spacing-6);
383 }
384
385 .template-modern .quote-meta {
386 min-width: auto;
387 }
388
389 .template-modern .address-section {
390 grid-template-columns: 1fr;
391 gap: var(--spacing-6);
392 }
393
394 .template-modern .quote-totals {
395 width: 100%;
396 }
397 }
398
399 /* Shared polish: numbers line up, numeric headings sit over their figures. */
400 .template-modern .quote-items th + th { text-align: right; }
401 .template-modern .quote-items .item-quantity,
402 .template-modern .quote-items .item-price,
403 .template-modern .quote-items .item-adjust,
404 .template-modern .quote-items .item-total,
405 .template-modern .quote-total-value { font-variant-numeric: tabular-nums; white-space: nowrap; }
406 .template-modern .meta-value { white-space: nowrap; }
407 .template-modern .quote-items .item-adjust { text-align: right; }
408 .template-modern .client-contact { font-weight: 500; margin-bottom: 0.15em; }
409 .template-modern .client-tax-number,
410 .template-modern .company-tax-number { margin-top: 0.35em; }
411 .template-modern .quote-items .item-description { white-space: pre-line; }
412 .template-modern .document-kind { display: block; font-size: 0.72rem; font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase; color: var(--text-muted, #8a8a8a); font-family: var(--font-family-body, inherit); font-style: normal; margin-bottom: 0.3em; line-height: 1.2; }
413
414 /* Modern: one card in the header instead of a card inside a panel; lighter shadows; tighter rhythm. */
415 .template-modern .quote-header { background: transparent; border: 0; padding: 0 0 var(--spacing-6); margin-bottom: var(--spacing-8); border-bottom: 1px solid var(--border-color); border-radius: 0; }
416 .template-modern .quote-meta { box-shadow: var(--shadow-sm); gap: 0; padding: var(--spacing-5) var(--spacing-6); }
417 .template-modern .quote-title { margin-bottom: var(--spacing-2); }
418 .template-modern .meta-item { padding: var(--spacing-2) 0; }
419 .template-modern .meta-item:last-child { border-bottom: 0; }
420 .template-modern .address-section { margin-bottom: var(--spacing-8); }
421 .template-modern .address-block { padding: var(--spacing-5); }
422 .template-modern .address-block h2 { font-size: var(--font-size-xs); letter-spacing: 0.14em; color: var(--text-muted); margin-bottom: var(--spacing-2); }
423 .template-modern .quote-items { box-shadow: var(--shadow-sm); margin-bottom: var(--spacing-8); border: 1px solid var(--border-color); }
424 .template-modern .quote-items th { padding: var(--spacing-3) var(--spacing-5); font-size: var(--font-size-xs); letter-spacing: 0.1em; }
425 .template-modern .quote-items td { padding: var(--spacing-4) var(--spacing-5); }
426 .template-modern .quote-items tr:hover { background: transparent; }
427 .template-modern .quote-totals { box-shadow: var(--shadow-sm); padding: var(--spacing-5) var(--spacing-6); width: 360px; }
428 .template-modern .quote-total-row { padding: var(--spacing-2) 0; }
429 .template-modern .quote-totals .quote-grand-total { padding-top: var(--spacing-3); margin-top: var(--spacing-2); }
430 .template-modern .quote-notes, .template-modern .quote-terms { margin-top: var(--spacing-8); padding: var(--spacing-5) var(--spacing-6); box-shadow: none; }
431 .template-modern .quote-notes h3, .template-modern .quote-terms h3 { font-size: var(--font-size-xs); text-transform: uppercase; letter-spacing: 0.14em; color: var(--text-muted); margin-bottom: var(--spacing-2); }
432 .template-modern .quote-footer { margin-top: var(--spacing-8); background: transparent; border: 0; border-top: 1px solid var(--border-color); border-radius: 0; padding: var(--spacing-5) 0 0; color: var(--text-muted); }
433 </style>
434
435 <div class="template template-modern">
436 <div class="quote-header">
437 <div class="company-info">
438 <?php if (!empty($company_info['logo'])): ?>
439 <div class="company-logo">
440 <img src="<?php echo esc_url($company_info['logo']); ?>" alt="<?php echo esc_attr($company_info['name']); ?>" class="logo-image" onerror="this.parentNode.parentNode.removeChild(this.parentNode)">
441 </div>
442 <?php endif; ?>
443 <div class="company-name"><?php echo esc_html($company_info['name']); ?></div>
444 <div class="company-details">
445 <?php echo wp_kses_post(\EasyInvoice\Helpers\TemplateTextHelper::generateFromSection($company_info, false, 'details-only')); ?>
446 </div>
447 </div>
448
449 <div class="quote-meta">
450 <?php $ei_kind = \EasyInvoice\Controllers\SettingsController::getTextQuote(); $ei_title = trim((string) $quote->getTitle()); ?>
451 <div class="quote-title"><?php if ('' !== $ei_title && 0 !== strcasecmp($ei_title, $ei_kind)) : ?><span class="document-kind"><?php echo esc_html($ei_kind); ?></span><?php endif; ?><?php echo esc_html('' !== $ei_title ? $ei_title : $ei_kind); ?></div>
452 <div class="meta-item">
453 <span class="meta-label"><?php echo esc_html($text_settings['quote_number']); ?></span>
454 <span class="meta-value"><?php echo esc_html($quote->getNumber()); ?></span>
455 </div>
456 <div class="meta-item">
457 <span class="meta-label"><?php echo esc_html($text_settings['quote_date']); ?></span>
458 <span class="meta-value"><?php echo esc_html(\EasyInvoice\Controllers\SettingsController::formatDate($quote->getIssueDate())); ?></span>
459 </div>
460 <div class="meta-item">
461 <span class="meta-label"><?php echo esc_html($text_settings['valid_until']); ?></span>
462 <span class="meta-value"><?php echo esc_html(\EasyInvoice\Controllers\SettingsController::formatDate($quote->getExpiryDate())); ?></span>
463 </div>
464 </div>
465 </div>
466
467 <?php $ei_client_html = \EasyInvoice\Helpers\TemplateTextHelper::generateClientBlock($quote); if ('' !== $ei_client_html) : ?>
468 <div class="address-section">
469 <div class="address-block">
470 <h2><?php echo esc_html($text_settings['to']); ?></h2>
471 <div class="address-content">
472 <?php echo wp_kses_post($ei_client_html); ?>
473 </div>
474 </div>
475 </div>
476 <?php endif; ?>
477
478 <?php if ($quote->getDescription()): ?>
479 <div class="quote-description" style="margin-bottom: 1.5rem;">
480 <div class="description-content" style="color:#6b7280; line-height:1.6; font-size:0.875rem; white-space:pre-wrap;">
481 <?php echo wp_kses_post($quote->getDescription()); ?>
482 </div>
483 </div>
484 <?php endif; ?>
485
486 <?php
487 // The adjustment column appears only when at least one line uses it.
488 $ei_show_adjust = \EasyInvoice\Controllers\SettingsController::shouldShowQuoteAdjustField();
489 if ($ei_show_adjust) {
490 $ei_show_adjust = false;
491 foreach ($quote->getItems() as $ei_item) {
492 if ((float) $ei_item->getAdjustPercentage() != 0.0) { $ei_show_adjust = true; break; }
493 }
494 }
495 ?>
496 <table class="quote-items">
497 <thead>
498 <tr>
499 <th><?php echo esc_html($text_settings['service']); ?></th>
500 <th><?php echo esc_html($text_settings['qty']); ?></th>
501 <th><?php echo esc_html($text_settings['rate_price']); ?></th>
502 <?php if ($ei_show_adjust): ?>
503 <th><?php echo esc_html($text_settings['adjust']); ?> (%)</th>
504 <?php endif; ?>
505 <th><?php echo esc_html($text_settings['line_total'] ?? $text_settings['total']); ?></th>
506 </tr>
507 </thead>
508 <tbody>
509 <?php if (!$quote->getItems()) : ?>
510 <tr class="no-items"><td colspan="<?php echo $ei_show_adjust ? 5 : 4; ?>" style="text-align:center;color:#9ca3af;padding:18px;"><?php esc_html_e('No items yet.', 'easy-invoice'); ?></td></tr>
511 <?php endif; ?>
512 <?php foreach ($quote->getItems() as $item): ?>
513 <tr>
514 <td class="item-name">
515 <div class="item-title"><?php echo esc_html($item->getName()); ?></div>
516 <?php if ($item->getDescription()): ?>
517 <div class="item-description"><?php echo esc_html($item->getDescription()); ?></div>
518 <?php endif; ?>
519 </td>
520 <td class="item-quantity"><?php echo esc_html($item->getQuantity() ?: '0'); ?></td>
521 <td class="item-price"><?php echo esc_html($formatter->format($item->getPrice())); ?></td>
522 <?php if ($ei_show_adjust): ?>
523 <td class="item-adjust"><?php
524 $adjust_percentage = $item->getAdjustPercentage();
525 if ($adjust_percentage != 0) {
526 echo esc_html($adjust_percentage > 0 ? '+' : '') . esc_html($adjust_percentage) . '%';
527 } else {
528 echo esc_html__('—', 'easy-invoice');
529 }
530 ?></td>
531 <?php endif; ?>
532 <td class="item-total"><?php echo esc_html($formatter->format($item->getAmount())); ?></td>
533 </tr>
534 <?php endforeach; ?>
535 </tbody>
536 </table>
537
538 <div class="quote-totals">
539 <?php echo wp_kses_post(\EasyInvoice\Helpers\TemplateTextHelper::generateTotalsSection($quote, $text_settings, $formatter, 'quote')); ?>
540 </div>
541
542 <?php if ($quote->getNotes()): ?>
543 <div class="quote-notes">
544 <h3><?php esc_html_e('Notes', 'easy-invoice'); ?></h3>
545 <div class="notes-content">
546 <?php echo wp_kses_post($quote->getNotes() ?: ''); ?>
547 </div>
548 </div>
549 <?php endif; ?>
550
551 <?php
552 $terms_conditions = $quote->getTerms() ?: \EasyInvoice\Controllers\SettingsController::getQuoteTermsConditions();
553 if ($terms_conditions):
554 ?>
555 <div class="quote-terms">
556 <h3><?php esc_html_e('Terms & Conditions', 'easy-invoice'); ?></h3>
557 <div class="terms-content">
558 <?php echo wp_kses_post($terms_conditions); ?>
559 </div>
560 </div>
561 <?php endif; ?>
562
563 <?php
564 /**
565 * Fires inside the document card, after notes and terms and before the
566 * footer text: attachments, the signature block, e-invoicing notes. Being
567 * inside the card, it is part of what "Download as PDF" captures.
568 *
569 * @param object $document The quote model.
570 * @param string $type 'quote'.
571 */
572 do_action('easy_invoice_document_body_after', $quote, 'quote');
573
574 $ei_footer_text = \EasyInvoice\Helpers\TemplateTextHelper::footerText($quote, 'quote');
575 if ('' !== trim(wp_strip_all_tags((string) $ei_footer_text))) :
576 ?>
577 <div class="quote-footer">
578 <p><?php echo wp_kses_post($ei_footer_text); ?></p>
579 </div>
580 <?php endif; ?>
581 </div>
582