PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.7.1
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.7.1
1.7.1 1.7.0 1.6.6 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 All 51 releases
← All changes | app/Services/Renderer/Receipt/ReceiptRenderer.php +460 -110 1.3.23 → 1.7.1 View file →
@@ -2,9 +2,8 @@
2 2
3 3 namespace FluentCart\App\Services\Renderer\Receipt;
4 4
5 5 use FluentCart\App\Helpers\Helper;
6 -use FluentCart\App\Models\OrderMeta;
7 6 use FluentCart\Framework\Support\Arr;
8 7
9 8 use FluentCart\Api\StoreSettings;
10 9 use FluentCart\App\Helpers\AddressHelper;
@@ -9,8 +8,9 @@
9 8 use FluentCart\Api\StoreSettings;
10 9 use FluentCart\App\Helpers\AddressHelper;
11 10 use FluentCart\App\Modules\Tax\TaxModule;
12 11 use FluentCart\App\Services\DateTime\DateTime;
12 +use FluentCart\App\Services\DateTime\DateFormatter;
13 13
14 14 class ReceiptRenderer
15 15 {
16 16 protected $config = null;
@@ -24,8 +24,10 @@
24 24 protected $vat_tax_id = null;
25 25
26 26 protected $orderTz;
27 27
28 + private $fctTaxSummaryCache = [];
29 +
28 30 public function __construct($config = [])
29 31 {
30 32 $this->config = $config;
31 33
@@ -36,8 +38,20 @@
36 38
37 39 $this->orderTz = Arr::get($this->config, 'user_tz', 'UTC');
38 40 }
39 41
42 + private function getMemoizedTaxSummary($order)
43 + {
44 + if (!$order) {
45 + return TaxSummaryHelper::computeTaxSummary($order);
46 + }
47 + $id = (int) $order->id;
48 + if (!isset($this->fctTaxSummaryCache[$id])) {
49 + $this->fctTaxSummaryCache[$id] = TaxSummaryHelper::computeTaxSummary($order);
50 + }
51 + return $this->fctTaxSummaryCache[$id];
52 + }
53 +
40 54 public function wrapperStart()
41 55 {
42 56 ?>
43 57 <div
@@ -70,14 +84,12 @@
70 84 if (!$order) {
71 85 return;
72 86 }
73 87
74 - $vatTaxId = OrderMeta::query()->where('order_id', $order->id)->where('meta_key', 'vat_tax_id')->first();
75 - $this->vat_tax_id = $vatTaxId ? $vatTaxId->meta_value : '';
88 + $this->vat_tax_id = $order->getCustomerTaxNumber();
76 89
77 - $this->settings = new StoreSettings();
78 90 $profilePage = $this->settings->getCustomerProfilePage();
79 - $orderTaxRates = $order->orderTaxRates->first();
91 + $orderTaxRates = $order->getPrimaryOrderTaxRate();
80 92
81 93 ?>
82 94
83 95 <style>
@@ -207,9 +219,9 @@
207 219
208 220 public function renderStoreTaxInformation()
209 221 {
210 222 $order = Arr::get($this->config, 'order', null);
211 - $orderTaxRates = $order->orderTaxRates->first();
223 + $orderTaxRates = $order->getPrimaryOrderTaxRate();
212 224 $storeVatNumber = Arr::get($orderTaxRates->meta ?? [], 'store_vat_number', '');
213 225 $taxcountry = Arr::get($orderTaxRates->meta ?? [], 'tax_country', '');
214 226 if (!empty($storeVatNumber)): ?>
215 227 <span class="fct_invoice_tax_content" style="font-weight: 500; font-size: 14px;">
@@ -231,12 +243,14 @@
231 243 <?php echo esc_html__('Order At', 'fluent-cart'); ?>
232 244 </p>
233 245 <p style="white-space: nowrap; font-weight: bold; color: #000; text-align: right; margin: 0;font-size:14px;">
234 246 <?php
235 - $date = wp_date(
236 - get_option('date_format'),
247 + // Through DateFormatter so the store's format and timezone settings
248 + // reach this too; orderTz is only consulted on the Browser source.
249 + $date = DateFormatter::format(
237 250 DateTime::anyTimeToGmt($order->created_at)->getTimestamp(),
238 - new \DateTimeZone($this->orderTz)
251 + false,
252 + $this->orderTz
239 253 );
240 254 echo esc_html(Helper::translateNumber($date));
241 255 ?>
242 256 </p>
@@ -309,9 +323,9 @@
309 323 style="margin-bottom: 3px;">
310 324 <?php echo esc_html($this->settings->getFormattedFullAddress()); ?>
311 325 </div>
312 326 <?php
313 - $orderTaxRates = $order->orderTaxRates->first();
327 + $orderTaxRates = $order->getPrimaryOrderTaxRate();
314 328 $storeVatNumber = Arr::get($orderTaxRates->meta ?? [], 'store_vat_number', '');
315 329 $taxCountry = Arr::get($orderTaxRates->meta ?? [], 'tax_country', '');
316 330 if (!empty($storeVatNumber)): ?>
317 331 <div
@@ -324,9 +338,9 @@
324 338
325 339 public function renderBillToAddress()
326 340 {
327 341 $order = Arr::get($this->config, 'order', null);
328 - $orderTaxRates = $order->orderTaxRates->first();
342 + $orderTaxRates = $order->getPrimaryOrderTaxRate();
329 343 ?>
330 344 <div
331 345 class="fct-receipt-page-order-items-addresses-bill-to"
332 346 style="border-radius: 5px;print-color-adjust: exact;">
@@ -341,15 +355,8 @@
341 355 class="fct-receipt-page-order-items-addresses-bill-to-address"
342 356 style="margin-bottom: 3px;">
343 357 <?php echo esc_html($order->billing_address->getAddressAsText()); ?>
344 358 </div>
345 - <?php if (!empty($this->vat_tax_id)) : ?>
346 - <div
347 - class="fct-receipt-page-order-items-addresses-bill-to-vat-number"
348 - style="margin-bottom: 3px;">
349 - <?php echo esc_html__('VAT/Tax ID:', 'fluent-cart') . ' ' . esc_html($this->vat_tax_id); ?>
350 - </div>
351 - <?php endif; ?>
352 359 <div
353 360 class="fct-receipt-page-order-items-addresses-bill-to-email"
354 361 style="margin-top: 10px;">
355 362 <?php echo esc_html($order->customer->email); ?>
@@ -364,28 +371,50 @@
364 371 style="margin-top: 3px;">
365 372 <?php echo esc_html($phoneNumber); ?>
366 373 </div>
367 374 <?php endif; ?>
375 + <?php
376 + $companyName = Arr::get($order->billing_address->meta ?? [], 'other_data.company_name', '');
377 + if ($companyName === '') {
378 + $companyName = $order->getCustomerTaxName();
379 + }
380 + if ($companyName !== ''):
381 + ?>
368 382 <div class="fct-receipt-page-order-items-addresses-bill-to-company-name">
369 - <?php
370 - $companyName = Arr::get($order->billing_address->meta ?? [], 'other_data.company_name', '');
371 - if ($companyName == '') {
372 - $companyName = Arr::get($orderTaxRates->meta ?? [], 'vat_reverse.name', '');
373 - }
374 - echo esc_html($companyName);
375 - ?>
383 + <?php echo esc_html($companyName); ?>
376 384 </div>
385 + <?php endif; ?>
386 + <?php
387 + $legalRegId = Arr::get($order->billing_address->meta ?? [], 'other_data.legal_registration_id', '');
388 + if ($legalRegId === '') {
389 + $legalRegId = Arr::get($order->getBusinessInfo(), 'legal_registration_id', '');
390 + }
391 + if ($legalRegId !== ''):
392 + ?>
393 + <div class="fct-receipt-page-order-items-addresses-bill-to-legal-reg" style="margin-top: 3px;">
394 + <?php echo esc_html__('Reg. ID', 'fluent-cart') . ': ' . esc_html($legalRegId); ?>
395 + </div>
396 + <?php endif; ?>
377 397 <div
378 398 class="fct-receipt-page-order-items-addresses-bill-to-vat-number"
379 399 style="margin-top: 5px;">
380 400 <?php
381 - $vatNumber = Arr::get($orderTaxRates->meta ?? [], 'vat_reverse.vat_number', '');
382 -
401 + $vatNumber = $order->getCustomerTaxNumber();
383 402 if ($vatNumber !== '') {
384 - echo esc_html__('EU VAT', 'fluent-cart') . ': ' . esc_html($vatNumber);
403 + $vatLabel = __('VAT/Tax ID', 'fluent-cart');
404 + echo esc_html($vatLabel) . ': ' . esc_html($vatNumber);
385 405 }
386 406 ?>
387 407 </div>
408 + <?php
409 + $reverseChargeDeclaration = Arr::get($order->getBusinessInfo(), 'reverse_charge_declaration', '');
410 + if ($reverseChargeDeclaration !== ''):
411 + ?>
412 + <div class="fct-receipt-page-order-items-addresses-bill-to-reverse-charge" style="margin-top: 5px;">
413 + <strong><?php echo esc_html__('Reverse Charge Declaration', 'fluent-cart'); ?>:</strong>
414 + <?php echo esc_html($reverseChargeDeclaration); ?>
415 + </div>
416 + <?php endif; ?>
388 417
389 418 <?php else: ?>
390 419 <div
391 420 class="fct-receipt-page-order-items-addresses-bill-to-name"
@@ -391,15 +420,8 @@
391 420 class="fct-receipt-page-order-items-addresses-bill-to-name"
392 421 style="margin-top: 10px;">
393 422 <?php echo esc_html($order->customer->full_name); ?>
394 423 </div>
395 - <?php if (!empty($vat_tax_id)) : ?>
396 - <div
397 - class="fct-receipt-page-order-items-addresses-bill-to-vat-number"
398 - style="margin-bottom: 3px;">
399 - <?php echo esc_html__('VAT/Tax ID:', 'fluent-cart') . ' ' . esc_html($vat_tax_id); ?>
400 - </div>
401 - <?php endif; ?>
402 424 <div
403 425 class="fct-receipt-page-order-items-addresses-bill-to-email"
404 426 style="margin-top: 3px;">
405 427 <?php echo esc_html($order->customer->email); ?>
@@ -488,34 +510,61 @@
488 510 </thead>
489 511 <tbody>
490 512 <?php
491 513 $orderItems = $order->order_items->toArray();
492 - $transaction = $order->getLatestTransaction();
514 + $isReversed = $order->isReverseChargeTaxOrder();
515 + $rcMode = $order->getOrderRcMode();
516 + $fctReceiptTaxDisplayMode = TaxSummaryHelper::getTaxDisplayMode();
493 517
494 518 foreach ($orderItems as $item) :
519 + if (($item['payment_type'] ?? '') === 'fee') {
520 + continue;
521 + }
522 + $itemRates = TaxSummaryHelper::getItemTaxRates($item);
523 + $itemBorder = empty($itemRates) ? '1px solid #dee2e6' : 'none';
495 524 ?>
496 525 <tr>
497 - <td style="font-size:15px;padding: 12px 8px;border: none;border-bottom: 1px solid #dee2e6;print-color-adjust: exact;">
526 + <td style="font-size:15px;padding: 12px 8px;border: none;border-bottom: <?php echo esc_attr($itemBorder); ?>;print-color-adjust: exact;">
498 527 <?php echo esc_html($item['post_title']); ?>
499 528 <br>
500 529 <?php if (!empty($item['title'])) : ?>
501 - <small style="font-size: 13px;color: #758195;">- <?php echo esc_html($item['title']); ?></small>
530 + <small style="font-size: 13px;color: #758195;">- <?php echo esc_html(!empty($item['variation_display_title']) ? $item['variation_display_title'] : $item['title']); ?></small>
502 531 <br>
503 532 <?php endif; ?>
504 533 <?php if (!empty($item['payment_info'])) : ?>
505 534 <small style="font-size: 13px;color: #758195;"><?php echo esc_html($item['payment_info']); ?></small>
506 535 <?php endif; ?>
536 + <?php if ($fctReceiptTaxDisplayMode !== 'simplified' && empty($itemRates) && !empty($item['tax_amount'])) : ?>
537 + <small style="font-size: 12px; color: #94a3b8; display:block; margin-top:2px;">
538 + <?php
539 + /* translators: %1$s: formatted tax amount */
540 + echo esc_html(sprintf(__('Tax: %1$s', 'fluent-cart'), Helper::toDecimal((int) $item['tax_amount']))); ?>
541 + </small>
542 + <?php endif; ?>
507 543 </td>
508 - <td style="padding: 12px 8px;border: none;border-bottom: 1px solid #dee2e6;text-align: right;">
544 + <td style="padding: 12px 8px;border: none;border-bottom: <?php echo esc_attr($itemBorder); ?>;text-align: right; vertical-align: top;">
509 545 <?php echo esc_html(Helper::translateNumber($item['quantity'])); ?>
510 546 </td>
511 - <td style="padding: 12px 8px;border: none;border-bottom: 1px solid #dee2e6;text-align: right">
547 + <?php $couponDiscount = (int) Arr::get($item['line_meta'] ?? [], 'coupon_discount', 0); ?>
548 + <td style="padding: 12px 8px;border: none;border-bottom: <?php echo esc_attr($itemBorder); ?>;text-align: right; vertical-align: top;">
512 549 <?php echo esc_html(\FluentCart\Api\CurrencySettings::getFormattedPrice($item['unit_price'], null, false, true, true)); ?>
513 550 </td>
514 - <td style="padding: 12px 8px;border: none;border-bottom: 1px solid #dee2e6;text-align: right">
551 + <td style="padding: 12px 8px;border: none;border-bottom: <?php echo esc_attr($itemBorder); ?>;text-align: right; vertical-align: top;">
552 + <?php if ($couponDiscount > 0): ?>
553 + <span style="text-decoration:line-through;opacity:0.5;font-size:11px;display:block;">
554 + <?php echo esc_html(Helper::toDecimal($item['subtotal'])); ?>
555 + </span>
556 + <?php endif; ?>
515 557 <?php echo esc_html($item['formatted_total']); ?>
516 558 </td>
517 559 </tr>
560 + <?php if ($fctReceiptTaxDisplayMode !== 'simplified' && !empty($itemRates)) : ?>
561 + <tr>
562 + <td colspan="4" style="padding:0 8px 8px 8px;border:none;border-bottom:1px solid #dee2e6;">
563 + <?php echo $this->renderTaxRatePills($itemRates, $isReversed, $rcMode); ?>
564 + </td>
565 + </tr>
566 + <?php endif; ?>
518 567 <?php endforeach; ?>
519 568 </tbody>
520 569 </table>
521 570 <?php endif;
@@ -529,16 +578,16 @@
529 578 class="fct-receipt-page-order-items-footer"
530 579 style="margin-top: 20px;">
531 580 <table
532 581 class="fct-receipt-page-order-items-footer-table"
533 - style="max-width: 250px;width: 100%;margin-left: auto;border-collapse: collapse;background: #f8f9fa;print-color-adjust: exact;border: none;">
582 + style="max-width: 250px;width: 100%;margin-left: auto;border-collapse: collapse;background: #f8f9fa;print-color-adjust: exact;border: none; border-radius: 8px;">
534 583 <tbody>
535 584 <?php $this->renderSubtotal(); ?>
536 585 <?php $this->renderDiscount(); ?>
537 586 <?php $this->renderShipping(); ?>
538 587 <?php $this->renderFees(); ?>
539 - <?php $this->renderTaxTotal(); ?>
540 - <?php $this->renderShippingTax(); ?>
588 + <?php $this->renderTaxSummaryBox(); ?>
589 + <?php $this->renderProrateCredit(); ?>
541 590 <?php $this->renderRefund(); ?>
542 591 <?php $this->renderTotal(); ?>
543 592 <?php $this->renderAmountPaid(); ?>
544 593 </tbody>
@@ -551,12 +600,12 @@
551 600 {
552 601 $order = Arr::get($this->config, 'order', null);
553 602 if ($order->subtotal != ($order->total_amount - $order->total_refund) || $order->tax_total > 0): ?>
554 603 <tr>
555 - <td style="padding: 8px 20px 8px 0;text-align: right;border: none;">
604 + <td style="text-align: right;border: none; padding-top: 20px;">
556 605 <?php echo esc_html__('Subtotal', 'fluent-cart'); ?>
557 606 </td>
558 - <td style="font-weight:700;padding: 8px 8px 8px 0;width: 100px;text-align: right;border: none;">
607 + <td style="font-weight:700; padding-right: 8px; padding-top: 20px;width: 100px;text-align: right;border: none;">
559 608 <?php echo esc_html(\FluentCart\App\Helpers\Helper::toDecimal($order->subtotal));
560 609 ?>
561 610 </td>
562 611 </tr>
@@ -565,33 +614,80 @@
565 614
566 615 public function renderDiscount()
567 616 {
568 617 $order = Arr::get($this->config, 'order', null);
618 + $prorateCredit = (int) \FluentCart\Framework\Support\Arr::get($order->config, 'prorate_credit', 0);
619 + $upgradeDiscount = $order->manual_discount_total - $prorateCredit;
620 + // When the prorate credit IS the whole discount, label the row directly
621 + // instead of showing "Discount" with a single redundant breakdown row.
622 + $onlyProrateCredit = $prorateCredit > 0 && $upgradeDiscount <= 0 && $order->coupon_discount_total <= 0;
623 +
569 624 if ($order->manual_discount_total + $order->coupon_discount_total > 0): ?>
570 - <tr>
571 - <td style="padding: 8px 20px 8px 0;text-align: right;border: none;">
572 - <?php echo esc_html__('Discount', 'fluent-cart'); ?>
573 - </td>
574 - <td style="padding: 8px 8px 8px 0;width: 100px;text-align: right;border: none;">
575 - - <?php echo esc_html(\FluentCart\App\Helpers\Helper::toDecimal($order->manual_discount_total + $order->coupon_discount_total)); ?>
576 - </td>
577 - </tr>
625 + <tr>
626 + <td style="text-align: right;border: none;">
627 + <?php echo $onlyProrateCredit ? esc_html__('Prorate Credit', 'fluent-cart') : esc_html__('Discount', 'fluent-cart'); ?>
628 + </td>
629 + <td style="padding-right:8px; width: 100px;text-align: right;border: none;">
630 + - <?php echo esc_html(\FluentCart\App\Helpers\Helper::toDecimal($order->manual_discount_total + $order->coupon_discount_total)); ?>
631 + </td>
632 + </tr>
633 + <?php if ($prorateCredit > 0 && $upgradeDiscount > 0): ?>
634 + <tr>
635 + <td style="padding-left:20px;text-align: right;border: none;font-size:12px;color:rgb(107,114,128);">
636 + <?php echo esc_html__('Upgrade Discount', 'fluent-cart'); ?>
637 + </td>
638 + <td style="padding-right:8px;width: 100px;text-align: right;border: none;font-size:12px;color:rgb(107,114,128);">
639 + <?php echo esc_html(\FluentCart\App\Helpers\Helper::toDecimal($upgradeDiscount)); ?>
640 + </td>
641 + </tr>
642 + <?php endif; ?>
643 + <?php if ($prorateCredit > 0 && !$onlyProrateCredit): ?>
644 + <tr>
645 + <td style="padding-left:20px;text-align: right;border: none;font-size:12px;color:rgb(107,114,128);">
646 + <?php echo esc_html__('Prorate Credit', 'fluent-cart'); ?>
647 + </td>
648 + <td style="padding-right:8px;width: 100px;text-align: right;border: none;font-size:12px;color:rgb(107,114,128);">
649 + <?php echo esc_html(\FluentCart\App\Helpers\Helper::toDecimal($prorateCredit)); ?>
650 + </td>
651 + </tr>
652 + <?php endif; ?>
578 653 <?php endif;
579 654 }
580 655
656 + public function renderProrateCredit()
657 + {
658 + // Rendered as a sub-row inside renderDiscount.
659 + }
660 +
581 661 public function renderShipping()
582 662 {
583 663 $order = Arr::get($this->config, 'order', null);
584 - if ($order->shipping_total > 0): ?>
585 - <tr>
586 - <td style="padding: 8px 20px 8px 0;text-align: right;border: none;">
587 - <?php echo esc_html__('Shipping', 'fluent-cart'); ?>
588 - </td>
589 - <td style="padding: 8px 8px 8px 0;width: 100px;text-align: right;border: none;">
590 - <?php echo esc_html(\FluentCart\App\Helpers\Helper::toDecimal($order->shipping_total)); ?>
591 - </td>
592 - </tr>
593 - <?php endif;
664 + if ($order->shipping_total <= 0) {
665 + return;
666 + }
667 + $displayShipping = (int) $order->shipping_total;
668 + if ($order->isReverseChargeTaxOrder()) {
669 + $rcAdj = (int) Arr::get($this->getMemoizedTaxSummary($order), 'rcShippingAdjustment', 0);
670 + if ($rcAdj > 0) {
671 + $displayShipping = max(0, $displayShipping - $rcAdj);
672 + }
673 + }
674 + $shippingMethodTitle = (string) Arr::get($order->config, 'shipping_method_title', '');
675 + ?>
676 + <tr>
677 + <td style="padding: 8px 20px 8px 0;text-align: right;border: none;">
678 + <?php echo esc_html__('Shipping', 'fluent-cart'); ?>
679 + <?php if ($shippingMethodTitle): ?>
680 + <span style="display:block;font-size:12px;color:rgb(107,114,128);line-height:18px;">
681 + <?php echo esc_html($shippingMethodTitle); ?>
682 + </span>
683 + <?php endif; ?>
684 + </td>
685 + <td style="padding: 8px 8px 8px 0;width: 100px;text-align: right;border: none;">
686 + <?php echo esc_html(\FluentCart\App\Helpers\Helper::toDecimal($displayShipping)); ?>
687 + </td>
688 + </tr>
689 + <?php
594 690 }
595 691
596 692 public function renderFees()
597 693 {
@@ -611,42 +707,8 @@
611 707 </tr>
612 708 <?php endforeach;
613 709 }
614 710
615 - public function renderTaxTotal()
616 - {
617 - $order = Arr::get($this->config, 'order', null);
618 - if ($order->tax_total > 0): ?>
619 - <tr>
620 - <td style="padding: 8px 20px 8px 0;text-align: right;border: none;">
621 - <?php echo esc_html__('Tax', 'fluent-cart');
622 - echo esc_html($order->tax_behavior == 2 ? __('(Included)', 'fluent-cart') : __('(Excluded)', 'fluent-cart'));
623 - ?>
624 - </td>
625 - <td style="padding: 8px 8px 8px 0;width: 100px;text-align: right;border: none;">
626 - <?php echo esc_html(\FluentCart\App\Helpers\Helper::toDecimal($order->tax_total)); ?>
627 - </td>
628 - </tr>
629 - <?php endif;
630 - }
631 -
632 - public function renderShippingTax()
633 - {
634 - $order = Arr::get($this->config, 'order', null);
635 - if ($order->shipping_tax > 0): ?>
636 - <tr>
637 - <td style="padding: 8px 20px 8px 0;text-align: right;border: none;">
638 - <?php echo esc_html__('Shipping Tax', 'fluent-cart');
639 - echo esc_html($order->tax_behavior == 2 ? __('(Included)', 'fluent-cart') : __('(Excluded)', 'fluent-cart'));
640 - ?>
641 - </td>
642 - <td style="padding: 8px 8px 8px 0;width: 100px;text-align: right;border: none;">
643 - <?php echo esc_html(\FluentCart\App\Helpers\Helper::toDecimal($order->shipping_tax)); ?>
644 - </td>
645 - </tr>
646 - <?php endif;
647 - }
648 -
649 711 public function renderRefund()
650 712 {
651 713 $order = Arr::get($this->config, 'order', null);
652 714 if ($order->total_refund > 0): ?>
@@ -663,15 +725,22 @@
663 725
664 726 public function renderTotal()
665 727 {
666 728 $order = Arr::get($this->config, 'order', null);
729 + $displayTotal = (int) $order->total_amount - (int) $order->total_refund;
730 + if ($order->isReverseChargeTaxOrder()) {
731 + $rcAdj = (int) Arr::get($this->getMemoizedTaxSummary($order), 'rcTotalAdjustment', 0);
732 + if ($rcAdj > 0) {
733 + $displayTotal = max(0, $displayTotal - $rcAdj);
734 + }
735 + }
667 736 ?>
668 737 <tr style="font-weight: bold;font-size: 14px;">
669 - <td style="font-weight:500;padding: 8px 20px 8px 0;text-align: right;border:none;">
738 + <td style="font-weight:500;text-align: right;border:none;">
670 739 <?php echo esc_html__('Total', 'fluent-cart'); ?>
671 740 </td>
672 - <td style="padding: 8px 8px 8px 0;width: 100px;text-align: right;border:none;">
673 - <?php echo esc_html(\FluentCart\Api\CurrencySettings::getFormattedPrice(($order->total_amount - $order->total_refund), null, false, true, true)); ?>
741 + <td style="width: 100px;text-align: right;border:none; padding-right: 8px;">
742 + <?php echo esc_html(\FluentCart\Api\CurrencySettings::getFormattedPrice($displayTotal, null, false, true, true)); ?>
674 743 </td>
675 744 </tr>
676 745 <?php
677 746 }
@@ -680,12 +749,12 @@
680 749 {
681 750 $order = Arr::get($this->config, 'order', null);
682 751 ?>
683 752 <tr style="font-weight: bold;font-size: 14px;">
684 - <td style="font-weight:500;padding: 8px 20px 8px 0;text-align: right;border:none;">
753 + <td style="font-weight:500;text-align: right;border:none; padding-bottom: 20px">
685 754 <?php echo esc_html__('Amount Paid', 'fluent-cart'); ?>
686 755 </td>
687 - <td style="padding: 8px 8px 8px 0;width: 100px;text-align: right;border:none;">
756 + <td style="width: 100px;text-align: right;border:none;padding-bottom: 20px; padding-right: 8px;">
688 757 <?php echo esc_html(\FluentCart\Api\CurrencySettings::getFormattedPrice(($order->total_paid - $order->total_refund), null, false, true, true)); ?>
689 758 </td>
690 759 </tr>
691 760 <?php
@@ -693,14 +762,12 @@
693 762
694 763 public function renderTaxNote()
695 764 {
696 765 $order = Arr::get($this->config, 'order', null);
697 - $orderTaxRates = $order->orderTaxRates->first();
698 - $taxtotal = $order->tax_total + $order->shipping_tax;
699 - if (Arr::get($orderTaxRates->meta ?? [], 'vat_reverse.valid') && !$taxtotal): ?>
766 + if ($order->isReverseChargeTaxOrder()): ?>
700 767
701 768 <div style="text-align: right; font-size: 14px; margin-top: 10px;">
702 - <?php echo esc_html__('* Tax to be paid on reverse charge basis', 'fluent-cart'); ?>
769 + <?php echo '*' . esc_html(TaxModule::getReverseChargeNoticeText()); ?>
703 770 </div>
704 771
705 772 <?php endif;
706 773 }
@@ -745,12 +812,14 @@
745 812 <?php echo esc_html($transaction->getPaymentMethodText()); ?>
746 813 </td>
747 814 <td style="padding: 10px;border:none;border-bottom: 1px solid #dee2e6;text-align: center;">
748 815 <?php
749 - $date = wp_date(
750 - get_option('date_format'),
816 + // Same route as the Order At header above, or
817 + // one receipt renders two different formats.
818 + $date = DateFormatter::format(
751 819 DateTime::anyTimeToGmt($transaction->created_at)->getTimestamp(),
752 - new \DateTimeZone($this->orderTz)
820 + false,
821 + $this->orderTz
753 822 );
754 823 echo esc_html(Helper::translateNumber($date));
755 824 ?>
756 825 </td>
@@ -789,5 +858,286 @@
789 858 <span><?php echo esc_html__('Please try to complete payment again from here!', 'fluent-cart'); ?></span>
790 859 <a href="<?php echo esc_url($custom_payment_url ?? ''); ?>"><?php echo esc_url($custom_payment_url); ?></a>
791 860 </div>
792 861 <?php }
862 +
863 + private function renderTaxRatePills(array $rates, bool $isReversed = false, string $rcMode = 'fixed')
864 + {
865 + $html = '';
866 + foreach ($rates as $rate) {
867 + $isInclusive = !empty($rate['inclusive']);
868 + $badgeBg = $isInclusive ? '#EAF3DE' : '#FAEEDA';
869 + $textColor = $isInclusive ? '#3B6D11' : '#854F0B';
870 + $shouldStrike = $isReversed && (!$isInclusive || $rcMode === 'dynamic');
871 + $amountStyle = 'color:' . esc_attr($textColor) . ';font-size:11px;font-weight:500;'
872 + . ($shouldStrike ? 'text-decoration:line-through;opacity:0.6;' : '');
873 + /* translators: %1$s: formatted tax amount (e.g. $12.00) */
874 + $amountDisplay = $isInclusive
875 + ? esc_html(sprintf(__('incl. %1$s', 'fluent-cart'), Helper::toDecimal($rate['tax_amount'])))
876 + : esc_html(Helper::toDecimal($rate['tax_amount']));
877 + $html .= '<table width="100%" cellpadding="0" cellspacing="0" style="border:none;margin-top:3px;">';
878 + $html .= '<tr>';
879 + $html .= '<td style="padding:0;border:none;">';
880 + $html .= '<span style="background-color:' . esc_attr($badgeBg) . ';color:' . esc_attr($textColor) . ';font-size:11px;padding:2px 7px;border-radius:4px;display:inline-block;">' . esc_html($rate['label']) . ' (' . esc_html(number_format((float) $rate['rate_percent'], 0)) . '%)</span>';
881 + $html .= '</td>';
882 + $html .= '<td style="text-align:right;padding:0;border:none;white-space:nowrap;">';
883 + $html .= '<span style="' . $amountStyle . '">' . $amountDisplay . '</span>';
884 + $html .= '</td>';
885 + $html .= '</tr>';
886 + $html .= '</table>';
887 + }
888 + return $html;
889 + }
890 +
891 + public function renderTaxSummaryBox()
892 + {
893 + $order = Arr::get($this->config, 'order', null);
894 + $summary = $this->getMemoizedTaxSummary($order);
895 + if (!$summary['shouldRender']) {
896 + return;
897 + }
898 + ?>
899 + <tr>
900 + <td colspan="2" style="padding: 6px 8px;">
901 + <table width="100%" cellpadding="0" cellspacing="0" style="border:1px solid #e2e8f0; border-radius:6px; border-collapse:separate; background:#ffffff; -webkit-print-color-adjust:exact; print-color-adjust:exact;">
902 + <tr>
903 + <td style="padding:6px 8px 6px 0;">
904 + <table width="100%" cellpadding="0" cellspacing="0" style="border:none;border-collapse:collapse;">
905 + <?php if (($summary['displayMode'] ?? '') === 'simplified' && !empty($summary['simpleLine'])): ?>
906 + <tr>
907 + <td style="padding:4px 0 3px 8px; font-size:11px; font-weight:600; color:#1e293b; text-align:left;">
908 + <?php echo esc_html($summary['simpleLine']['label']); ?>
909 + </td>
910 + <td style="padding:4px 0 3px; font-size:11px; font-weight:600; color:#1e293b; text-align:right;">
911 + <?php echo esc_html($summary['simpleLine']['value']); ?>
912 + </td>
913 + </tr>
914 + <?php endif; ?>
915 + <?php if (($summary['displayMode'] ?? '') !== 'simplified'): ?>
916 + <tr>
917 + <td colspan="2" style="padding:0 0 3px 0; font-size:10px; font-weight:600;
918 + text-transform:uppercase; letter-spacing:0.06em; color:#64748b;">
919 + <?php if (!empty(Arr::get($summary, 'foldedRateLines', []))): ?>
920 + <?php echo esc_html__('Tax breakdown by rate', 'fluent-cart'); ?>
921 + <?php else: ?>
922 + <?php echo esc_html__('TAX SUMMARY', 'fluent-cart'); ?>
923 + <?php endif; ?>
924 + </td>
925 + </tr>
926 + <?php
927 + $foldedRateLines = Arr::get($summary, 'foldedRateLines', []);
928 + $rcIsReverseCharge = !empty($summary['isReverseCharge']);
929 + $rcReversedTotal = (int) Arr::get($summary, 'reversedTaxTotal', 0);
930 + $rcReversedShipping = (int) Arr::get($summary, 'reversedShippingTax', 0);
931 + $rcReversedValue = $rcReversedTotal > 0
932 + ? Helper::toDecimal($rcReversedTotal)
933 + : __('Charge reversed', 'fluent-cart');
934 + $includedInPrices = (int) Arr::get($summary, 'includedInPrices', 0);
935 + ?>
936 + <?php if (!empty($foldedRateLines)): ?>
937 + <tr>
938 + <td colspan="2" style="padding:2px 0 0 0;">
939 + <table width="100%" cellpadding="0" cellspacing="0" style="border:none;border-collapse:collapse;table-layout:fixed;">
940 + <tr>
941 + <td style="width:58%;padding:3px 8px 3px 8px; font-size:10px; font-weight:600; text-transform:uppercase; letter-spacing:0.06em; color:#64748b; vertical-align:top;">
942 + <?php echo esc_html__('Rate', 'fluent-cart'); ?>
943 + </td>
944 + <td style="width:24%;padding:3px 8px 3px 0; font-size:10px; font-weight:600; text-transform:uppercase; letter-spacing:0.06em; color:#64748b; text-align:right; white-space:nowrap; vertical-align:top;">
945 + <?php echo esc_html__('Taxable base', 'fluent-cart'); ?>
946 + </td>
947 + <td style="width:18%;padding:3px 0 3px; font-size:10px; font-weight:600; text-transform:uppercase; letter-spacing:0.06em; color:#64748b; text-align:right; white-space:nowrap; vertical-align:top;">
948 + <?php echo esc_html__('Tax', 'fluent-cart'); ?>
949 + </td>
950 + </tr>
951 + <?php foreach ($foldedRateLines as $foldedRow):
952 + $foldedColor = !empty($foldedRow['inclusive']) ? '#94a3b8' : '#334155'; ?>
953 + <tr>
954 + <td style="width:58%;padding:3px 8px 3px 8px; font-size:11px; color:<?php echo esc_attr($foldedColor); ?>; text-align:left; white-space:normal; word-break:break-word; overflow-wrap:break-word; vertical-align:top;">
955 + <?php echo esc_html($foldedRow['label']); ?>
956 + </td>
957 + <td style="width:24%;padding:3px 8px 3px 0; font-size:11px; color:<?php echo esc_attr($foldedColor); ?>; text-align:right; white-space:nowrap; vertical-align:top;">
958 + <?php echo esc_html(Helper::toDecimal((int) $foldedRow['base'])); ?>
959 + </td>
960 + <td style="width:18%;padding:3px 0 3px; font-size:11px; color:<?php echo esc_attr($foldedColor); ?>; text-align:right; white-space:nowrap; vertical-align:top;">
961 + <?php echo esc_html(Helper::toDecimal((int) $foldedRow['tax'])); ?>
962 + </td>
963 + </tr>
964 + <?php endforeach; ?>
965 + </table>
966 + </td>
967 + </tr>
968 + <?php if ($rcIsReverseCharge): ?>
969 + <tr>
970 + <td style="padding:3px 0 4px 8px; font-size:11px; font-weight:600; color:#1e293b; text-align: left;">
971 + <?php echo esc_html__('VAT reversed', 'fluent-cart'); ?>
972 + </td>
973 + <td style="padding:3px 0 4px; font-size:11px; text-align:right; font-weight:600; color:#1e293b;">
974 + <?php echo esc_html($rcReversedValue); ?>
975 + </td>
976 + </tr>
977 + <?php else: ?>
978 + <tr>
979 + <td style="padding:4px 0 3px 8px; font-size:11px; font-weight:600; color:#1e293b; border-top:1px solid #e2e8f0; text-align:left;">
980 + <?php echo esc_html__('Total tax', 'fluent-cart'); ?>
981 + </td>
982 + <td style="padding:4px 0 3px; font-size:11px; font-weight:600; color:#1e293b; border-top:1px solid #e2e8f0; text-align:right;">
983 + <?php echo esc_html(Helper::toDecimal((int) $summary['totalOrderTax'])); ?>
984 + </td>
985 + </tr>
986 + <?php if ($includedInPrices > 0): ?>
987 + <tr>
988 + <td style="padding:3px 0 3px 8px; font-size:11px; color:#94a3b8; text-align:left;">
989 + <?php echo esc_html__('of which included in prices', 'fluent-cart'); ?>
990 + </td>
991 + <td style="padding:3px 0 3px; font-size:11px; color:#94a3b8; text-align:right;">
992 + <?php echo esc_html(Helper::toDecimal($includedInPrices)); ?>
993 + </td>
994 + </tr>
995 + <?php endif; ?>
996 + <?php if ($summary['payableTax'] > 0 && $includedInPrices > 0): ?>
997 + <tr>
998 + <td style="padding:3px 0 4px 8px; font-size:11px; color:#334155; text-align:left; border-top:1px solid #e2e8f0; padding-top:6px;">
999 + <?php echo esc_html__('Payable now (added)', 'fluent-cart'); ?>
1000 + </td>
1001 + <td style="padding:3px 0 4px; font-size:11px; color:#334155; text-align:right; border-top:1px solid #e2e8f0; padding-top:6px;">
1002 + <?php echo esc_html(Helper::toDecimal((int) $summary['payableTax'])); ?>
1003 + </td>
1004 + </tr>
1005 + <?php endif; ?>
1006 + <?php endif; ?>
1007 + <?php elseif ($rcIsReverseCharge): ?>
1008 + <?php if ($summary['showRcShippingRow'] && $rcReversedShipping > 0): ?>
1009 + <tr>
1010 + <td style="padding:3px 0 3px 8px; font-size:11px; color:#94a3b8;">
1011 + <?php echo esc_html__('Added on shipping', 'fluent-cart'); ?>
1012 + </td>
1013 + <td style="padding:3px 0 3px; font-size:11px; text-align:right; color:#94a3b8;">
1014 + <span style="text-decoration:line-through;opacity:0.6;"><?php echo esc_html(Helper::toDecimal($rcReversedShipping)); ?></span>
1015 + </td>
1016 + </tr>
1017 + <?php endif; ?>
1018 + <tr>
1019 + <td style="padding:3px 0 4px 8px; font-size:11px; font-weight:600; color:#1e293b; text-align: left;">
1020 + <?php echo esc_html__('Tax reversed', 'fluent-cart'); ?>
1021 + </td>
1022 + <td style="padding:3px 0 4px; font-size:11px; text-align:right; font-weight:600; color:#1e293b;">
1023 + <?php echo esc_html($rcReversedValue); ?>
1024 + </td>
1025 + </tr>
1026 + <?php else: ?>
1027 + <?php
1028 + $rcFeeRows = Arr::get($summary, 'feeTaxLineRows', []);
1029 + $taxRateLines = Arr::get($summary, 'taxRateLines', []);
1030 + $productTaxRowCount = !empty($taxRateLines)
1031 + ? count($taxRateLines)
1032 + : (int) ($summary['inclusiveTax'] > 0) + (int) ($summary['exclusiveTax'] > 0);
1033 + $rowCount = $productTaxRowCount + count($rcFeeRows) + (int) ($summary['shippingTax'] > 0);
1034 + $shippingTaxLines = Arr::get($summary, 'shippingTaxLines', []);
1035 + $shouldShowBreakdown = !empty($taxRateLines)
1036 + || !empty($shippingTaxLines)
1037 + || $rowCount >= 2
1038 + || ($rowCount === 1 && !($summary['payableTax'] > 0 || $summary['inclusiveTax'] > 0 || (int) Arr::get($summary, 'inclusiveFeeTax', 0) > 0));
1039 + ?>
1040 + <?php if (!empty($taxRateLines) && $shouldShowBreakdown): ?>
1041 + <?php foreach ($taxRateLines as $taxLine):
1042 + $taxLineColor = !empty($taxLine['inclusive']) ? '#94a3b8' : '#334155'; ?>
1043 + <tr>
1044 + <td style="padding:3px 0 3px 8px; font-size:11px; color:<?php echo esc_attr($taxLineColor); ?>; text-align: left;">
1045 + <?php echo esc_html($taxLine['label']); ?>
1046 + </td>
1047 + <td style="padding:3px 0 3px; font-size:11px; text-align:right; color:<?php echo esc_attr($taxLineColor); ?>;">
1048 + <?php echo esc_html(Helper::toDecimal($taxLine['order_tax'])); ?>
1049 + </td>
1050 + </tr>
1051 + <?php endforeach; ?>
1052 + <?php endif; ?>
1053 + <?php if (empty($taxRateLines) && $summary['inclusiveTax'] > 0 && $shouldShowBreakdown): ?>
1054 + <tr>
1055 + <td style="padding:3px 0 3px 8px; font-size:11px; color:#94a3b8;">
1056 + <?php echo esc_html__('Included in item prices', 'fluent-cart'); ?>
1057 + </td>
1058 + <td style="padding:3px 0 3px; font-size:11px; text-align:right; color:#94a3b8;">
1059 + <?php echo esc_html(Helper::toDecimal($summary['inclusiveTax'])); ?>
1060 + </td>
1061 + </tr>
1062 + <?php endif; ?>
1063 + <?php if (empty($taxRateLines) && $summary['exclusiveTax'] > 0 && $shouldShowBreakdown): ?>
1064 + <tr>
1065 + <td style="padding:3px 0 3px 8px; font-size:11px; color:#334155; text-align: left;">
1066 + <?php echo esc_html__('Added on products', 'fluent-cart'); ?>
1067 + </td>
1068 + <td style="padding:3px 0 3px; font-size:11px; text-align:right; color:#334155;">
1069 + <?php echo esc_html(Helper::toDecimal($summary['exclusiveTax'])); ?>
1070 + </td>
1071 + </tr>
1072 + <?php endif; ?>
1073 + <?php if ($shouldShowBreakdown) : ?>
1074 + <?php foreach ($rcFeeRows as $feeRow) :
1075 + $feeRowColor = $feeRow['inclusive'] ? '#94a3b8' : '#334155'; ?>
1076 + <tr>
1077 + <td style="padding:3px 0 3px 8px; font-size:11px; color:<?php echo esc_attr($feeRowColor); ?>; text-align: left;">
1078 + <?php echo esc_html($feeRow['display_label']); ?>
1079 + </td>
1080 + <td style="padding:3px 0 3px; font-size:11px; text-align:right; color:<?php echo esc_attr($feeRowColor); ?>;">
1081 + <?php echo esc_html(Helper::toDecimal($feeRow['tax_amount'])); ?>
1082 + </td>
1083 + </tr>
1084 + <?php endforeach; ?>
1085 + <?php endif; ?>
1086 + <?php if ($summary['shippingTax'] > 0 && $shouldShowBreakdown):
1087 + $isShippingInclusive = (bool) Arr::get($summary, 'isShippingInclusive', false);
1088 + $shippingRowColor = $isShippingInclusive ? '#94a3b8' : '#334155';
1089 + if (!empty($shippingTaxLines)):
1090 + foreach ($shippingTaxLines as $shLine): ?>
1091 + <tr>
1092 + <td style="padding:3px 0 3px 8px; font-size:11px; color:<?php echo esc_attr($shippingRowColor); ?>;">
1093 + <?php echo esc_html($shLine['label']); ?>
1094 + </td>
1095 + <td style="padding:3px 0 3px; font-size:11px; text-align:right; color:<?php echo esc_attr($shippingRowColor); ?>;">
1096 + <?php echo esc_html(Helper::toDecimal($shLine['shipping_tax'])); ?>
1097 + </td>
1098 + </tr>
1099 + <?php endforeach;
1100 + else: ?>
1101 + <tr>
1102 + <td style="padding:3px 0 3px 8px; font-size:11px; color:<?php echo esc_attr($shippingRowColor); ?>;">
1103 + <?php echo esc_html($isShippingInclusive ? __('Included in shipping prices', 'fluent-cart') : __('Added on shipping', 'fluent-cart')); ?>
1104 + </td>
1105 + <td style="padding:3px 0 3px; font-size:11px; text-align:right; color:<?php echo esc_attr($shippingRowColor); ?>;">
1106 + <?php echo esc_html(Helper::toDecimal($summary['shippingTax'])); ?>
1107 + </td>
1108 + </tr>
1109 + <?php endif; ?>
1110 + <?php endif; ?>
1111 + <?php if ($summary['payableTax'] > 0): ?>
1112 + <tr>
1113 + <td style="padding:4px 0 4px 8px; font-size:11px; font-weight:600; color:#1e293b;
1114 + border-top:1px solid #e2e8f0; text-align: left;">
1115 + <?php echo esc_html__('Total payable tax', 'fluent-cart'); ?>
1116 + </td>
1117 + <td style="padding:4px 0 4px; font-size:11px; text-align:right; font-weight:600; color:#1e293b;
1118 + border-top:1px solid #e2e8f0;">
1119 + <?php echo esc_html(Helper::toDecimal($summary['payableTax'])); ?>
1120 + </td>
1121 + </tr>
1122 + <?php endif; ?>
1123 + <?php if ($summary['inclusiveTax'] > 0 || $summary['inclusiveFeeTax'] > 0): ?>
1124 + <tr>
1125 + <td style="padding:3px 0 4px 8px; font-size:11px; color:#94a3b8;">
1126 + <?php echo esc_html__('Total tax in this order', 'fluent-cart'); ?>
1127 + </td>
1128 + <td style="padding:3px 0 4px; font-size:11px; text-align:right; color:#94a3b8;">
1129 + <?php echo esc_html(Helper::toDecimal($summary['totalOrderTax'])); ?>
1130 + </td>
1131 + </tr>
1132 + <?php endif; ?>
1133 + <?php endif; ?>
1134 + <?php endif; ?>
1135 + </table>
1136 + </td>
1137 + </tr>
1138 + </table>
1139 + </td>
1140 + </tr>
1141 + <?php
1142 + }
793 1143 }