# fluent-cart/1.7.0/app/Services/Email/EmailPreviewService.php

FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler, version 1.7.0. 335 lines.

- Page: https://pluginprobe.com/plugins/fluent-cart/1.7.0/code/app/Services/Email/EmailPreviewService.php
- Raw: https://pluginprobe.com/plugins/fluent-cart/1.7.0/raw/app/Services/Email/EmailPreviewService.php
- Modified: 2026-09-29T12:49:18+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/fluent-cart/1.7.0/code/app/Services/Email/EmailPreviewService.php#L10-L20`.

```php
<?php

namespace FluentCart\App\Services\Email;

use FluentCart\App\Helpers\Status;
use FluentCart\App\Models\Product;
use FluentCart\App\Models\ProductReview;
use FluentCart\App\Services\DateTime\DateTime;
use FluentCart\Framework\Support\Collection;
use FluentCart\Framework\Support\Str;

class EmailPreviewService
{
    public function getPreviewData(string $template): array
    {
        $order = $this->getDummyOrder();
        $subscription = $this->getDummySubscription($order);
        $customer = $order->customer;
        $transaction = $order->getLatestTransaction();

        $previewData = [
            'order'        => $order,
            'subscription' => $subscription,
            'customer'     => $customer,
            'transaction'  => $transaction,
            'reminder'     => [
                'stage'          => 'before_0',
                'due_at'         => DateTime::gmtNow()->addDays(2)->format('Y-m-d H:i:s'),
                'due_amount'     => 4900,
                'payment_link'   => '#',
                'order_ref'      => $order->invoice_no,
                'billing_date'   => DateTime::gmtNow()->addDays(30)->format('Y-m-d H:i:s'),
                'trial_end_date' => DateTime::gmtNow()->addDays(3)->format('Y-m-d H:i:s'),
            ],
        ];

        if (Str::startsWith($template, 'order.reminder.renewal_overdue.')) {
            if (Str::contains($template, '.final.')) {
                $previewData['reminder']['stage'] = 'overdue_7';
            } elseif (Str::contains($template, '.followup.')) {
                $previewData['reminder']['stage'] = 'overdue_3';
            } else {
                $previewData['reminder']['stage'] = 'overdue_1';
            }
        }

        // The review templates read a review, not an order. Without one the
        // preview of any of them fatals on the first property it touches.
        if (Str::startsWith($template, 'review.')) {
            $previewData['product'] = $this->getPreviewProduct();
            $previewData['review'] = $this->getDummyReview((int) $previewData['product']->ID);

            if (Str::startsWith($template, 'review.replied.')) {
                $previewData['reply'] = $this->getDummyReply((int) $previewData['product']->ID);
            }
            // A review is not about an order, and a real send carries none —
            // the order header (date, number) renders only when one is there.
            // Left in, the preview would show a header the email never has.
            $previewData['order'] = null;
            $previewData['transaction'] = null;
        }

        if (Str::startsWith($template, 'subscription.')) {
            $previewData['transaction'] = $subscription->getLatestTransaction();

            if (Str::contains($template, 'trial_end')) {
                $previewData['reminder']['stage'] = 'trial_end_3';
            }

            if (Str::contains($template, 'renewal_failed')) {
                $previewData['error'] = __('Your card was declined.', 'fluent-cart');
            }

            if (Str::contains($template, 'canceled')) {
                $previewData['reason'] = __('canceled on customer request', 'fluent-cart');
                $previewData['subscription'] = $this->getDummySubscription($previewData['order']);
            }
        }

        return $previewData;
    }

    /**
     * A stand-in review with every field the review templates and the
     * {{review.*}} codes read. A real model, not a stdClass: the templates
     * call attachItemLabels() on it and the parser type-checks for one.
     */
    /**
     * The product a review preview is about: a real published one when the
     * store has any, so the preview links where the email will — the
     * "See your review" button needs a page to point at, and a placeholder
     * has none. An empty store previews without the button, as the email
     * would for a product since deleted.
     */
    private function getPreviewProduct(): object
    {
        $product = Product::query()
            ->where('post_status', 'publish')
            ->orderBy('ID', 'DESC')
            ->first();

        if ($product) {
            return $product;
        }

        return (object) [
            'ID'         => 0,
            'post_title' => 'Sample Product',
        ];
    }

    private function getDummyReview(int $postId = 0): ProductReview
    {
        $review = new ProductReview([
            'post_id'        => $postId,
            'reviewer_name'  => 'John Doe',
            'reviewer_email' => 'john.doe@example.com',
            'title'          => 'Exactly what I was looking for',
            'review'         => 'Arrived quickly and works just as described. Would happily buy again.',
            'rating'         => 5,
        ]);
        $review->id = 0;
        $review->status = Status::REVIEW_APPROVED;

        return $review;
    }

    private function getDummyReply(int $postId = 0): ProductReview
    {
        $reply = new ProductReview([
            'post_id'        => $postId,
            'parent_id'      => 0,
            'reviewer_name'  => 'The Store Team',
            'reviewer_email' => 'store@example.com',
            'review'         => 'Thank you so much for the kind words — we are thrilled it worked out. Enjoy!',
        ]);
        $reply->id = 0;
        $reply->status = Status::REVIEW_APPROVED;
        $reply->is_admin_reply = 1;

        return $reply;
    }

    private function getDummyCustomer(): object
    {
        return (object) [
            'full_name'  => 'John Doe',
            'first_name' => 'John',
            'last_name'  => 'Doe',
            'email'      => 'john.doe@example.com',
        ];
    }

    private function getDummyTransaction(): object
    {
        return new class {
            public $created_at;
            public $total = 4900;
            public $vendor_charge_id = 'ch_preview_123';
            public $order = null;

            public function __construct()
            {
                $this->created_at = DateTime::gmtNow();
            }

            public function getPaymentMethodText()
            {
                return 'card';
            }
        };
    }

    private function getDummyOrder(): object
    {
        $customer = $this->getDummyCustomer();
        $transaction = $this->getDummyTransaction();

        $order = new class($customer, $transaction, new Collection()) {
            public $id = 1001;
            public $uuid = 'preview-order-uuid';
            public $invoice_no = 'FC-1001';
            public $customer;
            public $order_items;
            public $subscriptions;
            public $orderTaxRates;
            public $billing_address;
            public $shipping_address;
            public $fulfillment_type = 'digital';
            public $subtotal = 4900;
            public $manual_discount_total = 0;
            public $coupon_discount_total = 0;
            public $shipping_tax = 0;
            public $shipping_total = 0;
            public $tax_total = 0;
            public $tax_behavior = 2;
            public $total_amount = 4900;
            public $total_paid = 0;
            public $total_refund = 0;
            public $payment_status = 'pending';
            public $config = [];
            private $latestTransaction;

            public function __construct($customer, $transaction, $emptyCollection)
            {
                $this->customer = $customer;
                $this->latestTransaction = $transaction;
                $this->order_items = new Collection([
                    [
                        'post_title'           => 'Sample Product',
                        'quantity'             => 1,
                        'title'                => 'Standard Plan',
                        'payment_type'         => 'onetime',
                        'payment_info'         => '',
                        'formatted_total'      => '$49.00',
                        'package_info'       => __('Package: Medium Box · 30 × 20 × 15 cm · Wt: 2 kg · Shipping wt: 2.5 kg', 'fluent-cart'),
                        'other_info'         => [
                            'package_name'           => 'Medium Box',
                            'package_type'           => 'box',
                            'package_length'         => 30,
                            'package_width'          => 20,
                            'package_height'         => 15,
                            'package_dimension_unit' => 'cm',
                            'weight'                 => 2,
                            'weight_unit'            => 'kg',
                            'package_weight'         => 0.5,
                            'package_weight_unit'    => 'kg',
                            'package_slug'           => 'medium-box',
                        ],
                    ],
                ]);
                $this->subscriptions = $emptyCollection;
                $this->orderTaxRates = $emptyCollection;
                $this->billing_address = null;
                $this->shipping_address = null;
            }

            public function getViewUrl($type = 'customer')
            {
                return '#';
            }

            public function getMeta($metaKey, $defaultValue = false)
            {
                if ($metaKey === 'due_date') {
                    return gmdate('Y-m-d H:i:s', strtotime('+7 days'));
                }
                return $defaultValue;
            }

            public function isReverseChargeTaxOrder()
            {
                return false;
            }

            public function getOrderRcMode()
            {
                return 'fixed';
            }

            public function getLatestTransaction()
            {
                return $this->latestTransaction;
            }

            public function getDownloads($scope = 'email')
            {
                return [];
            }

            public function getLicenses($with = ['product', 'productVariant'])
            {
                return new Collection([]);
            }
        };

        // Templates reach the order through the transaction too (e.g. the
        // renewal admin email's $transaction->order->getViewUrl('admin')).
        $transaction->order = $order;

        return $order;
    }

    private function getDummySubscription($order): object
    {
        $customer = $order->customer ?? $this->getDummyCustomer();
        $transaction = $this->getDummyTransaction();

        return new class($customer, $transaction, $order) {
            public $id = 2001;
            public $uuid = 'preview-subscription-uuid';
            public $item_name = 'Sample Subscription';
            public $display_item_name = 'Sample Subscription';
            public $billing_interval = 'yearly';
            public $next_billing_date;
            public $recurring_total = 4900;
            public $status = 'active';
            public $trial_ends_at;
            public $customer;
            public $order;
            private $latestTransaction;

            public function __construct($customer, $transaction, $order)
            {
                $this->customer = $customer;
                $this->latestTransaction = $transaction;
                $this->order = $order;
                $transaction->order = $order;
                $this->next_billing_date = \FluentCart\App\Services\DateTime\DateTime::gmtNow()->addDays(30)->format('Y-m-d H:i:s');
                $this->trial_ends_at = \FluentCart\App\Services\DateTime\DateTime::gmtNow()->addDays(3)->format('Y-m-d H:i:s');
            }

            public function getLatestTransaction()
            {
                return $this->latestTransaction;
            }

            public function getViewUrl($type = 'customer')
            {
                return '#';
            }

            public function getReactivateUrl()
            {
                return '#';
            }

            public function getPaymentMethodText()
            {
                return 'Visa ***4242';
            }
        };
    }
}

```
