PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.6
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.6
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 1.3.20 1.3.19 All 49 releases
← All changes | app/Services/Renderer/Receipt/ReceiptRenderer.php +469 -108 1.3.21 → 1.6.6 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,14 +323,24 @@
309 323 style="margin-bottom: 3px;">
310 324 <?php echo esc_html($this->settings->getFormattedFullAddress()); ?>
311 325 </div>
312 326 <?php
327 + $orderTaxRates = $order->getPrimaryOrderTaxRate();
328 + $storeVatNumber = Arr::get($orderTaxRates->meta ?? [], 'store_vat_number', '');
329 + $taxCountry = Arr::get($orderTaxRates->meta ?? [], 'tax_country', '');
330 + if (!empty($storeVatNumber)): ?>
331 + <div
332 + class="fct-receipt-page-store-address-vat"
333 + style="margin-top: 5px;font-weight: 500;">
334 + <?php echo esc_html(TaxModule::getCountryTaxTitle($taxCountry)) . ': ' . esc_html($storeVatNumber); ?>
335 + </div>
336 + <?php endif;
313 337 }
314 338
315 339 public function renderBillToAddress()
316 340 {
317 341 $order = Arr::get($this->config, 'order', null);
318 - $orderTaxRates = $order->orderTaxRates->first();
342 + $orderTaxRates = $order->getPrimaryOrderTaxRate();
319 343 ?>
320 344 <div
321 345 class="fct-receipt-page-order-items-addresses-bill-to"
322 346 style="border-radius: 5px;print-color-adjust: exact;">
@@ -331,15 +355,8 @@
331 355 class="fct-receipt-page-order-items-addresses-bill-to-address"
332 356 style="margin-bottom: 3px;">
333 357 <?php echo esc_html($order->billing_address->getAddressAsText()); ?>
334 358 </div>
335 - <?php if (!empty($this->vat_tax_id)) : ?>
336 - <div
337 - class="fct-receipt-page-order-items-addresses-bill-to-vat-number"
338 - style="margin-bottom: 3px;">
339 - <?php echo esc_html__('VAT/Tax ID:', 'fluent-cart') . ' ' . esc_html($this->vat_tax_id); ?>
340 - </div>
341 - <?php endif; ?>
342 359 <div
343 360 class="fct-receipt-page-order-items-addresses-bill-to-email"
344 361 style="margin-top: 10px;">
345 362 <?php echo esc_html($order->customer->email); ?>
@@ -354,28 +371,50 @@
354 371 style="margin-top: 3px;">
355 372 <?php echo esc_html($phoneNumber); ?>
356 373 </div>
357 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 + ?>
358 382 <div class="fct-receipt-page-order-items-addresses-bill-to-company-name">
359 - <?php
360 - $companyName = Arr::get($order->billing_address->meta ?? [], 'other_data.company_name', '');
361 - if ($companyName == '') {
362 - $companyName = Arr::get($orderTaxRates->meta ?? [], 'vat_reverse.name', '');
363 - }
364 - echo esc_html($companyName);
365 - ?>
383 + <?php echo esc_html($companyName); ?>
366 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; ?>
367 397 <div
368 398 class="fct-receipt-page-order-items-addresses-bill-to-vat-number"
369 399 style="margin-top: 5px;">
370 400 <?php
371 - $vatNumber = Arr::get($orderTaxRates->meta ?? [], 'vat_reverse.vat_number', '');
372 -
401 + $vatNumber = $order->getCustomerTaxNumber();
373 402 if ($vatNumber !== '') {
374 - 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);
375 405 }
376 406 ?>
377 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; ?>
378 417
379 418 <?php else: ?>
380 419 <div
381 420 class="fct-receipt-page-order-items-addresses-bill-to-name"
@@ -381,15 +420,8 @@
381 420 class="fct-receipt-page-order-items-addresses-bill-to-name"
382 421 style="margin-top: 10px;">
383 422 <?php echo esc_html($order->customer->full_name); ?>
384 423 </div>
385 - <?php if (!empty($vat_tax_id)) : ?>
386 - <div
387 - class="fct-receipt-page-order-items-addresses-bill-to-vat-number"
388 - style="margin-bottom: 3px;">
389 - <?php echo esc_html__('VAT/Tax ID:', 'fluent-cart') . ' ' . esc_html($vat_tax_id); ?>
390 - </div>
391 - <?php endif; ?>
392 424 <div
393 425 class="fct-receipt-page-order-items-addresses-bill-to-email"
394 426 style="margin-top: 3px;">
395 427 <?php echo esc_html($order->customer->email); ?>
@@ -478,34 +510,61 @@
478 510 </thead>
479 511 <tbody>
480 512 <?php
481 513 $orderItems = $order->order_items->toArray();
482 - $transaction = $order->getLatestTransaction();
514 + $isReversed = $order->isReverseChargeTaxOrder();
515 + $rcMode = $order->getOrderRcMode();
516 + $fctReceiptTaxDisplayMode = TaxSummaryHelper::getTaxDisplayMode();
483 517
484 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';
485 524 ?>
486 525 <tr>
487 - <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;">
488 527 <?php echo esc_html($item['post_title']); ?>
489 528 <br>
490 529 <?php if (!empty($item['title'])) : ?>
491 - <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>
492 531 <br>
493 532 <?php endif; ?>
494 533 <?php if (!empty($item['payment_info'])) : ?>
495 534 <small style="font-size: 13px;color: #758195;"><?php echo esc_html($item['payment_info']); ?></small>
496 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; ?>
497 543 </td>
498 - <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;">
499 545 <?php echo esc_html(Helper::translateNumber($item['quantity'])); ?>
500 546 </td>
501 - <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;">
502 549 <?php echo esc_html(\FluentCart\Api\CurrencySettings::getFormattedPrice($item['unit_price'], null, false, true, true)); ?>
503 550 </td>
504 - <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; ?>
505 557 <?php echo esc_html($item['formatted_total']); ?>
506 558 </td>
507 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; ?>
508 567 <?php endforeach; ?>
509 568 </tbody>
510 569 </table>
511 570 <?php endif;
@@ -519,16 +578,16 @@
519 578 class="fct-receipt-page-order-items-footer"
520 579 style="margin-top: 20px;">
521 580 <table
522 581 class="fct-receipt-page-order-items-footer-table"
523 - 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;">
524 583 <tbody>
525 584 <?php $this->renderSubtotal(); ?>
526 585 <?php $this->renderDiscount(); ?>
527 586 <?php $this->renderShipping(); ?>
528 587 <?php $this->renderFees(); ?>
529 - <?php $this->renderTaxTotal(); ?>
530 - <?php $this->renderShippingTax(); ?>
588 + <?php $this->renderTaxSummaryBox(); ?>
589 + <?php $this->renderProrateCredit(); ?>
531 590 <?php $this->renderRefund(); ?>
532 591 <?php $this->renderTotal(); ?>
533 592 <?php $this->renderAmountPaid(); ?>
534 593 </tbody>
@@ -541,12 +600,12 @@
541 600 {
542 601 $order = Arr::get($this->config, 'order', null);
543 602 if ($order->subtotal != ($order->total_amount - $order->total_refund) || $order->tax_total > 0): ?>
544 603 <tr>
545 - <td style="padding: 8px 20px 8px 0;text-align: right;border: none;">
604 + <td style="text-align: right;border: none; padding-top: 20px;">
546 605 <?php echo esc_html__('Subtotal', 'fluent-cart'); ?>
547 606 </td>
548 - <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;">
549 608 <?php echo esc_html(\FluentCart\App\Helpers\Helper::toDecimal($order->subtotal));
550 609 ?>
551 610 </td>
552 611 </tr>
@@ -555,33 +614,80 @@
555 614
556 615 public function renderDiscount()
557 616 {
558 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 +
559 624 if ($order->manual_discount_total + $order->coupon_discount_total > 0): ?>
560 - <tr>
561 - <td style="padding: 8px 20px 8px 0;text-align: right;border: none;">
562 - <?php echo esc_html__('Discount', 'fluent-cart'); ?>
563 - </td>
564 - <td style="padding: 8px 8px 8px 0;width: 100px;text-align: right;border: none;">
565 - - <?php echo esc_html(\FluentCart\App\Helpers\Helper::toDecimal($order->manual_discount_total + $order->coupon_discount_total)); ?>
566 - </td>
567 - </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; ?>
568 653 <?php endif;
569 654 }
570 655
656 + public function renderProrateCredit()
657 + {
658 + // Rendered as a sub-row inside renderDiscount.
659 + }
660 +
571 661 public function renderShipping()
572 662 {
573 663 $order = Arr::get($this->config, 'order', null);
574 - if ($order->shipping_total > 0): ?>
575 - <tr>
576 - <td style="padding: 8px 20px 8px 0;text-align: right;border: none;">
577 - <?php echo esc_html__('Shipping', 'fluent-cart'); ?>
578 - </td>
579 - <td style="padding: 8px 8px 8px 0;width: 100px;text-align: right;border: none;">
580 - <?php echo esc_html(\FluentCart\App\Helpers\Helper::toDecimal($order->shipping_total)); ?>
581 - </td>
582 - </tr>
583 - <?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
584 690 }
585 691
586 692 public function renderFees()
587 693 {
@@ -601,42 +707,8 @@
601 707 </tr>
602 708 <?php endforeach;
603 709 }
604 710
605 - public function renderTaxTotal()
606 - {
607 - $order = Arr::get($this->config, 'order', null);
608 - if ($order->tax_total > 0): ?>
609 - <tr>
610 - <td style="padding: 8px 20px 8px 0;text-align: right;border: none;">
611 - <?php echo esc_html__('Tax', 'fluent-cart');
612 - echo esc_html($order->tax_behavior == 2 ? __('(Included)', 'fluent-cart') : __('(Excluded)', 'fluent-cart'));
613 - ?>
614 - </td>
615 - <td style="padding: 8px 8px 8px 0;width: 100px;text-align: right;border: none;">
616 - <?php echo esc_html(\FluentCart\App\Helpers\Helper::toDecimal($order->tax_total)); ?>
617 - </td>
618 - </tr>
619 - <?php endif;
620 - }
621 -
622 - public function renderShippingTax()
623 - {
624 - $order = Arr::get($this->config, 'order', null);
625 - if ($order->shipping_tax > 0): ?>
626 - <tr>
627 - <td style="padding: 8px 20px 8px 0;text-align: right;border: none;">
628 - <?php echo esc_html__('Shipping Tax', 'fluent-cart');
629 - echo esc_html($order->tax_behavior == 2 ? __('(Included)', 'fluent-cart') : __('(Excluded)', 'fluent-cart'));
630 - ?>
631 - </td>
632 - <td style="padding: 8px 8px 8px 0;width: 100px;text-align: right;border: none;">
633 - <?php echo esc_html(\FluentCart\App\Helpers\Helper::toDecimal($order->shipping_tax)); ?>
634 - </td>
635 - </tr>
636 - <?php endif;
637 - }
638 -
639 711 public function renderRefund()
640 712 {
641 713 $order = Arr::get($this->config, 'order', null);
642 714 if ($order->total_refund > 0): ?>
@@ -653,15 +725,22 @@
653 725
654 726 public function renderTotal()
655 727 {
656 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 + }
657 736 ?>
658 737 <tr style="font-weight: bold;font-size: 14px;">
659 - <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;">
660 739 <?php echo esc_html__('Total', 'fluent-cart'); ?>
661 740 </td>
662 - <td style="padding: 8px 8px 8px 0;width: 100px;text-align: right;border:none;">
663 - <?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)); ?>
664 743 </td>
665 744 </tr>
666 745 <?php
667 746 }
@@ -670,12 +749,12 @@
670 749 {
671 750 $order = Arr::get($this->config, 'order', null);
672 751 ?>
673 752 <tr style="font-weight: bold;font-size: 14px;">
674 - <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">
675 754 <?php echo esc_html__('Amount Paid', 'fluent-cart'); ?>
676 755 </td>
677 - <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;">
678 757 <?php echo esc_html(\FluentCart\Api\CurrencySettings::getFormattedPrice(($order->total_paid - $order->total_refund), null, false, true, true)); ?>
679 758 </td>
680 759 </tr>
681 760 <?php
@@ -683,13 +762,12 @@
683 762
684 763 public function renderTaxNote()
685 764 {
686 765 $order = Arr::get($this->config, 'order', null);
687 - $taxtotal = $order->tax_total + $order->shipping_tax;
688 - if (Arr::get($orderTaxRates->meta ?? [], 'vat_reverse.valid') && !$taxtotal): ?>
766 + if ($order->isReverseChargeTaxOrder()): ?>
689 767
690 768 <div style="text-align: right; font-size: 14px; margin-top: 10px;">
691 - <?php echo esc_html__('* Tax to be paid on reverse charge basis', 'fluent-cart'); ?>
769 + <?php echo '*' . esc_html(TaxModule::getReverseChargeNoticeText()); ?>
692 770 </div>
693 771
694 772 <?php endif;
695 773 }
@@ -734,12 +812,14 @@
734 812 <?php echo esc_html($transaction->getPaymentMethodText()); ?>
735 813 </td>
736 814 <td style="padding: 10px;border:none;border-bottom: 1px solid #dee2e6;text-align: center;">
737 815 <?php
738 - $date = wp_date(
739 - 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(
740 819 DateTime::anyTimeToGmt($transaction->created_at)->getTimestamp(),
741 - new \DateTimeZone($this->orderTz)
820 + false,
821 + $this->orderTz
742 822 );
743 823 echo esc_html(Helper::translateNumber($date));
744 824 ?>
745 825 </td>
@@ -778,5 +858,286 @@
778 858 <span><?php echo esc_html__('Please try to complete payment again from here!', 'fluent-cart'); ?></span>
779 859 <a href="<?php echo esc_url($custom_payment_url ?? ''); ?>"><?php echo esc_url($custom_payment_url); ?></a>
780 860 </div>
781 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 + }
782 1143 }