storeSettings = new StoreSettings(); $this->order = Arr::get($data, 'order'); $config = Arr::wrap( Arr::get($this->order, 'config') ); $rawTz = Arr::get($config, 'user_tz', 'UTC'); $this->orderTz = (@timezone_open($rawTz) !== false) ? $rawTz : 'UTC'; $orderId = Arr::get($this->order, 'id'); parent::__construct($data); } // protected array $methodMap = [ // 'customer_dashboard_link' => 'getCustomerDashboardLink', // 'payment_summary' => 'getPaymentSummary', // 'payment_receipt' => 'getPaymentReceipt', // ]; protected array $methodMap = [ 'item_count' => 'getItemCount', 'is_digital' => 'getIsDigital', 'store_vat_display' => 'getStoreVatDisplay', 'store_company_name' => 'getStoreCompanyName', 'store_company_display' => 'getStoreCompanyDisplay', 'store_legal_registration_id' => 'getStoreLegalRegistrationId', 'store_legal_registration_display' => 'getStoreLegalRegistrationDisplay', 'store_seller_vat_id' => 'getStoreSellerVatId', 'store_seller_vat_display' => 'getStoreSellerVatDisplay', 'store_seller_tax_id' => 'getStoreSellerTaxId', 'store_tax_display' => 'getStoreTaxDisplay', 'buyer_vat_display' => 'getBuyerVatDisplay', 'buyer_company_name' => 'getBuyerCompanyName', 'buyer_legal_registration_id' => 'getBuyerLegalRegistrationId', 'buyer_reverse_charge_declaration' => 'getBuyerReverseChargeDeclaration', 'tax_breakdown' => 'getTaxBreakdown', 'fee_lines' => 'getFeeLines', ]; protected array $attributeMap = [ 'id' => 'order.id', 'status' => 'order.status', 'created_at' => 'order.created_at', 'updated_at' => 'order.updated_at', ]; protected array $centColumns = [ 'total_amount', 'subtotal', 'discount_tax', 'manual_discount_total', 'coupon_discount_total', 'shipping_tax', 'shipping_total', 'fee_total', 'tax_total', 'total_paid', 'total_refund' ]; public function parse($accessor = '', $code = '', $transformer = null): ?string { if ($this->shouldParseAddress($accessor)) { return $this->parseAddressFields($accessor); } if (in_array($accessor, ['updated_at', 'created_at'])) { $date = Arr::get($this->data, $this->attributeMap[$accessor]); $timestamp = DateTime::anyTimeToGmt($date)->getTimestamp(); // Through DateFormatter so the store's format and timezone settings // reach this too; orderTz is only consulted on the Browser source. $date = DateFormatter::format($timestamp, false, $this->orderTz); return Helper::translateNumber($date); } // Handle _formatted suffix for cent columns (e.g. total_amount_formatted) $formattedSuffix = '_formatted'; if (Str::endsWith($accessor, $formattedSuffix)) { $baseAccessor = substr($accessor, 0, -strlen($formattedSuffix)); if (in_array($baseAccessor, $this->centColumns)) { $amount = Arr::get($this->order, $baseAccessor); if (!is_numeric($amount)) { return (string) $amount; } return CurrencySettings::getPriceHtml($amount, $this->order['currency']); } } if (in_array($accessor, $this->centColumns)) { $amount = Arr::get($this->order, $accessor); if (!is_numeric($amount)) { return (string) $amount; } return (string) ($amount / 100); } // $html parsers $htmlParsers = [ 'order.download_details', 'order.items_table', 'order.payment_summary', 'order.payment_receipt', 'order.subscription_details', 'order.license_details', 'order.address_details', ]; if (in_array($code, $htmlParsers)) { $order = $this->order; if ($code == 'order.items_table') { return \FluentCart\App\App::make('view')->make('emails.parts.items_table', [ 'order' => $order, 'formattedItems' => $order->order_items, 'heading' => __('Order Summary', 'fluent-cart'), ]); } if ($code === 'order.subscription_details') { if ($order->subscriptions && $order->subscriptions->count() > 0) { return \FluentCart\App\App::make('view')->make('invoice.parts.subscription_items', [ 'subscriptions' => $order->subscriptions, 'order' => $order ]); } return ''; } if ($code === 'order.license_details') { $licenses = $order->getLicenses(); if ($licenses && $licenses->count() > 0) { return \FluentCart\App\App::make('view')->make('emails.parts.licenses', [ 'licenses' => $licenses, 'heading' => _n('License', 'Licenses', $licenses->count(), 'fluent-cart'), 'show_notice' => false ]); } return ''; } if ($code === 'order.download_details') { $downloads = $order->getDownloads(); if ($downloads) { return \FluentCart\App\App::make('view')->make('emails.parts.downloads', [ 'order' => $order, 'heading' => _n('Download', 'Downloads', count($downloads), 'fluent-cart'), 'downloadItems' => $downloads, ]); } return ''; } if ($code === 'order.address_details') { return \FluentCart\App\App::make('view')->make('emails.parts.addresses', [ 'order' => $order, ]); } if ($code == 'order.payment_summary') { return $this->getPaymentSummary(); } if ($code == 'order.payment_receipt') { return $this->getPaymentReceipt(); } } return $this->get($accessor, $code); } public function shouldParseAddress($accessor): bool { return Str::startsWith($accessor, 'billing.') || Str::startsWith($accessor, 'shipping.'); } public function parseAddressFields($accessor) { list($addressType, $accessorsKey) = $this->resolveAddressFieldKeys($accessor); return $this->getAddressData($addressType, $accessorsKey); } public function resolveAddressFieldKeys($accessor): array { $exploded = explode('.', $accessor); $addressType = $exploded[0]; $accessorsKey = implode('.', array_slice($exploded, 1)); return [$addressType, $accessorsKey]; } public function getAddressData($addressAccessor, $accessor = null) { $address = Arr::get($this->order, $addressAccessor . '_address'); if (empty($address)) { return ""; } $formattedFields = ['city', 'state', 'country']; if (in_array($accessor, $formattedFields) && method_exists($address, 'getFormattedAddress')) { $formatted = $address->getFormattedAddress(); return Arr::get($formatted, $accessor) ?: ''; } return Arr::get($address, $accessor) ?: ''; } public function getPaymentSummary() { $order = $this->order; return \FluentCart\App\App::make('view')->make('emails.parts.items_table', [ 'order' => $order, 'formattedItems' => $order->order_items, 'heading' => '', ]); } public function getPaymentReceipt() { $order = $this->order; ob_start(); \FluentCart\App\App::make('view')->render('emails.parts.items_table', [ 'order' => $order, 'formattedItems' => $order->order_items, 'heading' => __('Order Summary', 'fluent-cart'), ]); if ($order->subscriptions && $order->subscriptions->count() > 0) { \FluentCart\App\App::make('view')->render('invoice.parts.subscription_items', [ 'subscriptions' => $order->subscriptions, 'order' => $order ]); } $licenses = $order->getLicenses(); if ($licenses && $licenses->count() > 0) { \FluentCart\App\App::make('view')->render('emails.parts.licenses', [ 'licenses' => $licenses, 'heading' => __('Licenses', 'fluent-cart'), 'show_notice' => false ]); } $downloads = $order->getDownloads(); if ($downloads) { \FluentCart\App\App::make('view')->render('emails.parts.downloads', [ 'order' => $order, 'heading' => __('Downloads', 'fluent-cart'), 'downloadItems' => $downloads, ]); } echo '
'; \FluentCart\App\App::make('view')->render('emails.parts.addresses', [ 'order' => $order, ]); return ob_get_clean(); } public function getDiscountTotal(): string { return (string) ($this->getDiscountTotalInCents() / 100); } public function getDiscountTotalFormatted(): string { return CurrencySettings::getPriceHtml($this->getDiscountTotalInCents(), $this->order['currency']); } private function getDiscountTotalInCents(): int { return (int) Arr::get($this->order, 'coupon_discount_total', 0) + (int) Arr::get($this->order, 'manual_discount_total', 0); } public function getOrderRef(): string { $invoiceNo = Arr::get($this->order, 'invoice_no'); if (!empty($invoiceNo)) { return (string) $invoiceNo; } return (string) Arr::get($this->order, 'id'); } public function getCustomerDashboardAnchorLink($accessor, $code = null, $conditions = []) { $defaultValue = Arr::get($conditions, 'default_value') ?? Arr::get($this->order, 'invoice_no'); if (empty($this->order)) { return $code; } $profilePage = $this->storeSettings->getCustomerProfilePage(); if (!empty($profilePage)) { return "" . $defaultValue . ""; } else { return Arr::get($this->order, 'invoice_no'); } } public function getCustomerDashboardLink($accessor, $code = null) { if (empty($this->order)) { return $code; } $orderLink = TemplateService::getCustomerProfileUrl('order/' . Arr::get($this->order, 'uuid')); return is_user_logged_in() ? $orderLink : wp_login_url($orderLink); } public function getPaymentLink($accessor = null, $code = null) { if (empty($this->order)) { return $code; } return PaymentHelper::getCustomPaymentLink(Arr::get($this->order, 'uuid')); } public function getAdminOrderLink($accessor, $code = null) { if (empty($this->order)) { return $code; } return admin_url('admin.php?page=fluent-cart#/orders/' . Arr::get($this->order, 'id') . '/view'); } public function getAdminOrderAnchorLink($accessor, $code = null, $conditions = []) { $defaultValue = Arr::get($conditions, 'default_value'); if (empty($this->order)) { return $code; } $url = admin_url('admin.php?page=fluent-cart#/orders/' . Arr::get($this->order, 'id') . '/view'); if (!empty($defaultValue)) { return "" . $defaultValue . ""; } return $url; } public function getCustomerOrderLink($accessor, $code = null) { if (empty($this->order)) { return $code; } $customerProfilePage = $this->storeSettings->getCustomerProfilePage(); $orderLink = $customerProfilePage . '#/order/' . Arr::get($this->order, 'uuid'); return is_user_logged_in() ? $orderLink : wp_login_url($orderLink); } public function getTotalAmount() { $total = ($this->order['total_amount'] / 100); $currency_sign = $this->order['currency']; return $total . $currency_sign; } public function getDownloads() { $order = $this->order; $downloads = $order->getDownloads(); if ($downloads) { return (string)\FluentCart\App\App::make('view')->make('emails.parts.downloads', [ 'order' => $order, 'heading' => '', 'downloadItems' => $downloads ]); } return ''; } public function getLicenses() { $order = $this->order; $licenses = $order->getLicenses(); if ($licenses && $licenses->count() > 0) { return (string)\FluentCart\App\App::make('view')->make('emails.parts.licenses', [ 'licenses' => $licenses, 'heading' => __('Licenses', 'fluent-cart'), 'show_notice' => false ]); } return ''; } public function getLicenseCount(): string { return (string)$this->licenses->count(); } public function getIsDigital(): string { if (!$this->order) { return 'no'; } $fulfillmentType = Arr::get($this->order, 'fulfillment_type'); return $fulfillmentType === 'digital' ? 'yes' : 'no'; } public function getItemCount(): string { $orderItems = $this->order ? $this->order->order_items : null; if ($orderItems) { return (string)$orderItems->count(); } return '0'; } public function getPaymentMethodTitle(): string { if (!$this->order) { return ''; } $title = (string) Arr::get($this->order, 'payment_method_title', ''); if ($title !== '') { return $title; } $slug = (string) Arr::get($this->order, 'payment_method', ''); if ($slug === '') { return ''; } if (class_exists(GatewayManager::class)) { $gateway = GatewayManager::getInstance($slug); if ($gateway) { $gatewayTitle = (string) $gateway->getMeta('title'); if ($gatewayTitle !== '') { return $gatewayTitle; } } } return ucwords(str_replace(['_', '-'], ' ', $slug)); } public function getFeeLines(): string { if (!$this->order) { return ''; } $currency = (string) Arr::get($this->order, 'currency', ''); $feeItems = $this->order->feeItems()->get(); if ($feeItems->isEmpty()) { return ''; } $rowStyle = 'padding:3px 0;font-size:11px;font-weight:600;color:#525866;'; $valueStyle = 'text-align:right;'; $rows = ''; foreach ($feeItems as $feeItem) { $rows .= '' . '' . esc_html((string) $feeItem->title) . '' . '' . CurrencySettings::getPriceHtml((int) $feeItem->subtotal, $currency) . '' . ''; } return $rows; } public function getTaxBreakdown(): string { if (!$this->order) { return ''; } $currency = (string) Arr::get($this->order, 'currency', ''); $summary = TaxSummaryHelper::computeTaxSummary($this->order); if (!$summary['shouldRender']) { return ''; } $headingStyle = 'padding:8px 0 4px;font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:0.06em;color:#94a3b8;'; $mutedStyle = 'padding:3px 0;font-size:11px;color:#94a3b8;'; $normalStyle = 'padding:3px 0;font-size:11px;font-weight:600;color:#525866;'; $totalStyle = 'padding:6px 0 3px;font-size:11px;font-weight:700;color:#0E121B;border-top:1px solid #e2e8f0;'; $valueStyle = 'text-align:right;'; $rows = ''; $foldedRateLines = Arr::get($summary, 'foldedRateLines', []); $isRcOrder = !empty($summary['isReverseCharge']); $rcReversedTotal = isset($summary['reversedTaxTotal']) ? (int) $summary['reversedTaxTotal'] : 0; $rcReversedValue = $rcReversedTotal > 0 ? esc_html(Helper::toDecimal($rcReversedTotal)) : esc_html__('Charge reversed', 'fluent-cart'); $includedInPrices = (int) Arr::get($summary, 'includedInPrices', 0); $opFeeRows = Arr::get($summary, 'feeTaxLineRows', []); $taxRateLines = Arr::get($summary, 'taxRateLines', []); $productTaxRowCount = !empty($taxRateLines) ? count($taxRateLines) : (int) ($summary['inclusiveTax'] > 0) + (int) ($summary['exclusiveTax'] > 0); $rowCount = $productTaxRowCount + count($opFeeRows) + (int) ($summary['shippingTax'] > 0); $shippingTaxLines = Arr::get($summary, 'shippingTaxLines', []); $shouldShowBreakdown = !empty($taxRateLines) || !empty($shippingTaxLines) || $rowCount >= 2 || ($rowCount === 1 && !($summary['payableTax'] > 0 || $summary['inclusiveTax'] > 0 || (int) Arr::get($summary, 'inclusiveFeeTax', 0) > 0)); $isSimplifiedMode = ($summary['displayMode'] ?? '') === 'simplified'; if ($isSimplifiedMode && !empty($summary['simpleLine'])) { $rows .= '' . '' . esc_html((string) $summary['simpleLine']['label']) . '' . '' . esc_html((string) $summary['simpleLine']['value']) . '' . ''; // Simplified mode: single tax line only, skip the detailed breakdown below. return $this->wrapTaxBreakdownBox($rows); } if (!empty($foldedRateLines)) { $colHeadStyle = 'width:58%;padding:3px 8px 3px 0;font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:0.06em;color:#64748b;vertical-align:top;'; $colHeadBaseStyle = '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;'; $colHeadTaxStyle = 'width:18%;padding: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;'; $rows .= '' . esc_html__('Tax breakdown by rate', 'fluent-cart') . ''; $nestedTable = ''; $nestedTable .= '' . '' . '' . '' . ''; foreach ($foldedRateLines as $foldedRow) { $foldedStyle = !empty($foldedRow['inclusive']) ? $mutedStyle : $normalStyle; $foldedStyleR = $foldedStyle . $valueStyle; $nestedTable .= '' . '' . '' . '' . ''; } $nestedTable .= '
' . esc_html__('Rate', 'fluent-cart') . '' . esc_html__('Taxable base', 'fluent-cart') . '' . esc_html__('Tax', 'fluent-cart') . '
' . esc_html((string) $foldedRow['label']) . '' . CurrencySettings::getPriceHtml((int) $foldedRow['base'], $currency) . '' . CurrencySettings::getPriceHtml((int) $foldedRow['tax'], $currency) . '
'; $rows .= '' . $nestedTable . ''; if ($isRcOrder) { $rcReversedTotalValue = $rcReversedTotal > 0 ? CurrencySettings::getPriceHtml($rcReversedTotal, $currency) : esc_html__('Charge reversed', 'fluent-cart'); $rows .= '' . '' . esc_html__('VAT reversed', 'fluent-cart') . '' . '' . $rcReversedTotalValue . '' . ''; return $this->wrapTaxBreakdownBox($rows); } $rows .= '' . '' . esc_html__('Total tax', 'fluent-cart') . '' . '' . CurrencySettings::getPriceHtml((int) $summary['totalOrderTax'], $currency) . '' . ''; if ($includedInPrices > 0) { $rows .= '' . '' . esc_html__('of which included in prices', 'fluent-cart') . '' . '' . CurrencySettings::getPriceHtml($includedInPrices, $currency) . '' . ''; } if ($summary['payableTax'] > 0 && $includedInPrices > 0) { $payableStyle = $totalStyle; $rows .= '' . '' . esc_html__('Payable now (added)', 'fluent-cart') . '' . '' . CurrencySettings::getPriceHtml((int) $summary['payableTax'], $currency) . '' . ''; } return $this->wrapTaxBreakdownBox($rows); } if ($isRcOrder) { $rows .= '' . esc_html__('TAX SUMMARY', 'fluent-cart') . ''; $rows .= '' . '' . esc_html__('Tax reversed', 'fluent-cart') . '' . '' . $rcReversedValue . '' . ''; return $this->wrapTaxBreakdownBox($rows); } $rows .= '' . esc_html__('TAX SUMMARY', 'fluent-cart') . ''; if (!empty($taxRateLines) && $shouldShowBreakdown) { foreach ($taxRateLines as $taxLine) { $taxLineStyle = !empty($taxLine['inclusive']) ? $mutedStyle : $normalStyle; $rows .= '' . '' . esc_html($taxLine['label']) . '' . '' . CurrencySettings::getPriceHtml($taxLine['order_tax'], $currency) . '' . ''; } } if (empty($taxRateLines) && $summary['inclusiveTax'] > 0 && $shouldShowBreakdown) { $rows .= '' . '' . esc_html__('Included in item prices', 'fluent-cart') . '' . '' . CurrencySettings::getPriceHtml($summary['inclusiveTax'], $currency) . '' . ''; } if (empty($taxRateLines) && $summary['exclusiveTax'] > 0 && $shouldShowBreakdown) { $rows .= '' . '' . esc_html__('Added on products', 'fluent-cart') . '' . '' . CurrencySettings::getPriceHtml($summary['exclusiveTax'], $currency) . '' . ''; } if ($shouldShowBreakdown) { foreach ($opFeeRows as $feeRow) { $feeLineStyle = $feeRow['inclusive'] ? $mutedStyle : $normalStyle; $rows .= '' . '' . esc_html($feeRow['display_label']) . '' . '' . CurrencySettings::getPriceHtml($feeRow['tax_amount'], $currency) . '' . ''; } } if ($summary['shippingTax'] > 0 && $shouldShowBreakdown) { $isShippingInclusive = TaxSummaryHelper::isShippingTaxInclusive($this->order); $shippingRowStyle = $isShippingInclusive ? $mutedStyle : $normalStyle; if (!empty($shippingTaxLines)) { foreach ($shippingTaxLines as $shippingTaxLine) { $rows .= '' . '' . esc_html($shippingTaxLine['label']) . '' . '' . CurrencySettings::getPriceHtml($shippingTaxLine['shipping_tax'], $currency) . '' . ''; } } else { $shippingRowLabel = $isShippingInclusive ? esc_html__('Included in shipping prices', 'fluent-cart') : esc_html__('Added on shipping', 'fluent-cart'); $rows .= '' . '' . $shippingRowLabel . '' . '' . CurrencySettings::getPriceHtml($summary['shippingTax'], $currency) . '' . ''; } } if ($summary['payableTax'] > 0) { $rows .= '' . '' . esc_html__('Total payable tax', 'fluent-cart') . '' . '' . CurrencySettings::getPriceHtml($summary['payableTax'], $currency) . '' . ''; } if ($summary['inclusiveTax'] > 0 || !empty($summary['inclusiveFeeTax'])) { $rows .= '' . '' . esc_html__('Total tax in this order', 'fluent-cart') . '' . '' . CurrencySettings::getPriceHtml($summary['totalOrderTax'], $currency) . '' . ''; } return $this->wrapTaxBreakdownBox($rows); } /** * Wrap the accumulated tax-breakdown rows in their own grey rounded box, * right-aligned to a fixed 400px column. * * The tax breakdown is the only thing that lives inside the grey box; the * surrounding Subtotal/Discount/Shipping/Fees rows (above) and Refund/Total/ * Payment rows (below) are rendered as plain rows by the summary table and * stay outside this wrapper. A table-based 400px right-aligned wrapper is used * (not a div) so PDF renderers (mPDF/Dompdf) and email clients honour the * width/alignment, matching the boxed treatment on the thank-you/customer * surfaces. Consumed by the PDF receipt templates via {{order.tax_breakdown}}. * * @param string $rows Inner rows for the tax breakdown. * @return string A single cell carrying the grey box. */ private function wrapTaxBreakdownBox(string $rows): string { if ($rows === '') { return ''; } $boxStyle = 'background-color:rgb(249,250,251);padding:16px;border-radius:8px;'; $nestedTable = '' . $rows . '
'; return '' . '' . '' . '
' . $nestedTable . '
' . ''; } private function resolveTaxRateLabel($orderTaxRate): string { $taxRate = $orderTaxRate->tax_rate ?? null; if ($taxRate) { $name = (string) Arr::get($taxRate, 'name', ''); $rate = Arr::get($taxRate, 'rate'); if ($name !== '' && is_numeric($rate)) { $rate = (string) $rate; if (strpos($rate, '.') !== false) { $rate = rtrim(rtrim($rate, '0'), '.'); } return $name . ' (' . $rate . '%)'; } if ($name !== '') { return $name; } } return __('Tax', 'fluent-cart'); } public function getSubscriptions() { return ''; } /** * Returns formatted store VAT display string, e.g. "VAT: NL123456789B01". * Returns empty string if no store VAT is configured for this order. */ public function getStoreVatDisplay(): string { if (!$this->order) { return ''; } $orderTaxRate = $this->order->orderTaxRates ? $this->order->orderTaxRates->first() : null; if (!$orderTaxRate) { return ''; } $storeVatNumber = Arr::get($orderTaxRate->meta ?? [], 'store_vat_number', ''); if (empty($storeVatNumber)) { return ''; } $taxCountry = Arr::get($orderTaxRate->meta ?? [], 'tax_country', ''); $label = \FluentCart\App\Modules\Tax\TaxModule::getCountryTaxTitle($taxCountry); return esc_html($label) . ': ' . esc_html($storeVatNumber); } /** * Returns formatted buyer VAT display string, e.g. "VAT/Tax ID: XX123456". * Checks business_info first, then falls back to legacy VAT storage. */ public function getBuyerVatDisplay(): string { if (!$this->order) { return ''; } $vatNumber = $this->order->getCustomerTaxNumber(); if (!empty($vatNumber)) { $label = __('VAT/Tax ID', 'fluent-cart'); return esc_html($label) . ': ' . esc_html($vatNumber); } return ''; } /** * Returns buyer company name from billing address meta or VAT reverse charge data. */ public function getBuyerCompanyName(): string { if (!$this->order) { return ''; } // Check billing address meta first if ($this->order->billing_address) { $companyName = Arr::get($this->order->billing_address->meta ?? [], 'other_data.company_name', ''); if (!empty($companyName)) { return esc_html($companyName); } } return esc_html($this->order->getCustomerTaxName()); } public function getBuyerLegalRegistrationId(): string { if (!$this->order) { return ''; } if ($this->order->billing_address) { $regId = Arr::get($this->order->billing_address->meta ?? [], 'other_data.legal_registration_id', ''); if (!empty($regId)) { return esc_html($regId); } } return esc_html(Arr::get($this->order->getBusinessInfo(), 'legal_registration_id', '')); } public function getBuyerReverseChargeDeclaration(): string { if (!$this->order) { return ''; } return esc_html(Arr::get($this->order->getBusinessInfo(), 'reverse_charge_declaration', '')); } // ------------------------------------------------------------------------- // Store business info — reads from snapshotted fct_order_meta[store_business_info] // with live StoreSettings fallback for orders placed before this feature. // ------------------------------------------------------------------------- private function getStoreBusinessField(string $field): string { if (!$this->order) { return ''; } $snapshot = $this->order->getMeta('store_business_info', false); if ($snapshot !== false && isset($snapshot[$field])) { return (string) $snapshot[$field]; } return (string) $this->storeSettings->get($field, ''); } public function getStoreCompanyName(): string { return esc_html($this->getStoreBusinessField('company_name')); } public function getStoreCompanyDisplay(): string { $val = $this->getStoreBusinessField('company_name'); if (empty($val)) { return ''; } /* translators: %1$s: store company name */ return esc_html(sprintf(__('Company: %1$s', 'fluent-cart'), $val)); } public function getStoreLegalRegistrationId(): string { return esc_html($this->getStoreBusinessField('legal_registration_id')); } public function getStoreLegalRegistrationDisplay(): string { $val = $this->getStoreBusinessField('legal_registration_id'); if (empty($val)) { return ''; } /* translators: %1$s: store legal registration ID */ return esc_html(sprintf(__('Reg. ID: %1$s', 'fluent-cart'), $val)); } public function getStoreSellerVatId(): string { return esc_html($this->getStoreBusinessField('seller_vat_id')); } public function getStoreSellerVatDisplay(): string { $val = $this->getStoreBusinessField('seller_vat_id'); if (empty($val)) { return ''; } /* translators: %1$s: store seller VAT ID */ return esc_html(sprintf(__('VAT ID: %1$s', 'fluent-cart'), $val)); } public function getStoreSellerTaxId(): string { return esc_html($this->getStoreBusinessField('seller_tax_id')); } public function getStoreTaxDisplay(): string { $val = $this->getStoreBusinessField('seller_tax_id'); if (empty($val)) { return ''; } /* translators: %1$s: store seller tax ID */ return esc_html(sprintf(__('Tax ID: %1$s', 'fluent-cart'), $val)); } }