PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.5.2
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.5.2
1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 trunk All 48 releases
fluent-cart / app / Services / PDF / DefaultPdfStructures.php

DefaultPdfStructures.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.5.2, at app/Services/PDF/DefaultPdfStructures.php

317 lines 11.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCart\App\Services\PDF;
4
5 if (!defined('ABSPATH')) {
6 exit;
7 }
8
9 /**
10 * Default block-editor PDF structures for FluentCart receipts.
11 *
12 * Design system (A4 Portrait) — minimal:
13 * TEXT #111111 primary text
14 * META #666666 labels / secondary text
15 * BORDER #DDDDDD dividers
16 * WHITE #FFFFFF
17 */
18 class DefaultPdfStructures
19 {
20 private const TEXT = '#111111';
21 private const META = '#666666';
22 private const BORDER = '#DDDDDD';
23 private const WHITE = '#FFFFFF';
24
25 /**
26 * Default meta for all PDF templates.
27 */
28 public static function getDefaultMeta(): array
29 {
30 return [
31 '_fluent_cart_paper_size' => 'A4',
32 '_fluent_cart_orientation' => 'Portrait',
33 '_fluent_cart_font' => 'DejaVuSans',
34 '_fluent_cart_watermark_enabled' => 0,
35 '_fluent_cart_watermark_text' => 'PAID',
36 ];
37 }
38
39 // ── Order Receipt ────────────────────────────────────────────────────────
40
41 /**
42 * @return array{content:string, blocks:array, meta:array}
43 */
44 public static function getDefaultReceiptStructure(): array
45 {
46 $blocks = self::buildReceiptBlocks();
47 return [
48 'content' => self::blocksToContent($blocks),
49 'blocks' => $blocks,
50 'meta' => self::getDefaultMeta(),
51 ];
52 }
53
54 private static function buildReceiptBlocks(): array
55 {
56 $blocks = [];
57
58 $blocks[] = self::header('RECEIPT');
59 $blocks[] = self::addressColumns();
60 $blocks[] = self::metaTable([
61 'Order Number' => '{{order.invoice_no}}',
62 'Order Date' => '{{order.created_at}}',
63 'Payment Method' => '{{order.payment_method_title}}',
64 'Payment Status' => '{{order.payment_status}}',
65 ]);
66 $blocks[] = self::itemsTable();
67 $blocks[] = self::summaryTable([
68 'Subtotal' => '{{order.subtotal_formatted}}',
69 'Discount' => '{{order.discount_total_formatted}}',
70 'Fees' => '{{order.fee_lines}}',
71 'Tax' => '{{order.tax_breakdown}}',
72 'Shipping' => '{{order.shipping_total_formatted}}',
73 ], 'Total', '{{order.total_amount_formatted}}');
74 $blocks[] = self::footer(__('Thank you for your purchase!', 'fluent-cart'));
75
76 return $blocks;
77 }
78
79 // ── Renewal Receipt ───────────────────────────────────────────────────────
80
81 /**
82 * @return array{content:string, blocks:array, meta:array}
83 */
84 public static function getDefaultRenewalReceiptStructure(): array
85 {
86 $blocks = self::buildRenewalReceiptBlocks();
87 return [
88 'content' => self::blocksToContent($blocks),
89 'blocks' => $blocks,
90 'meta' => self::getDefaultMeta(),
91 ];
92 }
93
94 private static function buildRenewalReceiptBlocks(): array
95 {
96 $blocks = [];
97
98 $blocks[] = self::header('RENEWAL RECEIPT');
99 $blocks[] = self::addressColumns();
100 $blocks[] = self::metaTable([
101 'Order Number' => '{{order.invoice_no}}',
102 'Renewal Date' => '{{order.created_at}}',
103 'Payment Method' => '{{order.payment_method_title}}',
104 'Payment Status' => '{{order.payment_status}}',
105 ]);
106 $blocks[] = self::itemsTable();
107 $blocks[] = self::summaryTable([
108 'Subtotal' => '{{order.subtotal_formatted}}',
109 'Discount' => '{{order.discount_total_formatted}}',
110 'Fees' => '{{order.fee_lines}}',
111 'Tax' => '{{order.tax_breakdown}}',
112 ], 'Total', '{{order.total_amount_formatted}}');
113 $blocks[] = self::footer(__('Thank you for your continued subscription!', 'fluent-cart'));
114
115 return $blocks;
116 }
117
118 // ── Refund Notice ─────────────────────────────────────────────────────────
119
120 /**
121 * @return array{content:string, blocks:array, meta:array}
122 */
123 public static function getDefaultRefundNoticeStructure(): array
124 {
125 $blocks = self::buildRefundNoticeBlocks();
126 $meta = self::getDefaultMeta();
127 $meta['_fluent_cart_watermark_text'] = 'REFUNDED';
128 return [
129 'content' => self::blocksToContent($blocks),
130 'blocks' => $blocks,
131 'meta' => $meta,
132 ];
133 }
134
135 private static function buildRefundNoticeBlocks(): array
136 {
137 $blocks = [];
138
139 $blocks[] = self::header('REFUND NOTICE');
140 $blocks[] = self::addressColumns('REFUND TO');
141 $blocks[] = self::metaTable([
142 'Order Number' => '{{order.invoice_no}}',
143 'Order Date' => '{{order.created_at}}',
144 'Payment Method' => '{{order.payment_method_title}}',
145 ]);
146 $blocks[] = self::itemsTable();
147 $blocks[] = self::summaryTable([
148 'Original Total' => '{{order.total_amount_formatted}}',
149 ], 'Refund Amount', '{{order.total_refund}}');
150 $blocks[] = self::footer(__('Your refund has been processed. Please allow a few business days for the amount to appear in your account.', 'fluent-cart'));
151
152 return $blocks;
153 }
154
155 // ── Proforma Invoice ──────────────────────────────────────────────────────
156
157 /**
158 * @return array{content:string, blocks:array, meta:array}
159 */
160 public static function getDefaultProformaInvoiceStructure(): array
161 {
162 $blocks = self::buildProformaInvoiceBlocks();
163 $meta = self::getDefaultMeta();
164 $meta['_fluent_cart_watermark_enabled'] = 0;
165 $meta['_fluent_cart_watermark_text'] = '';
166 return [
167 'content' => self::blocksToContent($blocks),
168 'blocks' => $blocks,
169 'meta' => $meta,
170 ];
171 }
172
173 private static function buildProformaInvoiceBlocks(): array
174 {
175 $blocks = [];
176
177 $blocks[] = self::header('INVOICE');
178 $blocks[] = self::addressColumns();
179 $blocks[] = self::metaTable([
180 'Invoice Number' => '{{order.invoice_no}}',
181 'Invoice Date' => '{{order.created_at}}',
182 'Payment Method' => '{{order.payment_method_title}}',
183 'Payment Status' => '{{order.payment_status}}',
184 ]);
185 $blocks[] = self::itemsTable();
186 $blocks[] = self::summaryTable([
187 'Subtotal' => '{{order.subtotal_formatted}}',
188 'Discount' => '{{order.discount_total_formatted}}',
189 'Fees' => '{{order.fee_lines}}',
190 'Tax' => '{{order.tax_breakdown}}',
191 'Shipping' => '{{order.shipping_total_formatted}}',
192 ], 'Amount Due', '{{order.total_amount_formatted}}');
193 $blocks[] = self::footer(__('Thank you for your order. Please complete the payment to process your order.', 'fluent-cart'));
194
195 return $blocks;
196 }
197
198 // ── Shared block builders ─────────────────────────────────────────────────
199
200 /**
201 * Document header: logo left, title right, bottom rule.
202 */
203 private static function header(string $title): array
204 {
205 return self::block('fluent-cart/receipt-header', ['title' => $title]);
206 }
207
208 /**
209 * Two-column FROM / BILL TO address block.
210 */
211 private static function addressColumns(string $billingLabel = 'BILL TO'): array
212 {
213 return self::block('fluent-cart/receipt-addresses', ['billingLabel' => $billingLabel]);
214 }
215
216 /**
217 * Key/value meta rows (order number, date, etc.).
218 *
219 * @param array<string,string> $rows label => smartcode
220 */
221 private static function metaTable(array $rows): array
222 {
223 $rowsData = [];
224 foreach ($rows as $label => $value) {
225 $rowsData[] = ['label' => $label, 'value' => $value];
226 }
227
228 return self::block('fluent-cart/receipt-meta', ['rows' => $rowsData]);
229 }
230
231 /**
232 * Line-items table (delegated to the order variable).
233 */
234 private static function itemsTable(): array
235 {
236 return self::block('fluent-cart/receipt-item-table', [
237 'headerBg' => self::WHITE,
238 'headerColor' => self::TEXT,
239 'bodyColor' => self::TEXT,
240 'borderColor' => self::BORDER,
241 'fontSize' => 11,
242 ], '{{order.items_table}}');
243 }
244
245 /**
246 * Payment summary with optional sub-rows and a bold total row.
247 *
248 * @param array<string,string> $rows label => smartcode
249 */
250 private static function summaryTable(array $rows, string $totalLabel, string $totalValue): array
251 {
252 $rowsData = [];
253 foreach ($rows as $label => $value) {
254 $rowsData[] = ['label' => $label, 'value' => $value];
255 }
256
257 return self::block('fluent-cart/receipt-payment-summary', [
258 'rows' => $rowsData,
259 'totalLabel' => $totalLabel,
260 'totalValue' => $totalValue,
261 ]);
262 }
263
264 /**
265 * Footer note, centred, small text.
266 */
267 private static function footer(string $text): array
268 {
269 return self::block('fluent-cart/receipt-footer', ['text' => $text]);
270 }
271
272 // ── Low-level helpers ─────────────────────────────────────────────────────
273
274 private static function block(string $name, array $attrs = [], ?string $content = null, array $innerBlocks = []): array
275 {
276 return [
277 'blockName' => $name,
278 'attrs' => $attrs,
279 'innerHTML' => $content ?? '',
280 'innerContent' => $content !== null ? [$content] : [],
281 'innerBlocks' => $innerBlocks,
282 ];
283 }
284
285 /**
286 * Serialize blocks array to Gutenberg block comment format.
287 */
288 public static function blocksToContent(array $blocks): string
289 {
290 $out = '';
291 foreach ($blocks as $block) {
292 $name = $block['blockName'];
293 $attrs = $block['attrs'] ?? [];
294 $innerBlocks = $block['innerBlocks'] ?? [];
295 $innerHTML = $block['innerHTML'] ?? '';
296
297 $attrJson = !empty($attrs) ? ' ' . wp_json_encode($attrs) : '';
298
299 if (!empty($innerBlocks)) {
300 $out .= "<!-- wp:{$name}{$attrJson} -->\n";
301 $out .= $innerHTML ? "{$innerHTML}\n" : '';
302 $out .= self::blocksToContent($innerBlocks);
303 $out .= "<!-- /wp:{$name} -->\n\n";
304 } else {
305 if ($innerHTML) {
306 $out .= "<!-- wp:{$name}{$attrJson} -->\n";
307 $out .= "{$innerHTML}\n";
308 $out .= "<!-- /wp:{$name} -->\n\n";
309 } else {
310 $out .= "<!-- wp:{$name}{$attrJson} /-->\n\n";
311 }
312 }
313 }
314 return $out;
315 }
316 }
317