PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.4
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.4
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 1.2.0 All 47 releases
fluent-cart / app / Services / Renderer / Receipt / ThankYouRender.php

ThankYouRender.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.6.4, at app/Services/Renderer/Receipt/ThankYouRender.php

1,449 lines 64.3 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\Renderer\Receipt;
4
5 use FluentCart\Api\StoreSettings;
6 use FluentCart\App\App;
7 use FluentCart\App\Helpers\Helper;
8 use FluentCart\App\Helpers\Status;
9 use FluentCart\App\Modules\Tax\TaxModule;
10 use FluentCart\App\Modules\Templating\AssetLoader;
11 use FluentCart\App\Vite;
12 use FluentCart\Framework\Support\Arr;
13 use FluentCart\App\Modules\PaymentMethods\Core\GatewayManager;
14
15 class ThankYouRender
16 {
17
18 protected $config = null;
19
20 protected $settings = null;
21
22 protected $is_first_time = false;
23
24 protected $order_operation = null;
25
26 private $fctTaxSummaryCache = [];
27
28 public function __construct($config)
29 {
30 $this->config = $config;
31
32 $this->is_first_time = Arr::get($this->config, 'is_first_time', false);
33 $this->order_operation = Arr::get($this->config, 'order_operation', false);
34
35 $this->settings = new StoreSettings();
36 AssetLoader::enqueueThankYouPageAssets();
37
38 }
39
40 private function getMemoizedTaxSummary($order)
41 {
42 if (!$order) {
43 return TaxSummaryHelper::computeTaxSummary($order);
44 }
45 $id = (int) $order->id;
46 if (!isset($this->fctTaxSummaryCache[$id])) {
47 $this->fctTaxSummaryCache[$id] = TaxSummaryHelper::computeTaxSummary($order);
48 }
49 return $this->fctTaxSummaryCache[$id];
50 }
51
52 public function renderWrapperStart()
53 {
54 ?>
55 <div class="fct-thank-you-page">
56 <div class="fct-thank-you-page-inner">
57 <div class="fct-thank-you-page-content email-template-content">
58 <?php
59 }
60
61 public function renderWrapperEnd()
62 {
63 ?>
64 </div>
65 </div>
66 </div>
67 <?php
68 }
69
70 public function render($hide_wrapper = false)
71 {
72 $order = Arr::get($this->config, 'order', null);
73
74 if (!$order) {
75 return;
76 }
77 ?>
78 <?php if (!$hide_wrapper) {
79 $this->renderWrapperStart();
80 } ?>
81 <?php do_action('fluent_cart/receipt/thank_you/before_header', $this->config); ?>
82 <?php $this->renderHeader(); ?>
83 <?php do_action('fluent_cart/receipt/thank_you/after_header', $this->config); ?>
84
85 <?php do_action('fluent_cart/receipt/thank_you/before_body', $this->config); ?>
86 <?php $this->renderBody(); ?>
87 <?php do_action('fluent_cart/receipt/thank_you/after_body', $this->config); ?>
88 <?php if (!$hide_wrapper) {
89 $this->renderWrapperEnd();
90 } ?>
91
92 <?php
93
94 $this->renderFooter();
95
96 do_action('fluent_cart/after_receipt', [
97 'order' => $order,
98 'is_first_time' => $this->is_first_time ?? false,
99 'order_operation' => $this->order_operation ?? null
100 ]);
101
102 if (!empty($this->is_first_time)) {
103 do_action('fluent_cart/after_receipt_first_time', [
104 'order' => $order,
105 'order_operation' => $this->order_operation ?? null
106 ]);
107 }
108 }
109
110 protected function getHeaderState()
111 {
112 $order = Arr::get($this->config, 'order', null);
113 $status = $order ? $order->payment_status : '';
114
115 if ($status === Status::PAYMENT_REFUNDED) {
116 return 'refunded';
117 }
118 if ($status === Status::PAYMENT_FAILED) {
119 return 'failed';
120 }
121 if (in_array($status, [Status::PAYMENT_PAID, Status::PAYMENT_PARTIALLY_REFUNDED], true)) {
122 return 'success';
123 }
124
125 return 'pending';
126 }
127
128 public function renderHeader()
129 {
130 $state = $this->getHeaderState();
131
132 $styles = [
133 'success' => ['bg' => '#d4edda', 'title' => '#155724', 'iconBg' => '#155724bd'],
134 'pending' => ['bg' => '#fff3cd', 'title' => '#856404', 'iconBg' => '#856404bd'],
135 'failed' => ['bg' => '#f8d7da', 'title' => '#721c24', 'iconBg' => '#721c24bd'],
136 'refunded' => ['bg' => '#e2e3e5', 'title' => '#383d41', 'iconBg' => '#383d41bd'],
137 ];
138
139 $titles = [
140 'success' => __('Purchase Successful!', 'fluent-cart'),
141 'pending' => __('Payment Pending!', 'fluent-cart'),
142 'failed' => __('Payment Failed', 'fluent-cart'),
143 'refunded' => __('Order Refunded', 'fluent-cart'),
144 ];
145
146 $bgColor = $styles[$state]['bg'];
147 $titleColor = $styles[$state]['title'];
148 $iconBg = $styles[$state]['iconBg'];
149 ?>
150 <div class="fct-thank-you-page-header" style="background: <?php echo esc_attr($bgColor); ?>;">
151 <div class="fct-thank-you-page-header-icon" style="background: <?php echo esc_attr($iconBg); ?>;">
152 <?php if ($state === 'success') : ?>
153 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor"
154 stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
155 <polyline points="20,6 9,17 4,12"></polyline>
156 </svg>
157 <?php elseif ($state === 'failed') : ?>
158 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor"
159 stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
160 <line x1="18" y1="6" x2="6" y2="18"></line>
161 <line x1="6" y1="6" x2="18" y2="18"></line>
162 </svg>
163 <?php elseif ($state === 'refunded') : ?>
164 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor"
165 stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
166 <polyline points="9,14 4,9 9,4"></polyline>
167 <path d="M4 9h10a6 6 0 0 1 0 12h-3"></path>
168 </svg>
169 <?php else : ?>
170 <svg class="w-64 h-64" xmlns="http://www.w3.org/2000/svg"
171 viewBox="0 0 1024 1024" fill="currentColor">
172 <path
173 d="M480 674V192c0-18 14-32 32-32s32 14 32 32v482h-64zm0 63h64v60h-64v-60zM0 512C0 229 229 0 512 0s512 229 512 512-229 512-512 512S0 795 0 512zm961 0c0-247-202-448-449-448S64 265 64 512s201 448 448 448 449-201 449-448z"></path>
174 </svg>
175 <?php endif; ?>
176 </div>
177 <h1 class="fct-thank-you-page-header-title" style="color:<?php echo esc_attr($titleColor); ?>;">
178 <?php echo esc_html($titles[$state]); ?>
179 </h1>
180
181 <?php do_action('fluent_cart/receipt/thank_you/after_header_title', $this->config); ?>
182
183 </div>
184
185 <?php
186 }
187
188 public function renderBody()
189 {
190 $order = Arr::get($this->config, 'order', null);
191
192 if (!$order) {
193 return;
194 }
195 ?>
196 <div class="fct-thank-you-page-body">
197 <div class="fct-thank-you-page-body-inner">
198 <div class="fct-thank-you-page-body-content">
199 <div class="fct-thank-you-page-body-content-inner">
200 <?php do_action('fluent_cart/receipt/thank_you/before_order_header', $this->config); ?>
201 <?php $this->renderOrderHeader(); ?>
202 <?php do_action('fluent_cart/receipt/thank_you/after_order_header', $this->config); ?>
203
204 <?php $this->renderStoreTaxInformation(); ?>
205
206 <?php do_action('fluent_cart/receipt/thank_you/before_order_items', $this->config); ?>
207 <?php $this->renderOrderItems(); ?>
208 <?php do_action('fluent_cart/receipt/thank_you/after_order_items', $this->config); ?>
209
210 <?php $this->renderSubscriptionItems(); ?>
211
212 <?php $this->renderDownloads(); ?>
213
214 <?php $this->renderLicenses(); ?>
215
216 <?php $this->renderAddress(); ?>
217
218 <?php $this->renderThankYouPageInstructions(); ?>
219
220 </div>
221 </div>
222 </div>
223 </div>
224
225 <?php
226 }
227
228 public function renderOrderHeader()
229 {
230 $order = Arr::get($this->config, 'order', null);
231 $profilePage = $this->settings->getCustomerProfilePage();
232 ?>
233 <div class="no-print">
234 <div class="no-print-title">
235 <?php
236 echo sprintf(
237 /* translators: %s is the customer's full name */
238 esc_html__('Hello %s!', 'fluent-cart'),
239 esc_html($order->customer->full_name)
240 );
241 ?>
242 </div>
243 <?php $state = $this->getHeaderState(); ?>
244 <?php if ($state === 'success') : ?>
245 <p>
246 <?php
247 printf(
248 '%s<strong style="color: #007bff;"><a href="%s">#%s</a></strong>%s',
249 esc_html__('Your order ', 'fluent-cart'),
250 esc_url($profilePage . 'order/' . $order->uuid),
251 esc_html($order->invoice_no),
252 esc_html__(' has been placed successfully.', 'fluent-cart')
253 );
254 ?>
255 </p>
256 <?php elseif ($state === 'refunded') : ?>
257 <p>
258 <?php
259 printf(
260 '%s<strong style="color: #007bff;"><a href="%s">#%s</a></strong>%s',
261 esc_html__('Your order ', 'fluent-cart'),
262 esc_url($profilePage . 'order/' . $order->uuid),
263 esc_html($order->invoice_no),
264 esc_html__(' has been refunded.', 'fluent-cart')
265 );
266 ?>
267 </p>
268 <?php elseif ($state === 'failed') : ?>
269 <p>
270 <?php
271 printf(
272 '%s<strong style="color: #007bff;"><a href="%s">#%s</a></strong>%s <a style="color: #007bff;" target="_blank" href="%s">%s</a>.',
273 esc_html__('The payment for your order ', 'fluent-cart'),
274 esc_url($profilePage . 'order/' . $order->uuid),
275 esc_html($order->invoice_no),
276 esc_html__(' could not be completed. You can try again from', 'fluent-cart'),
277 esc_url(\FluentCart\App\Services\Payments\PaymentHelper::getCustomPaymentLink($order->uuid)),
278 esc_html__('here', 'fluent-cart')
279 );
280 ?>
281 </p>
282 <?php else: ?>
283 <p>
284
285 <?php
286 printf(
287 '<strong style="color: #007bff;"><a href="%s">%s</a></strong> %s <a style="color: #007bff;" target="_blank" href="%s">%s</a>.',
288 esc_url($profilePage . 'order/' . $order->uuid),
289 esc_html__('Your order', 'fluent-cart'),
290 esc_html__('has payment due. You can pay from', 'fluent-cart'),
291 esc_url(\FluentCart\App\Services\Payments\PaymentHelper::getCustomPaymentLink($order->uuid)),
292 esc_html__('here', 'fluent-cart')
293 );
294 ?>
295
296 </p>
297 <?php endif; ?>
298
299 </div>
300
301 <?php
302 }
303
304 public function renderStoreTaxInformation()
305 {
306 $order = Arr::get($this->config, 'order', null);
307
308 $orderTaxRates = $order->getPrimaryOrderTaxRate();
309 if ($order->tax_total > 0 || $orderTaxRates): ?>
310 <div class="fct_invoice_tax_content">
311 <?php
312 if ($orderTaxRates) {
313 $storeVatNumber = Arr::get($orderTaxRates->meta, 'store_vat_number', '');
314 $taxcountry = Arr::get($orderTaxRates->meta ?? [], 'tax_country', '');
315 if ($storeVatNumber !== '') {
316 echo '<p>' . esc_html(TaxModule::getCountryTaxTitle($taxcountry)) . ': ' . esc_html($storeVatNumber) . '</p>';
317 }
318 }
319 ?>
320 </div>
321 <?php endif;
322 }
323
324 public function renderOrderItems()
325 {
326 $order = Arr::get($this->config, 'order', null);
327
328 if ($order->order_items) : ?>
329 <div class="fct-thank-you-page-order-items">
330 <?php $this->renderOrderItemsHeader(); ?>
331
332 <?php $this->renderOrderItemsBody(); ?>
333 </div>
334 <?php endif;
335 }
336
337 public function renderOrderItemsHeader()
338 {
339 ?>
340 <div class="fct-thank-you-page-order-items-header">
341 <div class="fct-thank-you-page-order-items-header-row">
342 <?php echo esc_html__('Item', 'fluent-cart'); ?>
343 </div>
344 <div class="fct-thank-you-page-order-items-header-row">
345 <?php echo esc_html__('Total', 'fluent-cart'); ?>
346 </div>
347 </div>
348 <?php
349 }
350
351 public function renderOrderItemsBody()
352 {
353 $order = Arr::get($this->config, 'order', null);
354 $fctTaxDisplayMode = TaxSummaryHelper::getTaxDisplayMode();
355 ?>
356 <div class="fct-thank-you-page-order-items-body">
357 <?php
358 $order->loadMissing(['order_items']);
359 $orderItems = $order->getProductItems()->toArray();
360 $orderItems = $this->buildBundleItemsTree($orderItems);
361
362 foreach ($orderItems as $item) :
363 ?>
364 <div class="fct-thank-you-page-order-items-list">
365 <div class="fct-thank-you-page-order-items-list-title">
366 <p class="fct-thank-you-page-order-items-list-quantity">
367 <?php echo esc_html($item['post_title']); ?>
368 <?php if ($item['quantity'] > 1): ?>
369 <span>x <?php echo esc_html(Helper::translateNumber($item['quantity'])); ?></span>
370 <?php endif; ?>
371 </p>
372 <?php if (!empty($item['title']) && $item['title'] !== $item['post_title']): ?>
373 <p class="fct-thank-you-page-order-items-list-variant-title">
374 - <?php echo esc_html(!empty($item['variation_display_title']) ? $item['variation_display_title'] : $item['title']); ?>
375 </p>
376 <?php endif; ?>
377 <?php if ($item['payment_type'] === 'subscription' && !empty($item['payment_info'])): ?>
378 <p class="fct-thank-you-page-order-items-list-payment-info">
379 <?php echo wp_kses_post($item['payment_info']) ?>
380 </p>
381 <?php endif; ?>
382 <?php $this->renderBundleProducts($item); ?>
383 </div>
384 <div class="fct-thank-you-page-order-items-list-price">
385 <div class="fct-thank-you-page-order-items-list-price-inner">
386 <?php echo esc_html($item['formatted_total']); ?>
387 </div>
388 </div>
389 </div>
390
391 <div class="fct-thank-you-page-order-items-tax-info">
392 <?php if ($fctTaxDisplayMode !== 'simplified'): ?>
393 <?php $this->renderItemTaxPill($item, $order); ?>
394 <?php endif; ?>
395 <?php if (!empty($item['setup_info'])): ?>
396 <div class="fct-thank-you-page-order-items-setup-fee">
397 <div class="setup-fee">
398 <?php echo esc_html(Arr::get($item, 'other_info.signup_fee_name', '')); ?>
399 </div>
400
401 <div class="setup-fee-amount">
402 <?php echo esc_html(Helper::toDecimal(Arr::get($item, 'other_info.signup_fee', ''))); ?>
403 </div>
404 </div>
405 <?php endif; ?>
406 <?php if ($fctTaxDisplayMode !== 'simplified'): ?>
407 <?php $this->renderItemSetupFeeTaxPills($item, $order); ?>
408 <?php endif; ?>
409 </div>
410 <?php endforeach; ?>
411
412 <?php $this->renderOrderTotal(); ?>
413
414 <!-- tax note -->
415 <?php $this->renderTaxNote(); ?>
416
417 </div>
418 <?php
419 }
420
421 public function renderThankYouPageInstructions()
422 {
423 $order = Arr::get($this->config, 'order', null);
424 if (!$order) {
425 return;
426 }
427 $transaction = $order->getLatestTransaction();
428 $methodSlug = '';
429 $thankYouPageInstructions = '';
430 if ($transaction && !empty($transaction->payment_method)) {
431 $methodSlug = $transaction->payment_method;
432 }
433 if (GatewayManager::has($methodSlug)) {
434 $gatewayInstance = GatewayManager::getInstance($methodSlug);
435 if ($gatewayInstance && isset($gatewayInstance->settings)) {
436 $gatewaySettings = (array) $gatewayInstance->settings->get();
437 $thankYouPageInstructions = Arr::get($gatewaySettings, 'thank_you_page_instructions', '');
438 }
439 }
440
441 if (!empty($thankYouPageInstructions)) : ?>
442
443 <div style="max-width: 620px; margin: 15px auto 0; font-family: Arial, Helvetica, sans-serif;">
444 <div style="font-size: 14px; color: #2F3448; padding: 12px 0; border-top: 1px solid #e7eaee;">
445 <?php echo wp_kses_post($thankYouPageInstructions); ?>
446 </div>
447 </div>
448 <?php endif;
449 }
450
451 public function renderOrderTotal()
452 {
453 ?>
454 <div class="fct-thank-you-page-order-items-total">
455 <?php $this->renderSubtotal(); ?>
456 <?php $this->renderDiscount(); ?>
457 <?php $this->renderShipping(); ?>
458 <?php $this->renderFees(); ?>
459 <?php $this->renderTaxSummaryBox(); ?>
460
461 <?php $this->renderProrateCredit(); ?>
462 <?php $this->renderRefund(); ?>
463 <?php $this->renderTotal(); ?>
464 <?php $this->renderPaymentMethod(); ?>
465 </div>
466 <?php
467 }
468
469 public function renderTaxNote()
470 {
471 $order = Arr::get($this->config, 'order', null);
472 if ($order->isReverseChargeTaxOrder()): ?>
473 <div style="text-align: right; font-size: 14px; margin-top: 10px;">
474 <?php echo '*' . esc_html(TaxModule::getReverseChargeNoticeText()) ?>
475 </div>
476 <?php
477 endif;
478 }
479
480 public function renderSubtotal()
481 {
482 $order = Arr::get($this->config, 'order', null);
483 if ($order->subtotal != $order->total_amount || $order->tax_total > 0): ?>
484 <div class="fct-meta-line fct-thank-you-page-order-items-total-subtotal">
485 <div class="fct-meta-line-label fct-thank-you-page-order-items-total-label">
486 <?php echo esc_html__('Subtotal', 'fluent-cart'); ?>
487 </div>
488 <div class="fct-meta-line-value fct-thank-you-page-order-items-total-value"><?php echo esc_html(Helper::toDecimal($order->subtotal)); ?></div>
489 </div>
490 <?php endif;
491 }
492
493 public function renderDiscount()
494 {
495 $order = Arr::get($this->config, 'order', null);
496 $prorateCredit = (int) Arr::get($order->config, 'prorate_credit', 0);
497 $upgradeDiscount = $order->manual_discount_total - $prorateCredit;
498 // When the prorate credit IS the whole discount, label the row directly
499 // instead of showing "Discount" with a single redundant breakdown row.
500 $onlyProrateCredit = $prorateCredit > 0 && $upgradeDiscount <= 0 && $order->coupon_discount_total <= 0;
501
502 if ($order->manual_discount_total + $order->coupon_discount_total > 0): ?>
503 <div class="fct-meta-line fct-thank-you-page-order-items-total-discount">
504 <div class="fct-meta-line-label fct-thank-you-page-order-items-total-label">
505 <?php echo $onlyProrateCredit ? esc_html__('Prorate Credit', 'fluent-cart') : esc_html__('Discount', 'fluent-cart'); ?>
506 </div>
507 <div class="fct-meta-line-value fct-thank-you-page-order-items-total-value">
508 - <?php echo esc_html(Helper::toDecimal($order->manual_discount_total + $order->coupon_discount_total)); ?>
509 </div>
510 </div>
511 <?php if ($prorateCredit > 0 && $upgradeDiscount > 0): ?>
512 <div class="fct-meta-line" style="padding-left:12px;">
513 <div class="fct-meta-line-label" style="font-size:12px;color:rgb(107,114,128);">
514 <?php echo esc_html__('Upgrade Discount', 'fluent-cart'); ?>
515 </div>
516 <div class="fct-meta-line-value" style="font-size:12px;color:rgb(107,114,128);">
517 <?php echo esc_html(Helper::toDecimal($upgradeDiscount)); ?>
518 </div>
519 </div>
520 <?php endif; ?>
521 <?php if ($prorateCredit > 0 && !$onlyProrateCredit): ?>
522 <div class="fct-meta-line" style="padding-left:12px;">
523 <div class="fct-meta-line-label" style="font-size:12px;color:rgb(107,114,128);">
524 <?php echo esc_html__('Prorate Credit', 'fluent-cart'); ?>
525 </div>
526 <div class="fct-meta-line-value" style="font-size:12px;color:rgb(107,114,128);">
527 <?php echo esc_html(Helper::toDecimal($prorateCredit)); ?>
528 </div>
529 </div>
530 <?php endif; ?>
531 <?php endif;
532 }
533
534 public function renderProrateCredit()
535 {
536 // Rendered as a sub-row inside renderDiscount.
537 }
538
539 public function renderShipping()
540 {
541 $order = Arr::get($this->config, 'order', null);
542
543 if ($order->shipping_total <= 0) {
544 return;
545 }
546 $displayShipping = (int) $order->shipping_total;
547 if ($order->isReverseChargeTaxOrder()) {
548 $rcAdj = (int) Arr::get($this->getMemoizedTaxSummary($order), 'rcShippingAdjustment', 0);
549 if ($rcAdj > 0) {
550 $displayShipping = max(0, $displayShipping - $rcAdj);
551 }
552 }
553 $shippingMethodTitle = (string) Arr::get($order->config, 'shipping_method_title', '');
554 ?>
555 <div class="fct-meta-line fct-thank-you-page-order-items-total-shipping">
556 <div class="fct-meta-line-label fct-thank-you-page-order-items-total-label">
557 <?php echo esc_html__('Shipping', 'fluent-cart'); ?>
558 <?php if ($shippingMethodTitle): ?>
559 <span class="fct-shipping-method-name"><?php echo esc_html($shippingMethodTitle); ?></span>
560 <?php endif; ?>
561 </div>
562 <div class="fct-meta-line-value fct-thank-you-page-order-items-total-value"><?php echo esc_html(Helper::toDecimal($displayShipping)); ?></div>
563 </div>
564 <?php
565 }
566
567 public function renderFees()
568 {
569 $order = Arr::get($this->config, 'order', null);
570 if (!$order || $order->fee_total <= 0) {
571 return;
572 }
573 $feeItems = $order->feeItems()->get();
574 foreach ($feeItems as $feeItem): ?>
575 <div class="fct-meta-line fct-thank-you-page-order-items-total-fee">
576 <div class="fct-meta-line-label fct-thank-you-page-order-items-total-label">
577 <?php echo esc_html($feeItem->title); ?>
578 </div>
579 <div class="fct-meta-line-value fct-thank-you-page-order-items-total-value">
580 <?php echo esc_html(Helper::toDecimal($feeItem->subtotal)); ?>
581 </div>
582 </div>
583 <?php endforeach;
584 }
585
586 public function renderRefund()
587 {
588 $order = Arr::get($this->config, 'order', null);
589
590 if ($order->total_refund > 0): ?>
591 <div class="fct-meta-line fct-thank-you-page-order-items-total-refund">
592 <div class="fct-meta-line-label fct-thank-you-page-order-items-total-label">
593 <?php echo esc_html__('Refund', 'fluent-cart'); ?>
594 </div>
595 <div class="fct-meta-line-value fct-thank-you-page-order-items-total-value">
596 - <?php echo esc_html(Helper::toDecimal($order->total_refund)); ?>
597 </div>
598 </div>
599 <?php endif;
600 }
601
602 public function renderTotal()
603 {
604 $order = Arr::get($this->config, 'order', null);
605 $displayTotal = (int) $order->total_amount - (int) $order->total_refund;
606 if ($order->isReverseChargeTaxOrder()) {
607 $rcAdj = (int) Arr::get($this->getMemoizedTaxSummary($order), 'rcTotalAdjustment', 0);
608 if ($rcAdj > 0) {
609 $displayTotal = max(0, $displayTotal - $rcAdj);
610 }
611 }
612 ?>
613 <div class="fct-meta-line fct-thank-you-page-order-items-total-total">
614 <div class="fct-meta-line-label fct-thank-you-page-order-items-total-label">
615 <?php echo esc_html__('Total', 'fluent-cart'); ?>
616 </div>
617 <div class="fct-meta-line-value fct-thank-you-page-order-items-total-value">
618 <?php echo esc_html(Helper::toDecimal($displayTotal)); ?>
619 </div>
620 </div>
621 <?php
622 }
623
624 public function renderPaymentMethod()
625 {
626 $order = Arr::get($this->config, 'order', null);
627 $transaction = $order->getLatestTransaction();
628 ?>
629 <div class="fct-meta-line fct-thank-you-page-order-items-total-payment-method">
630 <div class="fct-meta-line-label fct-thank-you-page-order-items-total-label">
631 <?php echo esc_html__('Payment Method', 'fluent-cart'); ?>
632 </div>
633 <div class="fct-meta-line-value fct-thank-you-page-order-items-total-value">
634 <?php if ($transaction->card_last_4) :
635 echo esc_html($transaction->card_brand) . ' ' . esc_html($transaction->card_last_4);
636 else:
637 $title = $transaction->payment_method;
638 $gateway = GatewayManager::getInstance($transaction->payment_method);
639 $title = $gateway ? $gateway->getMeta('title') : $title;
640 echo esc_html($title);
641 endif; ?>
642 </div>
643 </div>
644 <?php
645 }
646
647 public function renderSubscriptionItems()
648 {
649 $order = Arr::get($this->config, 'order', null);
650 $subscriptions = $order->subscriptions;
651
652 if ($subscriptions->count() == 0) {
653 return;
654 }
655 ?>
656 <div class="fct-thank-you-page-order-items-subscriptions">
657 <p class="fct-thank-you-page-order-items-subscriptions-heading">
658 <?php echo esc_html__('Subscription Details', 'fluent-cart'); ?>
659 </p>
660
661 <table class="fct-thank-you-page-order-items-subscriptions-table" role="presentation">
662 <tbody>
663 <?php foreach ($subscriptions as $subs): ?>
664 <tr>
665 <td class="fct-thank-you-page-order-items-subscriptions-table-file">
666 <p>
667 <?php echo esc_html($subs->display_item_name); ?>
668 </p>
669 </td>
670
671 <td class="fct-thank-you-page-order-items-subscriptions-billing-infos">
672 <div>
673 <?php if (!empty($subs->payment_info)) : ?>
674 <span>
675 <?php echo $subs->payment_info; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
676 </span>
677 <?php endif; ?>
678
679 <?php if (!empty($subs->next_billing_date)) : ?>
680 <p class="fct-thank-you-page-order-items-subscriptions-billing-infos-next-billing"><?php
681 echo sprintf(
682 /* translators: 1: Next billing date */
683 esc_html__('- Auto renews on %1$s', 'fluent-cart'),
684 esc_html(
685 \FluentCart\App\Services\DateTime\DateTime::gmtToTimezone($subs->next_billing_date)->format('M d, Y h:i A')
686 )
687 );
688 ?>
689 </p>
690 <?php endif; ?>
691 </div>
692 </td>
693 </tr>
694 <?php endforeach; ?>
695 </tbody>
696 </table>
697 </div>
698
699
700 <?php
701 // App::make('view')->render('invoice.parts.subscription_items', [
702 // 'subscriptions' => $order->subscriptions,
703 // 'order' => $order
704 // ]);
705 }
706
707 public function renderDownloads()
708 {
709 $order = Arr::get($this->config, 'order', null);
710 $downloads = $order->getDownloads();
711 if (!$downloads) {
712 return;
713 }
714 ?>
715 <div class="fct-thank-you-page-order-items-downloads">
716 <p class="fct-thank-you-page-order-items-downloads-heading">
717 <?php echo esc_html__('Downloads', 'fluent-cart'); ?>
718 </p>
719
720 <table class="fct-thank-you-page-order-items-downloads-table"
721 role="presentation">
722 <tbody>
723 <tr>
724 <td>
725 <table role="presentation" width="100%">
726 <tbody>
727 <?php foreach ($downloads as $downloadItem): ?>
728 <tr>
729 <td>
730 <?php if ($downloadItem['downloads']): ?>
731
732 <table role="presentation" width="100%">
733 <tbody>
734 <?php foreach ($downloadItem['downloads'] as $download): ?>
735 <tr>
736 <td class="fct-thank-you-page-order-items-downloads-table-file">
737 <p>
738 <?php echo esc_html($download['title']); ?>
739 <?php if ($download['file_size']): ?>
740 <span>(<?php echo esc_html(Helper::readableFileSize($download['file_size'])); ?>)</span>
741 <?php endif; ?>
742 </p>
743 </td>
744 <td class="fct-thank-you-page-order-items-downloads-button">
745 <a href="<?php echo esc_url($download['download_url'] ?? ''); ?>">
746 <?php echo esc_html__('Download', 'fluent-cart'); ?>
747 </a>
748 </td>
749 </tr>
750 <?php endforeach; ?>
751 </tbody>
752 </table>
753
754 <?php endif; ?>
755
756 </td>
757 </tr>
758 <?php endforeach; ?>
759 </tbody>
760 </table>
761 </td>
762 </tr>
763 </tbody>
764 </table>
765 </div>
766
767 <?php $this->renderDownloadsNotice(); ?>
768
769 <?php
770 }
771
772 public function renderDownloadsNotice($show_notice = false)
773 {
774 $showNotice = $show_notice ?? true;
775 ?>
776 <?php if (!$showNotice) {
777 return;
778 } ?>
779 <table
780 class="fct-thank-you-page-order-items-downloads-notice"
781 role="presentation">
782 <tbody>
783 <tr>
784 <td>
785 <p class="fct-thank-you-page-order-items-downloads-notice-title">
786 <?php echo esc_html__('Important', 'fluent-cart'); ?>
787 </p>
788 <p class="fct-thank-you-page-order-items-downloads-notice-content">
789 <?php echo esc_html__('This download link is valid for 7 days. After that, you can download the files again from your account
790 on our website.', 'fluent-cart'); ?>
791 </p>
792 </td>
793 </tr>
794 </tbody>
795 </table>
796 <?php
797 }
798
799 public function renderLicenseNotice($show_notice = false)
800 {
801 $showNotice = $show_notice ?? true;
802 ?>
803 <?php if (!$showNotice) {
804 return;
805 } ?>
806 <table
807 class="fct-thank-you-page-order-items-downloads-notice"
808 role="presentation">
809 <tbody>
810 <tr>
811 <td>
812 <p class="fct-thank-you-page-order-items-downloads-notice-title">
813 <?php echo esc_html__('Important', 'fluent-cart'); ?>
814 </p>
815 <p class="fct-thank-you-page-order-items-downloads-notice-content">
816 <?php echo esc_html__('This download link is valid for 7 days. After that, you can download the files again from your account on our website.', 'fluent-cart'); ?>
817 </p>
818 </td>
819 </tr>
820 </tbody>
821 </table>
822 <?php
823 }
824
825 public function renderLicenses()
826 {
827 $order = Arr::get($this->config, 'order', null);
828 $licenses = $order->getLicenses();
829 if (!$licenses || $licenses->count() == 0) {
830 return;
831 }
832 ?>
833 <div class="fct-thank-you-page-order-items-licenses">
834 <p class="fct-thank-you-page-order-items-licenses-heading">
835 <?php echo esc_html__('Licenses', 'fluent-cart'); ?>
836 </p>
837 <table class="fct-thank-you-page-order-items-licenses-table" role="presentation">
838 <tbody>
839 <tr>
840 <td>
841 <table role="presentation">
842 <tbody>
843
844 <?php foreach ($licenses as $license): ?>
845 <tr>
846 <td class="fct-thank-you-page-order-items-licenses-table-file">
847 <p>
848 <?php echo esc_html($license->productVariant->variation_title); ?>:
849 <?php echo esc_html($license->license_key); ?>
850 </p>
851 </td>
852 </tr>
853 <?php endforeach; ?>
854 </tbody>
855 </table>
856 </td>
857 </tr>
858 </tbody>
859 </table>
860 </div>
861
862 <?php $this->renderLicenseNotice(); ?>
863 <?php
864 }
865
866 public function renderAddress()
867 {
868 $order = Arr::get($this->config, 'order', null);
869 ?>
870 <div class="fct-thank-you-page-order-items-addresses">
871 <?php $this->renderBillToAddress(); ?>
872 <?php if ($order->fulfillment_type === 'physical') : ?>
873 <?php $this->renderShipToAddress(); ?>
874 <?php endif; ?>
875 </div>
876 <?php
877 }
878
879 public function renderBillToAddress()
880 {
881 $order = Arr::get($this->config, 'order', null);
882 ?>
883 <div class="fct-thank-you-page-order-items-addresses-bill-to">
884 <h5>
885 <?php echo esc_html__('Bill To', 'fluent-cart'); ?>
886 </h5>
887 <?php
888 if (!empty($order->billing_address)) :
889 ?>
890 <div class="fct-thank-you-page-order-items-addresses-bill-to-address">
891 <?php echo esc_html($order->billing_address->getAddressAsText()); ?>
892 </div>
893
894 <div class="fct-thank-you-page-order-items-addresses-bill-to-email">
895 <?php echo esc_html($order->customer->email); ?>
896 </div>
897 <?php else: ?>
898 <div class="fct-thank-you-page-order-items-addresses-bill-to-name">
899 <?php echo esc_html($order->customer->full_name); ?>
900 </div>
901 <div class="fct-thank-you-page-order-items-addresses-bill-to-email">
902 <?php echo esc_html($order->customer->email); ?>
903 </div>
904 <?php endif; ?>
905 <?php
906 $phoneNumber = Arr::get($order->billing_address->meta ?? [], 'other_data.phone', '');
907 if ($phoneNumber !== ''):
908 ?>
909 <div class="fct-thank-you-page-order-items-addresses-bill-to-phone">
910 <?php echo esc_html($phoneNumber); ?>
911 </div>
912 <?php endif; ?>
913 <?php
914 $companyName = $order->billing_address
915 ? Arr::get($order->billing_address->meta ?? [], 'other_data.company_name', '')
916 : '';
917 if ($companyName === '') {
918 $companyName = $order->getCustomerTaxName();
919 }
920 if ($companyName !== ''):
921 ?>
922 <div class="fct-thank-you-page-order-items-addresses-bill-to-company-name">
923 <?php echo esc_html($companyName); ?>
924 </div>
925 <?php endif; ?>
926 <?php
927 $legalRegId = $order->billing_address
928 ? Arr::get($order->billing_address->meta ?? [], 'other_data.legal_registration_id', '')
929 : '';
930 if ($legalRegId === '') {
931 $legalRegId = Arr::get($order->getBusinessInfo(), 'legal_registration_id', '');
932 }
933 if ($legalRegId !== ''):
934 ?>
935 <div class="fct-thank-you-page-order-items-addresses-bill-to-legal-reg">
936 <?php echo esc_html__('Reg. ID', 'fluent-cart') . ': ' . esc_html($legalRegId); ?>
937 </div>
938 <?php endif; ?>
939 <div class="fct-thank-you-page-order-items-addresses-bill-to-vat-number">
940 <?php
941 $vatNumber = $order->getCustomerTaxNumber();
942 if ($vatNumber !== '') {
943 $vatLabel = __('VAT/Tax ID', 'fluent-cart');
944 echo esc_html($vatLabel) . ': ' . esc_html($vatNumber);
945 }
946 ?>
947 </div>
948 <?php
949 $reverseChargeDeclaration = Arr::get($order->getBusinessInfo(), 'reverse_charge_declaration', '');
950 if ($reverseChargeDeclaration !== ''):
951 ?>
952 <div class="fct-thank-you-page-order-items-addresses-bill-to-reverse-charge">
953 <strong><?php echo esc_html__('Reverse Charge Declaration', 'fluent-cart'); ?>:</strong>
954 <?php echo esc_html($reverseChargeDeclaration); ?>
955 </div>
956 <?php endif; ?>
957 </div>
958 <?php
959 }
960
961 public function renderShipToAddress()
962 {
963 $order = Arr::get($this->config, 'order', null);
964 ?>
965 <div class="fct-thank-you-page-order-items-addresses-ship-to">
966 <h5 class="fct-thank-you-page-order-items-addresses-ship-to-title">
967 <?php echo esc_html__('Ship To', 'fluent-cart'); ?>
968 </h5>
969 <?php if (!empty($order->shipping_address)) : ?>
970 <div class="fct-thank-you-page-order-items-addresses-ship-to-address">
971 <?php echo esc_html($order->shipping_address->getAddressAsText()); ?>
972 </div>
973 <!-- show phone number -->
974 <?php
975 $phone = Arr::get($order->shipping_address->meta ?? [], 'other_data.phone', '');
976 if ($phone !== ''):?>
977 <div class="fct-thank-you-page-order-items-addresses-ship-to-phone">
978 <?php echo esc_html($phone); ?>
979 </div>
980 <?php endif; ?>
981 <?php else: ?>
982 <div class="fct-thank-you-page-order-items-addresses-ship-to-name">
983 <?php echo esc_html($order->customer->full_name); ?>
984 </div>
985 <div class="fct-thank-you-page-order-items-addresses-ship-to-email">
986 <?php echo esc_html($order->customer->email); ?>
987 </div>
988 <?php endif; ?>
989 </div>
990 <?php
991 }
992
993 public function renderFooter()
994 {
995 ?>
996 <div class="fct-thank-you-page-footer">
997 <?php do_action('fluent_cart/receipt/thank_you/before_footer_buttons', $this->config); ?>
998 <?php $this->renderViewOrderButton(); ?>
999 <?php $this->renderDownloadReceiptButton(); ?>
1000 <?php do_action('fluent_cart/receipt/thank_you/after_footer_buttons', $this->config); ?>
1001 </div>
1002 <?php
1003 }
1004
1005 public function renderViewOrderButton()
1006 {
1007 $order = Arr::get($this->config, 'order', null);
1008 $profilePage = $this->settings->getCustomerProfilePage();
1009
1010 ?>
1011 <a
1012 class="fct-thank-you-page-view-order-button"
1013 href="<?php echo esc_url($profilePage . 'order/' . $order->uuid); ?>">
1014 <?php echo esc_html__('View Order', 'fluent-cart'); ?>
1015 </a>
1016 <?php
1017 }
1018
1019 public function renderDownloadReceiptButton()
1020 {
1021 $order = Arr::get($this->config, 'order', null);
1022 ?>
1023 <a
1024 class="fct-thank-you-page-download-receipt-button"
1025 href="<?php echo esc_url(\FluentCart\App\Services\URL::appendQueryParams(
1026 home_url(),
1027 [
1028 'fluent-cart' => 'receipt',
1029 'order_hash' => $order->uuid,
1030 'download' => 1
1031 ]
1032 )) ?>">
1033 <?php echo esc_html__('Download Receipt', 'fluent-cart'); ?>
1034 </a>
1035 <?php
1036 }
1037
1038 /**
1039 * Build a parent → bundle items relationship from flat order items
1040 *
1041 * Converts a flat order items list into:
1042 * - Parent items
1043 * - Each parent contains a ` bundle_items ` array
1044 *
1045 * @param array $orderItems
1046 * @return array
1047 */
1048 protected function buildBundleItemsTree($orderItems)
1049 {
1050 if (!$orderItems) {
1051 return [];
1052 }
1053
1054 $parents = [];
1055 $childrenByParent = [];
1056
1057 // Separate parents and children
1058 foreach ($orderItems as $item) {
1059 $parentId = Arr::get($item, 'line_meta.bundle_parent_item_id', null);
1060
1061 // If bundle child → group by parent ID
1062 if ($parentId) {
1063 $childrenByParent[$parentId][] = $item;
1064
1065 // Otherwise it's a parent item
1066 } else {
1067 $item['bundle_items'] = [];
1068 $parents[$item['id']] = $item;
1069 }
1070 }
1071
1072 // Attach children to their parent
1073 foreach ($childrenByParent as $parentId => $children) {
1074 if (isset($parents[$parentId])) {
1075 $parents[$parentId]['bundle_items'] = $children;
1076 }
1077 }
1078
1079 // Re-index a final array
1080 return array_values($parents);
1081 }
1082
1083 public function renderBundleProducts($item)
1084 {
1085 //dd($item);
1086 if (!$item['bundle_items']) {
1087 return;
1088 }
1089
1090 $total = count($item['bundle_items']);
1091 ?>
1092 <div class="fct-bundle-products" data-fluent-cart-collapsibles>
1093 <h4 class="fct-bundle-products-title">
1094 <?php echo esc_html__('Bundle of', 'fluent-cart') . ':'; ?>
1095 </h4>
1096
1097 <div class="fct-bundle-products-list">
1098 <?php foreach (array_slice($item['bundle_items'], 0, 2) as $bundleItem): ?>
1099 <p>
1100 <?php echo esc_html(Arr::get($bundleItem, 'title', '')); ?>
1101 </p>
1102 <?php endforeach; ?>
1103
1104 <?php if ($total > 2): ?>
1105 <div class="fct-bundle-products-more">
1106 <div class="fct-bundle-products-more-list">
1107 <?php foreach (array_slice($item['bundle_items'], 2) as $bundleItem): ?>
1108 <p>
1109 <?php echo esc_html(Arr::get($bundleItem, 'title', '')); ?>
1110 </p>
1111 <?php endforeach; ?>
1112 </div>
1113 </div>
1114 <?php endif; ?>
1115 </div>
1116
1117 <?php if ($total > 2) : ?>
1118 <a href="#" class="fct-see-more-btn" data-fluent-cart-collapsible-toggle>
1119 <span class="see-more-text">
1120 <?php echo esc_html__('See More', 'fluent-cart'); ?>
1121 <svg xmlns="http://www.w3.org/2000/svg" width="12" height="7" viewBox="0 0 12 7" fill="none">
1122 <path d="M0.75 0.75L5.04289 5.04289C5.37623 5.37623 5.54289 5.54289 5.75 5.54289C5.95711 5.54289 6.12377 5.37623 6.45711 5.04289L10.75 0.75" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
1123 </svg>
1124 </span>
1125
1126 <span class="see-less-text">
1127 <?php echo esc_html__('See Less', 'fluent-cart'); ?>
1128 <svg xmlns="http://www.w3.org/2000/svg" width="12" height="7" viewBox="0 0 14 8" fill="none">
1129 <path d="M0.75 6.54297L6.04289 1.25008C6.37623 0.916742 6.54289 0.750076 6.75 0.750076C6.95711 0.750076 7.12377 0.916742 7.45711 1.25008L12.75 6.54297" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
1130 </svg>
1131 </span>
1132 </a>
1133 <?php endif; ?>
1134 </div>
1135 <?php
1136 }
1137
1138 public function renderTaxSummaryBox()
1139 {
1140 $order = Arr::get($this->config, 'order', null);
1141 $summary = $this->getMemoizedTaxSummary($order);
1142 if (!$summary['shouldRender']) {
1143 return;
1144 }
1145
1146 $tyIsSimplified = (($summary['displayMode'] ?? '') === 'simplified') && !empty($summary['simpleLine']);
1147
1148 if ($tyIsSimplified) :
1149 ?>
1150 <div class="fct-meta-line fct-thank-you-tax-simple-line">
1151 <div class="fct-meta-line-label fct-thank-you-page-order-items-total-label fct-thank-you-tax-simple-label">
1152 <span><?php echo esc_html($summary['simpleLine']['label']); ?></span>
1153 <?php if (!empty($summary['simpleLine']['hasDetails'])) : ?>
1154 <details class="fct-thank-you-tax-details">
1155 <summary class="fct-thank-you-tax-toggle"><?php echo esc_html__('See details', 'fluent-cart'); ?> &#9662;</summary>
1156 <div class="fct-thank-you-tax-summary fct-thank-you-tax-floating">
1157 <?php $this->renderTaxBreakdownCardInner($summary); ?>
1158 </div>
1159 </details>
1160 <?php endif; ?>
1161 </div>
1162 <div class="fct-meta-line-value fct-thank-you-page-order-items-total-value"><?php echo esc_html($summary['simpleLine']['value']); ?></div>
1163 </div>
1164 <?php
1165 else :
1166 ?>
1167 <div class="fct-thank-you-tax-summary">
1168 <?php $this->renderTaxBreakdownCardInner($summary); ?>
1169 </div>
1170 <?php
1171 endif;
1172 }
1173
1174 private function renderTaxBreakdownCardInner($summary)
1175 {
1176 ?>
1177 <div class="fct-thank-you-tax-summary-header">
1178 <span class="fct-thank-you-tax-summary-title">
1179 <?php if (!empty(Arr::get($summary, 'foldedRateLines', []))): ?>
1180 <?php echo esc_html__('Tax breakdown by rate', 'fluent-cart'); ?>
1181 <?php else: ?>
1182 <?php echo esc_html__('TAX SUMMARY', 'fluent-cart'); ?>
1183 <?php endif; ?>
1184 </span>
1185 <span class="fct-item-tax-hint" tabindex="0"
1186 aria-label="<?php echo esc_attr__('Tax breakdown explanation', 'fluent-cart'); ?>">
1187 <span class="fct-item-tax-hint-icon">i</span>
1188 <span class="fct-item-tax-hint-tooltip">
1189 <?php echo esc_html__('Inclusive tax is embedded in item prices. Exclusive tax is added on top.', 'fluent-cart'); ?>
1190 </span>
1191 </span>
1192 </div>
1193
1194 <?php
1195 $tyFoldedRateLines = Arr::get($summary, 'foldedRateLines', []);
1196 $tyIsReverseCharge = !empty($summary['isReverseCharge']);
1197 $rcReversedTotal = (int) Arr::get($summary, 'reversedTaxTotal', 0);
1198 $rcReversedShipping = (int) Arr::get($summary, 'reversedShippingTax', 0);
1199 $rcReversedValue = $rcReversedTotal > 0
1200 ? Helper::toDecimal($rcReversedTotal)
1201 : __('Charge reversed', 'fluent-cart');
1202 ?>
1203 <?php if (!empty($tyFoldedRateLines)): ?>
1204 <?php
1205 $tyIncludedInPrices = (int) Arr::get($summary, 'includedInPrices', 0);
1206 $tyPayableTax = (int) Arr::get($summary, 'payableTax', 0);
1207 $tyTotalOrderTax = (int) Arr::get($summary, 'totalOrderTax', 0);
1208 ?>
1209 <div style="display:grid;grid-template-columns:minmax(0,1fr) 92px 64px;column-gap:12px;align-items:start;">
1210 <span style="min-width:0;font-size:11px;text-transform:uppercase;letter-spacing:0.04em;color:#94a3b8;"><?php echo esc_html__('Rate', 'fluent-cart'); ?></span>
1211 <span style="text-align:right;font-size:11px;text-transform:uppercase;letter-spacing:0.04em;color:#94a3b8;white-space:nowrap;"><?php echo esc_html__('Taxable base', 'fluent-cart'); ?></span>
1212 <span style="text-align:right;font-size:11px;text-transform:uppercase;letter-spacing:0.04em;color:#94a3b8;white-space:nowrap;"><?php echo esc_html__('Tax', 'fluent-cart'); ?></span>
1213 </div>
1214 <?php foreach ($tyFoldedRateLines as $tyFoldedLine): ?>
1215 <div class="fct-thank-you-tax-summary-row<?php echo !empty($tyFoldedLine['inclusive']) ? ' fct-thank-you-tax-summary-row--muted' : ''; ?>" style="display:grid;grid-template-columns:minmax(0,1fr) 92px 64px;column-gap:12px;align-items:start;">
1216 <span style="min-width:0;white-space:normal;overflow-wrap:anywhere;word-break:break-word;"><?php echo esc_html($tyFoldedLine['label']); ?></span>
1217 <span style="text-align:right;color:#94a3b8;white-space:nowrap;"><?php echo esc_html(Helper::toDecimal($tyFoldedLine['base'])); ?></span>
1218 <span style="text-align:right;white-space:nowrap;"><?php echo esc_html(Helper::toDecimal($tyFoldedLine['tax'])); ?></span>
1219 </div>
1220 <?php endforeach; ?>
1221 <?php if ($tyIsReverseCharge): ?>
1222 <div class="fct-thank-you-tax-summary-row fct-thank-you-tax-summary-row--total">
1223 <span><?php echo esc_html__('VAT reversed', 'fluent-cart'); ?></span>
1224 <span><?php echo esc_html($rcReversedValue); ?></span>
1225 </div>
1226 <?php else: ?>
1227 <div class="fct-thank-you-tax-summary-row fct-thank-you-tax-summary-row--total">
1228 <span><?php echo esc_html__('Total tax', 'fluent-cart'); ?></span>
1229 <span><?php echo esc_html(Helper::toDecimal($tyTotalOrderTax)); ?></span>
1230 </div>
1231 <?php if ($tyIncludedInPrices > 0): ?>
1232 <div class="fct-thank-you-tax-summary-row fct-thank-you-tax-summary-row--muted">
1233 <span><?php echo esc_html__('of which included in prices', 'fluent-cart'); ?></span>
1234 <span><?php echo esc_html(Helper::toDecimal($tyIncludedInPrices)); ?></span>
1235 </div>
1236 <?php endif; ?>
1237 <?php if ($tyPayableTax > 0 && $tyIncludedInPrices > 0): ?>
1238 <div class="fct-thank-you-tax-summary-row fct-thank-you-tax-summary-row--total">
1239 <span><?php echo esc_html__('Payable now (added)', 'fluent-cart'); ?></span>
1240 <span><?php echo esc_html(Helper::toDecimal($tyPayableTax)); ?></span>
1241 </div>
1242 <?php endif; ?>
1243 <?php endif; ?>
1244 <?php elseif ($tyIsReverseCharge): ?>
1245 <?php if ($summary['showRcShippingRow'] && $rcReversedShipping > 0): ?>
1246 <div class="fct-thank-you-tax-summary-row fct-thank-you-tax-summary-row--muted">
1247 <span><?php echo esc_html__('Added on shipping', 'fluent-cart'); ?></span>
1248 <span style="text-decoration:line-through;opacity:0.6;"><?php echo esc_html(Helper::toDecimal($rcReversedShipping)); ?></span>
1249 </div>
1250 <?php endif; ?>
1251 <div class="fct-thank-you-tax-summary-row fct-thank-you-tax-summary-row--total">
1252 <span><?php echo esc_html__('Tax reversed', 'fluent-cart'); ?></span>
1253 <span><?php echo esc_html($rcReversedValue); ?></span>
1254 </div>
1255 <?php else: ?>
1256 <?php
1257 $tyFeeRows = Arr::get($summary, 'feeTaxLineRows', []);
1258 $taxRateLines = Arr::get($summary, 'taxRateLines', []);
1259 $shippingTaxLines = Arr::get($summary, 'shippingTaxLines', []);
1260 ?>
1261 <?php
1262 $productTaxRowCount = !empty($taxRateLines)
1263 ? count($taxRateLines)
1264 : (int) ($summary['inclusiveTax'] > 0) + (int) ($summary['exclusiveTax'] > 0);
1265 $rowCount = $productTaxRowCount + count($tyFeeRows) + (int) ($summary['shippingTax'] > 0);
1266 $shouldShowBreakdown = !empty($taxRateLines)
1267 || !empty($shippingTaxLines)
1268 || $rowCount >= 2
1269 || ($rowCount === 1 && !($summary['payableTax'] > 0 || $summary['inclusiveTax'] > 0 || (int) Arr::get($summary, 'inclusiveFeeTax', 0) > 0));
1270 ?>
1271 <?php if (!empty($taxRateLines) && $shouldShowBreakdown): ?>
1272 <?php foreach ($taxRateLines as $taxLine) : ?>
1273 <div class="fct-thank-you-tax-summary-row<?php echo !empty($taxLine['inclusive']) ? ' fct-thank-you-tax-summary-row--muted' : ''; ?>">
1274 <span><?php echo esc_html($taxLine['label']); ?></span>
1275 <span><?php echo esc_html(Helper::toDecimal($taxLine['order_tax'])); ?></span>
1276 </div>
1277 <?php endforeach; ?>
1278 <?php endif; ?>
1279 <?php if (empty($taxRateLines) && $summary['inclusiveTax'] > 0 && $shouldShowBreakdown): ?>
1280 <div class="fct-thank-you-tax-summary-row fct-thank-you-tax-summary-row--muted">
1281 <span><?php echo esc_html__('Included in item prices', 'fluent-cart'); ?></span>
1282 <span><?php echo esc_html(Helper::toDecimal($summary['inclusiveTax'])); ?></span>
1283 </div>
1284 <?php endif; ?>
1285 <?php if (empty($taxRateLines) && $summary['exclusiveTax'] > 0 && $shouldShowBreakdown): ?>
1286 <div class="fct-thank-you-tax-summary-row">
1287 <span><?php echo esc_html__('Added on products', 'fluent-cart'); ?></span>
1288 <span><?php echo esc_html(Helper::toDecimal($summary['exclusiveTax'])); ?></span>
1289 </div>
1290 <?php endif; ?>
1291 <?php if ($shouldShowBreakdown) : ?>
1292 <?php foreach ($tyFeeRows as $feeRow) : ?>
1293 <div class="fct-thank-you-tax-summary-row<?php echo $feeRow['inclusive'] ? ' fct-thank-you-tax-summary-row--muted' : ''; ?>">
1294 <span><?php echo esc_html($feeRow['display_label']); ?></span>
1295 <span><?php echo esc_html(Helper::toDecimal($feeRow['tax_amount'])); ?></span>
1296 </div>
1297 <?php endforeach; ?>
1298 <?php endif; ?>
1299 <?php if ($summary['shippingTax'] > 0 && $shouldShowBreakdown):
1300 $isShippingInclusive = (bool) Arr::get($summary, 'isShippingInclusive', false);
1301 $shippingRowClass = 'fct-thank-you-tax-summary-row' . ($isShippingInclusive ? ' fct-thank-you-tax-summary-row--muted' : '');
1302 if (!empty($shippingTaxLines)):
1303 foreach ($shippingTaxLines as $shLine): ?>
1304 <div class="<?php echo esc_attr($shippingRowClass); ?>">
1305 <span><?php echo esc_html($shLine['label']); ?></span>
1306 <span><?php echo esc_html(Helper::toDecimal($shLine['shipping_tax'])); ?></span>
1307 </div>
1308 <?php endforeach;
1309 else: ?>
1310 <div class="<?php echo esc_attr($shippingRowClass); ?>">
1311 <span>
1312 <?php if ($isShippingInclusive): ?>
1313 <?php echo esc_html__('Included in shipping prices', 'fluent-cart'); ?>
1314 <?php else: ?>
1315 <?php echo esc_html__('Added on shipping', 'fluent-cart'); ?>
1316 <?php endif; ?>
1317 </span>
1318 <span><?php echo esc_html(Helper::toDecimal($summary['shippingTax'])); ?></span>
1319 </div>
1320 <?php endif; ?>
1321 <?php endif; ?>
1322 <?php if ($summary['payableTax'] > 0): ?>
1323 <div class="fct-thank-you-tax-summary-row fct-thank-you-tax-summary-row--total">
1324 <span><?php echo esc_html__('Total payable tax', 'fluent-cart'); ?></span>
1325 <span><?php echo esc_html(Helper::toDecimal($summary['payableTax'])); ?></span>
1326 </div>
1327 <?php endif; ?>
1328 <?php if ($summary['inclusiveTax'] > 0 || $summary['inclusiveFeeTax'] > 0): ?>
1329 <div class="fct-thank-you-tax-summary-row fct-thank-you-tax-summary-row--muted">
1330 <span><?php echo esc_html__('Total tax in this order', 'fluent-cart'); ?></span>
1331 <span><?php echo esc_html(Helper::toDecimal($summary['totalOrderTax'])); ?></span>
1332 </div>
1333 <?php endif; ?>
1334 <?php endif; ?>
1335 <?php
1336 }
1337
1338 public function renderItemTaxPill($item, $order)
1339 {
1340 $rates = TaxSummaryHelper::getItemTaxRates($item);
1341 $isReversed = $order->isReverseChargeTaxOrder();
1342 $rcMode = $order->getOrderRcMode();
1343
1344 if (!empty($rates)) {
1345 $this->renderTaxRatePills($rates, $isReversed, $rcMode);
1346 return;
1347 }
1348
1349 // Fallback: existing aggregate pill for old orders without tax_config
1350 $taxAmount = (int) ($item['tax_amount'] ?? 0);
1351 if ($taxAmount <= 0) {
1352 return;
1353 }
1354 $isInclusive = TaxSummaryHelper::isPrimaryTaxInclusive($order);
1355 $pillClass = $isInclusive ? 'fct-tax-pill--inclusive' : 'fct-tax-pill--exclusive';
1356 $reversedClass = ($isReversed && (!$isInclusive || $rcMode === 'dynamic')) ? ' is-reversed' : '';
1357 ?>
1358 <div class="fct-item-tax-pills">
1359 <div class="fct-item-tax-pill-row">
1360 <span class="fct-tax-pill <?php echo esc_attr($pillClass); ?>">
1361 <?php echo $isInclusive ? esc_html__('Incl.', 'fluent-cart') : esc_html__('Add.', 'fluent-cart'); ?>
1362 </span>
1363 <span class="fct-item-tax-pill-amount <?php echo esc_attr(($isInclusive ? 'is-inclusive' : 'is-exclusive') . $reversedClass); ?>">
1364 <?php if ($isInclusive): ?>
1365 <?php echo esc_html__('incl.', 'fluent-cart'); ?> <?php echo esc_html(Helper::toDecimal($taxAmount)); ?>
1366 <?php else: ?>
1367 + <?php echo esc_html(Helper::toDecimal($taxAmount)); ?>
1368 <?php endif; ?>
1369 </span>
1370 </div>
1371 </div>
1372 <?php
1373 }
1374
1375 public function renderItemSetupFeeTaxPills($item, $order)
1376 {
1377 $isSubscription = $item['payment_type'] === 'subscription'
1378 || !empty(Arr::get($item, 'other_info.signup_fee'));
1379
1380 if (!$isSubscription) {
1381 return;
1382 }
1383
1384 $isReversed = $order->isReverseChargeTaxOrder();
1385 $rcMode = $order->getOrderRcMode();
1386 $signupFeeItem = null;
1387 if ($order->order_items) {
1388 $signupFeeItem = $order->order_items
1389 ->where('payment_type', 'signup_fee')
1390 ->where('object_id', $item['object_id'])
1391 ->first();
1392 }
1393
1394 if ($signupFeeItem) {
1395 $rates = TaxSummaryHelper::getItemTaxRates($signupFeeItem->toArray());
1396 if (!empty($rates)) {
1397 $this->renderTaxRatePills($rates, $isReversed, $rcMode);
1398 return;
1399 }
1400 }
1401
1402 $signupFeeTax = (int) Arr::get($item, 'other_info.signup_fee_tax', 0);
1403 if ($signupFeeTax <= 0) {
1404 return;
1405 }
1406 $sfIsInclusive = TaxSummaryHelper::isPrimaryTaxInclusive($order);
1407 $reversedClass = ($isReversed && (!$sfIsInclusive || $rcMode === 'dynamic')) ? ' is-reversed' : '';
1408 ?>
1409 <div class="fct-item-tax-pills">
1410 <div class="fct-item-tax-pill-row">
1411 <span class="fct-item-tax-pill-amount<?php echo esc_attr($reversedClass); ?>"><?php
1412 /* translators: %1$s: formatted setup fee tax amount */
1413 echo sprintf(esc_html__('Setup fee tax: %1$s', 'fluent-cart'), esc_html(Helper::toDecimal($signupFeeTax)));
1414 ?></span>
1415 </div>
1416 </div>
1417 <?php
1418 }
1419
1420 private function renderTaxRatePills(array $rates, bool $isReversed = false, string $rcMode = 'fixed')
1421 {
1422 ?>
1423 <div class="fct-item-tax-pills">
1424 <?php foreach ($rates as $rate) : ?>
1425 <?php
1426 $pillClass = $rate['inclusive'] ? 'fct-tax-pill--inclusive' : 'fct-tax-pill--exclusive';
1427 $percent = rtrim(rtrim(number_format($rate['rate_percent'], 3, '.', ''), '0'), '.');
1428 $rateIsInclusive = !empty($rate['inclusive']);
1429 $rateReversedClass = ($isReversed && (!$rateIsInclusive || $rcMode === 'dynamic')) ? ' is-reversed' : '';
1430 ?>
1431 <div class="fct-item-tax-pill-row">
1432 <span class="fct-tax-pill <?php echo esc_attr($pillClass); ?>">
1433 <?php echo esc_html($rate['label']) . ' (' . esc_html($percent) . '%)'; ?>
1434 </span>
1435 <span class="fct-item-tax-pill-amount <?php echo esc_attr(($rate['inclusive'] ? 'is-inclusive' : 'is-exclusive') . $rateReversedClass); ?>">
1436 <?php if ($rate['inclusive']): ?>
1437 <?php echo esc_html__('incl.', 'fluent-cart'); ?> <?php echo esc_html(Helper::toDecimal($rate['tax_amount'])); ?>
1438 <?php else: ?>
1439 + <?php echo esc_html(Helper::toDecimal($rate['tax_amount'])); ?>
1440 <?php endif; ?>
1441 </span>
1442 </div>
1443 <?php endforeach; ?>
1444 </div>
1445 <?php
1446 }
1447
1448 }
1449