# woocommerce-pos/1.10.12/includes/Services/Receipt_Data_Schema.php

WCPOS – Point of Sale (POS) plugin for WooCommerce, version 1.10.12. 1,660 lines.

- Page: https://pluginprobe.com/plugins/woocommerce-pos/1.10.12/code/includes/Services/Receipt_Data_Schema.php
- Raw: https://pluginprobe.com/plugins/woocommerce-pos/1.10.12/raw/includes/Services/Receipt_Data_Schema.php
- Modified: 2026-09-06T10:00:12+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/woocommerce-pos/1.10.12/code/includes/Services/Receipt_Data_Schema.php#L10-L20`.

```php
<?php
/**
 * Receipt data schema constants.
 *
 * @package WCPOS\WooCommercePOS\Services
 */

namespace WCPOS\WooCommercePOS\Services;

/**
 * Receipt_Data_Schema class.
 */
class Receipt_Data_Schema {
	/**
	 * Top-level keys required in a receipt payload.
	 *
	 * `presentation_hints` is required but internal: builders use it for
	 * formatting inputs such as locale, timezone, currency placement, and
	 * decimal separators. Template-facing mode signals belong in subject
	 * sections like `tax` when they are data-derived, not freely choosable by
	 * the template author, and required for logicless template branching.
	 */
	const REQUIRED_KEYS = array(
		'order',
		'store',
		'cashier',
		'customer',
		'lines',
		'fees',
		'shipping',
		'discounts',
		'totals',
		'tax',
		'tax_summary',
		'has_tax_summary',
		'payments',
		'refunds',
		'fiscal',
		'presentation_hints',
		'i18n',
	);

	/**
	 * Receipt data schema contract version.
	 */
	const SCHEMA_VERSION = '1.2.0';

	/**
	 * Money keys that must be present in totals.
	 */
	const TOTAL_MONEY_KEYS = array(
		'subtotal',
		'subtotal_incl',
		'subtotal_excl',
		'discount_total',
		'discount_total_incl',
		'discount_total_excl',
		'sale_savings_total',
		'sale_savings_total_incl',
		'sale_savings_total_excl',
		'total_saved',
		'total_saved_incl',
		'total_saved_excl',
		'tax_total',
		'total',
		'total_incl',
		'total_excl',
		'paid_total',
		'change_total',
		'refund_total',
		'net_total',
	);

	/**
	 * Money fields where a zero value should remain numeric 0 (Mustache-falsy)
	 * so that section guards like {{#change}}...{{/change}} treat them as empty.
	 *
	 * All other money fields are always formatted to a currency string,
	 * including when their value is zero (e.g. "$0.00").
	 */
	const ZERO_FALSY_MONEY_FIELDS = array(
		'change',
		'tendered',
		'discounts',
		'discounts_incl',
		'discounts_excl',
		'unit_savings',
		'unit_savings_incl',
		'unit_savings_excl',
		'line_savings',
		'line_savings_incl',
		'line_savings_excl',
		'change_total',
		'discount_total',
		'discount_total_incl',
		'discount_total_excl',
		'sale_savings_total',
		'sale_savings_total_incl',
		'sale_savings_total_excl',
		'total_saved',
		'total_saved_incl',
		'total_saved_excl',
		'refund_total',
		'total_refunded',
	);

	/**
	 * Field names (terminal key segment) that represent money values.
	 *
	 * Used by the logicless renderer to auto-format currency output.
	 * Matched against the last segment of dot-path keys during substitution.
	 */
	const MONEY_FIELDS = array(
		// Line items (display).
		'regular_price',
		'selling_price',
		'unit_savings',
		'line_regular_total',
		'line_selling_total',
		'line_savings',
		'unit_subtotal',
		'unit_price',
		'line_subtotal',
		'discounts',
		'line_total',
		// Line items (explicit incl/excl).
		'unit_subtotal_incl',
		'unit_subtotal_excl',
		'unit_price_incl',
		'unit_price_excl',
		'line_subtotal_incl',
		'line_subtotal_excl',
		'discounts_incl',
		'discounts_excl',
		'line_total_incl',
		'line_total_excl',
		'regular_price_incl',
		'regular_price_excl',
		'selling_price_incl',
		'selling_price_excl',
		'unit_savings_incl',
		'unit_savings_excl',
		'line_regular_total_incl',
		'line_regular_total_excl',
		'line_selling_total_incl',
		'line_selling_total_excl',
		'line_savings_incl',
		'line_savings_excl',
		// Shared by fees / shipping / discounts arrays AND by totals — same key
		// names appear in both contexts; listing once is enough since the
		// `array_flip` lookup uses values as keys.
		'total',
		'total_incl',
		'total_excl',
		// Totals (display + explicit incl/excl).
		'subtotal',
		'subtotal_incl',
		'subtotal_excl',
		'discount_total',
		'discount_total_incl',
		'discount_total_excl',
		'sale_savings_total',
		'sale_savings_total_incl',
		'sale_savings_total_excl',
		'total_saved',
		'total_saved_incl',
		'total_saved_excl',
		'tax_total',
		'paid_total',
		'change_total',
		'refund_total',
		'net_total',
		// Per-line refund.
		'total_refunded',
		// Refund-level totals.
		'shipping_total',
		'shipping_tax',
		// Tax summary.
		'taxable_amount_excl',
		'tax_amount',
		'taxable_amount_incl',
		// Payments.
		'amount',
		'tendered',
		'change',
	);

	/**
	 * Format money fields in receipt data using wc_price().
	 *
	 * Recursively walks the data structure and replaces numeric values
	 * whose terminal key matches a known money field with a formatted
	 * currency string (e.g. "$29.99").
	 *
	 * @param array               $data               Receipt data array (or nested sub-array).
	 * @param string              $currency           WooCommerce currency code.
	 * @param array<string,mixed> $presentation_hints Receipt presentation hints.
	 *
	 * @return array Data with money fields formatted as strings.
	 */
	public static function format_money_fields( array $data, string $currency = 'USD', array $presentation_hints = array() ): array {
		static $lookup = null;
		static $zero_falsy = null;
		if ( null === $lookup ) {
			$lookup     = array_flip( self::MONEY_FIELDS );
			$zero_falsy = array_flip( self::ZERO_FALSY_MONEY_FIELDS );
		}

		if ( empty( $presentation_hints ) && isset( $data['presentation_hints'] ) && \is_array( $data['presentation_hints'] ) ) {
			$presentation_hints = $data['presentation_hints'];
		}

		$price_args = self::get_price_format_args( $currency, $presentation_hints );
		$result = array();

		foreach ( $data as $k => $value ) {
			if ( \is_array( $value ) ) {
				$result[ $k ] = self::format_money_fields( $value, $currency, $presentation_hints );
			} elseif ( is_numeric( $value ) && isset( $lookup[ $k ] ) ) {
				// ──────────────────────────────────────────────────────────
				// Money fields: KEEP the numeric value at the bare key and
				// ADD a `<key>_display` companion holding the locale-formatted
				// currency string. Mirrors the JS `formatReceiptData` shape
				// exactly so a single Mustache template renders the same way
				// in both the studio (JS) and production print (PHP).
				//
				// DO NOT change this back to in-place replacement — bare keys
				// must be numeric so app code can still do math on them, and
				// templates have a stable `_display` variant to render
				// currency without re-implementing wc_price() in JS.
				// ──────────────────────────────────────────────────────────
				$numeric    = (float) $value;
				$is_zero_falsy = ( 0.0 === $numeric && isset( $zero_falsy[ $k ] ) );
				// Conditional-display fields (change, tendered, discounts, etc.) keep
				// the bare key as integer 0 when the value is zero so Mustache section
				// guards (`{{#change}}…{{/change}}`) treat them as falsy and the rest
				// of the test suite's `assertSame( 0, … )` checks stay green.
				$result[ $k ]              = $is_zero_falsy ? 0 : $numeric;
				$result[ $k . '_display' ] = $is_zero_falsy
					? ''
					: html_entity_decode(
						wp_strip_all_tags(
							wc_price( $numeric, $price_args )
						),
						ENT_QUOTES | ENT_SUBSTITUTE,
						'UTF-8'
					);
			} else {
				$result[ $k ] = $value;
			}
		}

		return $result;
	}

	/**
	 * Build wc_price() arguments from presentation hints.
	 *
	 * @param string              $currency           WooCommerce currency code.
	 * @param array<string,mixed> $presentation_hints Receipt presentation hints.
	 *
	 * @return array<string,mixed>
	 */
	private static function get_price_format_args( string $currency, array $presentation_hints ): array {
		$args = array( 'currency' => $currency );

		if ( isset( $presentation_hints['currency_position'] ) ) {
			$args['price_format'] = self::get_price_format_for_position( (string) $presentation_hints['currency_position'] );
		}
		if ( isset( $presentation_hints['price_decimal_separator'] ) ) {
			$args['decimal_separator'] = (string) $presentation_hints['price_decimal_separator'];
		}
		if ( isset( $presentation_hints['price_thousand_separator'] ) ) {
			$args['thousand_separator'] = (string) $presentation_hints['price_thousand_separator'];
		}
		if ( isset( $presentation_hints['price_num_decimals'] ) && is_numeric( $presentation_hints['price_num_decimals'] ) ) {
			$args['decimals'] = (int) $presentation_hints['price_num_decimals'];
		}

		return $args;
	}

	/**
	 * Convert a WooCommerce currency position option to a wc_price format.
	 *
	 * @param string $position WooCommerce currency position.
	 *
	 * @return string wc_price format.
	 */
	private static function get_price_format_for_position( string $position ): string {
		switch ( $position ) {
			case 'right':
				return '%2$s%1$s';
			case 'left_space':
				return '%1$s %2$s';
			case 'right_space':
				return '%2$s %1$s';
			case 'left':
			default:
				return '%1$s%2$s';
		}
	}

	/**
	 * Get the field tree for the template editor field picker.
	 *
	 * Returns a structured array describing template-picker sections and fields
	 * from the receipt_data contract. Used by the JS field picker sidebar.
	 * Internal sections (e.g. presentation_hints) are intentionally excluded.
	 *
	 * @return array<string, array{label: string, is_array?: bool, fields: array<string, array{type: string, label: string}>}>
	 */
	public static function get_field_tree(): array {
		return array(
			'order'       => array(
				'label'  => /* translators: Label for a receipt data field in the template editor. */ __( 'Order', 'woocommerce-pos' ),
				'fields' => array(
					'id'           => array(
						'type'  => 'number',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Order ID', 'woocommerce-pos' ),
					),
					'number'       => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Order Number', 'woocommerce-pos' ),
					),
					'currency'     => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Currency', 'woocommerce-pos' ),
					),
					'customer_note' => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Customer Note', 'woocommerce-pos' ),
					),
					'wc_status'    => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'WC Status', 'woocommerce-pos' ),
					),
					'status_label' => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Status Label', 'woocommerce-pos' ),
					),
					'created_via'  => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Created Via', 'woocommerce-pos' ),
					),
					'needs_payment' => array(
						'type'  => 'boolean',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Needs Payment', 'woocommerce-pos' ),
					),
					'payment_url'  => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Payment URL', 'woocommerce-pos' ),
					),
				),
			),
			'order.created' => array(
				'label'  => /* translators: Label for a receipt data field in the template editor. */ __( 'Order Created', 'woocommerce-pos' ),
				'fields' => self::get_date_field_tree_fields(),
			),
			'order.paid' => array(
				'label'  => /* translators: Label for a receipt data field in the template editor. */ __( 'Order Paid', 'woocommerce-pos' ),
				'fields' => self::get_date_field_tree_fields(),
			),
			'order.completed' => array(
				'label'  => /* translators: Label for a receipt data field in the template editor. */ __( 'Order Completed', 'woocommerce-pos' ),
				'fields' => self::get_date_field_tree_fields(),
			),
			'order.printed' => array(
				'label'  => /* translators: Label for a receipt data field in the template editor. */ __( 'Receipt Printed', 'woocommerce-pos' ),
				'fields' => self::get_date_field_tree_fields(),
			),
			'store'       => array(
				'label'  => /* translators: Label for a receipt data field in the template editor. */ __( 'Store', 'woocommerce-pos' ),
				'fields' => array(
					'id'                      => array(
						'type'  => 'number',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Store ID', 'woocommerce-pos' ),
					),
					'name'                    => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Store Name', 'woocommerce-pos' ),
					),
					'address_lines'           => array(
						'type'  => 'string[]',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Address Lines', 'woocommerce-pos' ),
					),
					'phone'                   => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Phone', 'woocommerce-pos' ),
					),
					'email'                   => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Email', 'woocommerce-pos' ),
					),
					'logo'                    => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Logo URL', 'woocommerce-pos' ),
					),
					'opening_hours'           => array(
						'type'     => 'string',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Opening Hours', 'woocommerce-pos' ),
					),
					'opening_hours_vertical' => array(
						'type'     => 'string',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Opening Hours (Vertical)', 'woocommerce-pos' ),
					),
					'opening_hours_inline'   => array(
						'type'     => 'string',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Opening Hours (Inline)', 'woocommerce-pos' ),
					),
					'opening_hours_notes'    => array(
						'type'     => 'string',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Opening Hours Notes', 'woocommerce-pos' ),
					),
					'personal_notes'          => array(
						'type'     => 'string',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Personal Notes', 'woocommerce-pos' ),
					),
					'policies_and_conditions' => array(
						'type'     => 'string',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Policies & Conditions', 'woocommerce-pos' ),
					),
					'footer_imprint'          => array(
						'type'     => 'string',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Footer Imprint', 'woocommerce-pos' ),
					),
				),
			),
			'cashier'     => array(
				'label'  => /* translators: Label for a receipt data field in the template editor. */ __( 'Cashier', 'woocommerce-pos' ),
				'fields' => array(
					'id'   => array(
						'type'  => 'number',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Cashier ID', 'woocommerce-pos' ),
					),
					'name' => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Cashier Name', 'woocommerce-pos' ),
					),
				),
			),
			'customer'    => array(
				'label'  => /* translators: Label for a receipt data field in the template editor. */ __( 'Customer', 'woocommerce-pos' ),
				'fields' => array(
					'id'               => array(
						'type'  => 'number',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Customer ID', 'woocommerce-pos' ),
					),
					'name'             => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Customer Name', 'woocommerce-pos' ),
					),
					'billing_address'  => array(
						'type'  => 'object',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Billing Address', 'woocommerce-pos' ),
					),
					'shipping_address' => array(
						'type'  => 'object',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Shipping Address', 'woocommerce-pos' ),
					),
				),
			),
			'customer.tax_ids' => array(
				'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Customer Tax IDs', 'woocommerce-pos' ),
				'is_array' => true,
				'fields'   => array(
					'type'    => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Type', 'woocommerce-pos' ),
					),
					'value'   => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Value', 'woocommerce-pos' ),
					),
					'country' => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Country', 'woocommerce-pos' ),
					),
					'label'   => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Label', 'woocommerce-pos' ),
					),
				),
			),
			'store.tax_ids' => array(
				'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Store Tax IDs', 'woocommerce-pos' ),
				'is_array' => true,
				'fields'   => array(
					'type'    => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Type', 'woocommerce-pos' ),
					),
					'value'   => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Value', 'woocommerce-pos' ),
					),
					'country' => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Country', 'woocommerce-pos' ),
					),
					'label'   => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Label', 'woocommerce-pos' ),
					),
				),
			),
			'store.address' => array(
				'label'  => /* translators: Label for a receipt data field in the template editor. */ __( 'Store Address', 'woocommerce-pos' ),
				'fields' => array(
					'address_1' => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Address line 1', 'woocommerce-pos' ),
					),
					'address_2' => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Address line 2', 'woocommerce-pos' ),
					),
					'city'      => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'City', 'woocommerce-pos' ),
					),
					'state'     => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'State / Region', 'woocommerce-pos' ),
					),
					'postcode'  => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Postcode', 'woocommerce-pos' ),
					),
					'country'   => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Country', 'woocommerce-pos' ),
					),
				),
			),
			'lines'       => array(
				'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Line Items', 'woocommerce-pos' ),
				'is_array' => true,
				'fields'   => array(
					'key'                => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Item Key', 'woocommerce-pos' ),
					),
					'sku'                => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'SKU', 'woocommerce-pos' ),
					),
					'name'               => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Product Name', 'woocommerce-pos' ),
					),
					'qty'                => array(
						'type'  => 'number',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Quantity', 'woocommerce-pos' ),
					),
					'qty_refunded'       => array(
						'type'  => 'number',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Quantity Refunded', 'woocommerce-pos' ),
					),
					'regular_price'      => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Regular price per item', 'woocommerce-pos' ),
					),
					'regular_price_incl' => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Regular price per item (incl tax)', 'woocommerce-pos' ),
					),
					'regular_price_excl' => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Regular price per item (excl tax)', 'woocommerce-pos' ),
					),
					'selling_price'      => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Selling price per item, before coupons', 'woocommerce-pos' ),
					),
					'selling_price_incl' => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Selling price per item, before coupons (incl tax)', 'woocommerce-pos' ),
					),
					'selling_price_excl' => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Selling price per item, before coupons (excl tax)', 'woocommerce-pos' ),
					),
					'unit_savings'       => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Savings per item', 'woocommerce-pos' ),
					),
					'unit_savings_incl'  => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Savings per item (incl tax)', 'woocommerce-pos' ),
					),
					'unit_savings_excl'  => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Savings per item (excl tax)', 'woocommerce-pos' ),
					),
					'line_regular_total' => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Regular-price total', 'woocommerce-pos' ),
					),
					'line_regular_total_incl' => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Regular-price total (incl tax)', 'woocommerce-pos' ),
					),
					'line_regular_total_excl' => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Regular-price total (excl tax)', 'woocommerce-pos' ),
					),
					'line_selling_total' => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Selling-price total, before coupons', 'woocommerce-pos' ),
					),
					'line_selling_total_incl' => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Selling-price total, before coupons (incl tax)', 'woocommerce-pos' ),
					),
					'line_selling_total_excl' => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Selling-price total, before coupons (excl tax)', 'woocommerce-pos' ),
					),
					'line_savings'       => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Total savings for this item', 'woocommerce-pos' ),
					),
					'line_savings_incl'  => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Total savings for this item (incl tax)', 'woocommerce-pos' ),
					),
					'line_savings_excl'  => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Total savings for this item (excl tax)', 'woocommerce-pos' ),
					),
					'savings_in_discounts' => array(
						'type'  => 'boolean',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Savings already included in WooCommerce discounts', 'woocommerce-pos' ),
					),
					'unit_subtotal'      => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Unit Subtotal', 'woocommerce-pos' ),
					),
					'unit_subtotal_incl' => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Unit Subtotal (incl tax)', 'woocommerce-pos' ),
					),
					'unit_subtotal_excl' => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Unit Subtotal (excl tax)', 'woocommerce-pos' ),
					),
					'unit_price'         => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Unit Price', 'woocommerce-pos' ),
					),
					'unit_price_incl'    => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Unit Price (incl tax)', 'woocommerce-pos' ),
					),
					'unit_price_excl'    => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Unit Price (excl tax)', 'woocommerce-pos' ),
					),
					'line_subtotal'      => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Subtotal', 'woocommerce-pos' ),
					),
					'line_subtotal_incl' => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Subtotal (incl tax)', 'woocommerce-pos' ),
					),
					'line_subtotal_excl' => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Subtotal (excl tax)', 'woocommerce-pos' ),
					),
					'discounts'          => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Discounts', 'woocommerce-pos' ),
					),
					'discounts_incl'     => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Discounts (incl tax)', 'woocommerce-pos' ),
					),
					'discounts_excl'     => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Discounts (excl tax)', 'woocommerce-pos' ),
					),
					'line_total'         => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Line Total', 'woocommerce-pos' ),
					),
					'line_total_incl'    => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Line Total (incl tax)', 'woocommerce-pos' ),
					),
					'line_total_excl'    => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Line Total (excl tax)', 'woocommerce-pos' ),
					),
					'total_refunded'     => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Total Refunded', 'woocommerce-pos' ),
					),
					'taxes'              => array(
						'type'  => 'array',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Line Taxes', 'woocommerce-pos' ),
					),
					'meta'               => array(
						'type'  => 'array',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Item Meta', 'woocommerce-pos' ),
					),
					'attributes'         => array(
						'type'  => 'array',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Product Attributes', 'woocommerce-pos' ),
					),
				),
			),
			'fees'        => array(
				'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Fees', 'woocommerce-pos' ),
				'is_array' => true,
				'fields'   => array(
					'label'      => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Fee Label', 'woocommerce-pos' ),
					),
					'total'      => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Total', 'woocommerce-pos' ),
					),
					'total_incl' => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Total (incl tax)', 'woocommerce-pos' ),
					),
					'total_excl' => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Total (excl tax)', 'woocommerce-pos' ),
					),
					'taxes'      => array(
						'type'  => 'array',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Fee Taxes', 'woocommerce-pos' ),
					),
					'meta'       => array(
						'type'  => 'array',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Fee Meta', 'woocommerce-pos' ),
					),
				),
			),
			'shipping'    => array(
				'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Shipping', 'woocommerce-pos' ),
				'is_array' => true,
				'fields'   => array(
					'label'      => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Shipping Label', 'woocommerce-pos' ),
					),
					'method_id'  => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Shipping Method ID', 'woocommerce-pos' ),
					),
					'total'      => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Total', 'woocommerce-pos' ),
					),
					'total_incl' => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Total (incl tax)', 'woocommerce-pos' ),
					),
					'total_excl' => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Total (excl tax)', 'woocommerce-pos' ),
					),
					'taxes'      => array(
						'type'  => 'array',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Shipping Taxes', 'woocommerce-pos' ),
					),
					'meta'       => array(
						'type'  => 'array',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Shipping Meta', 'woocommerce-pos' ),
					),
				),
			),
			'discounts'   => array(
				'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Discounts', 'woocommerce-pos' ),
				'is_array' => true,
				'fields'   => array(
					'label'         => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Discount Label', 'woocommerce-pos' ),
					),
					'code'          => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Coupon Code', 'woocommerce-pos' ),
					),
					'discount_type' => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Coupon Type', 'woocommerce-pos' ),
					),
					'total'         => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Total', 'woocommerce-pos' ),
					),
					'total_incl'    => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Total (incl tax)', 'woocommerce-pos' ),
					),
					'total_excl'    => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Total (excl tax)', 'woocommerce-pos' ),
					),
				),
			),
			'totals'      => array(
				'label'  => /* translators: Label for a receipt data field in the template editor. */ __( 'Totals', 'woocommerce-pos' ),
				'fields' => array(
					'subtotal'                => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Subtotal', 'woocommerce-pos' ),
					),
					'subtotal_incl'           => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Subtotal (incl tax)', 'woocommerce-pos' ),
					),
					'subtotal_excl'           => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Subtotal (excl tax)', 'woocommerce-pos' ),
					),
					'discount_total'          => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Discount Total', 'woocommerce-pos' ),
					),
					'discount_total_incl'     => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Discount Total (incl tax)', 'woocommerce-pos' ),
					),
					'discount_total_excl'     => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Discount Total (excl tax)', 'woocommerce-pos' ),
					),
					'sale_savings_total'      => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Sale Savings Total', 'woocommerce-pos' ),
					),
					'sale_savings_total_incl' => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Sale Savings Total (incl tax)', 'woocommerce-pos' ),
					),
					'sale_savings_total_excl' => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Sale Savings Total (excl tax)', 'woocommerce-pos' ),
					),
					'total_saved'             => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Total Saved (sale savings + discounts)', 'woocommerce-pos' ),
					),
					'total_saved_incl'        => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Total Saved (sale savings + discounts, incl tax)', 'woocommerce-pos' ),
					),
					'total_saved_excl'        => array(
						'type'     => 'money',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Total Saved (sale savings + discounts, excl tax)', 'woocommerce-pos' ),
					),
					'total_saved_complete'    => array(
						'type'  => 'boolean',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Total Saved Is Complete', 'woocommerce-pos' ),
					),
					'tax_total'               => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Tax Total', 'woocommerce-pos' ),
					),
					'total'                   => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Total', 'woocommerce-pos' ),
					),
					'total_incl'              => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Total (incl. tax)', 'woocommerce-pos' ),
					),
					'total_excl'              => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Total (excl. tax)', 'woocommerce-pos' ),
					),
					'paid_total'              => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Paid Total', 'woocommerce-pos' ),
					),
					'change_total'            => array(
						'type'  => 'money',
						'label' => /* translators: Template-editor field label for total cash returned to the customer after payments; not "change" meaning modify. */ __( 'Change', 'woocommerce-pos' ),
					),
					'refund_total'            => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Total', 'woocommerce-pos' ),
					),
					'net_total'               => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Net Total', 'woocommerce-pos' ),
					),
					'total_qty'               => array(
						'type'  => 'number',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Total Quantity', 'woocommerce-pos' ),
					),
					'line_count'              => array(
						'type'  => 'number',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Line Count', 'woocommerce-pos' ),
					),
				),
			),

			'tax'         => array(
				'label'  => /* translators: Label for a receipt data field in the template editor. */ __( 'Tax', 'woocommerce-pos' ),
				'fields' => array(
					'display'            => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Tax Display Mode', 'woocommerce-pos' ),
					),
					'display_incl'       => array(
						'type'  => 'boolean',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Tax Display Is Inclusive', 'woocommerce-pos' ),
					),
					'display_excl'       => array(
						'type'  => 'boolean',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Tax Display Is Exclusive', 'woocommerce-pos' ),
					),
					'breakdown'          => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Tax Breakdown Mode', 'woocommerce-pos' ),
					),
					'breakdown_hidden'   => array(
						'type'  => 'boolean',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Tax Breakdown Hidden', 'woocommerce-pos' ),
					),
					'breakdown_single'   => array(
						'type'  => 'boolean',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Tax Breakdown Single', 'woocommerce-pos' ),
					),
					'breakdown_itemized' => array(
						'type'  => 'boolean',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Tax Breakdown Itemized', 'woocommerce-pos' ),
					),
				),
			),
			'has_tax_summary' => array(
				'type'   => 'boolean',
				'label'  => /* translators: Label for a receipt data field in the template editor. */ __( 'Has Tax Summary', 'woocommerce-pos' ),
				'fields' => array(),
			),
			'tax_summary' => array(
				'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Tax Summary', 'woocommerce-pos' ),
				'is_array' => true,
				'fields'   => array(
					'code'                => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Tax Code', 'woocommerce-pos' ),
					),
					'label'               => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Tax Label', 'woocommerce-pos' ),
					),
					'rate'                => array(
						'type'  => 'number',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Tax Rate (%)', 'woocommerce-pos' ),
					),
					'compound'            => array(
						'type'  => 'boolean',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Compound Tax', 'woocommerce-pos' ),
					),
					'taxable_amount_excl' => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Taxable Amount (excl)', 'woocommerce-pos' ),
					),
					'tax_amount'          => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Tax Amount', 'woocommerce-pos' ),
					),
					'taxable_amount_incl' => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Taxable Amount (incl)', 'woocommerce-pos' ),
					),
				),
			),
			'payments'    => array(
				'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Payments', 'woocommerce-pos' ),
				'is_array' => true,
				'fields'   => array(
					'method_id'    => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Method ID', 'woocommerce-pos' ),
					),
					'method_title' => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Payment Method', 'woocommerce-pos' ),
					),
					'amount'       => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Amount', 'woocommerce-pos' ),
					),
					'tendered'     => array(
						'type'  => 'money',
						'label' => /* translators: Template-editor field label for the money received from the customer at checkout; use the target-language equivalent of "Received", not procurement tender/bid language. */ __( 'Tendered', 'woocommerce-pos' ),
					),
					'change'       => array(
						'type'  => 'money',
						'label' => /* translators: Template-editor field label for cash returned to the customer after payment; not "change" meaning modify. */ __( 'Change', 'woocommerce-pos' ),
					),
					'transaction_id' => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Transaction ID', 'woocommerce-pos' ),
					),
				),
			),
			'refunds'     => array(
				'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Refunds', 'woocommerce-pos' ),
				'is_array' => true,
				'fields'   => array(
					'id'                => array(
						'type'  => 'number',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund ID', 'woocommerce-pos' ),
					),
					'date'              => array(
						'type'  => 'object',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Date', 'woocommerce-pos' ),
					),
					'amount'            => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Amount', 'woocommerce-pos' ),
					),
					'subtotal'          => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Subtotal', 'woocommerce-pos' ),
					),
					'tax_total'         => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Tax Total', 'woocommerce-pos' ),
					),
					'shipping_total'    => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Shipping Total', 'woocommerce-pos' ),
					),
					'shipping_tax'      => array(
						'type'  => 'money',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Shipping Tax', 'woocommerce-pos' ),
					),
					'reason'            => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Reason', 'woocommerce-pos' ),
					),
					'refunded_by_id'    => array(
						'type'     => 'number',
						'nullable' => true,
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Refunded By (User ID)', 'woocommerce-pos' ),
					),
					'refunded_by_name'  => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refunded By (Name)', 'woocommerce-pos' ),
					),
					'refunded_payment'  => array(
						'type'  => 'boolean',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refunded Payment', 'woocommerce-pos' ),
					),
					'destination'       => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Destination', 'woocommerce-pos' ),
					),
					'gateway_id'        => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Gateway ID', 'woocommerce-pos' ),
					),
					'gateway_title'     => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Gateway Title', 'woocommerce-pos' ),
					),
					'processing_mode'   => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Processing Mode', 'woocommerce-pos' ),
					),
					'lines'             => array(
						'type'     => 'array',
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Lines', 'woocommerce-pos' ),
						'is_array' => true,
						'fields'   => array(
							'name'       => array(
								'type'  => 'string',
								'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Product Name', 'woocommerce-pos' ),
							),
							'sku'        => array(
								'type'  => 'string',
								'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'SKU', 'woocommerce-pos' ),
							),
							'qty'        => array(
								'type'  => 'number',
								'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Quantity', 'woocommerce-pos' ),
							),
							'total'      => array(
								'type'  => 'money',
								'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Line Total', 'woocommerce-pos' ),
							),
							'total_incl' => array(
								'type'  => 'money',
								'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Line Total (incl tax)', 'woocommerce-pos' ),
							),
							'total_excl' => array(
								'type'  => 'money',
								'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Line Total (excl tax)', 'woocommerce-pos' ),
							),
							'taxes'      => array(
								'type'  => 'array',
								'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Line Taxes', 'woocommerce-pos' ),
							),
						),
					),
					'fees'              => array(
						'type'     => 'array',
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Fees', 'woocommerce-pos' ),
						'is_array' => true,
						'fields'   => array(
							'label'      => array(
								'type'  => 'string',
								'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Fee Label', 'woocommerce-pos' ),
							),
							'total'      => array(
								'type'  => 'money',
								'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Fee Total', 'woocommerce-pos' ),
							),
							'total_incl' => array(
								'type'  => 'money',
								'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Fee Total (incl tax)', 'woocommerce-pos' ),
							),
							'total_excl' => array(
								'type'  => 'money',
								'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Fee Total (excl tax)', 'woocommerce-pos' ),
							),
							'taxes'      => array(
								'type'  => 'array',
								'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Fee Taxes', 'woocommerce-pos' ),
							),
						),
					),
					'shipping'          => array(
						'type'     => 'array',
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Shipping', 'woocommerce-pos' ),
						'is_array' => true,
						'fields'   => array(
							'label'      => array(
								'type'  => 'string',
								'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Shipping Label', 'woocommerce-pos' ),
							),
							'method_id'  => array(
								'type'  => 'string',
								'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Shipping Method ID', 'woocommerce-pos' ),
							),
							'total'      => array(
								'type'  => 'money',
								'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Shipping Total', 'woocommerce-pos' ),
							),
							'total_incl' => array(
								'type'  => 'money',
								'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Shipping Total (incl tax)', 'woocommerce-pos' ),
							),
							'total_excl' => array(
								'type'  => 'money',
								'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Shipping Total (excl tax)', 'woocommerce-pos' ),
							),
							'taxes'      => array(
								'type'  => 'array',
								'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Refund Shipping Taxes', 'woocommerce-pos' ),
							),
						),
					),
				),
			),
			'fiscal'      => array(
				'label'  => /* translators: Label for a receipt data field in the template editor. */ __( 'Fiscal', 'woocommerce-pos' ),
				'fields' => array(
					'immutable_id'      => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Immutable ID', 'woocommerce-pos' ),
					),
					'receipt_number'    => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Receipt Number', 'woocommerce-pos' ),
					),
					'sequence'          => array(
						'type'  => 'number',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Sequence', 'woocommerce-pos' ),
					),
					'hash'              => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Hash', 'woocommerce-pos' ),
					),
					'qr_payload'        => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'QR Payload', 'woocommerce-pos' ),
					),
					'tax_agency_code'   => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Tax Agency Code', 'woocommerce-pos' ),
					),
					'signed_at'         => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Signed At', 'woocommerce-pos' ),
					),
					'signature_excerpt' => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Signature Excerpt', 'woocommerce-pos' ),
					),
					'document_label'    => array(
						'type'  => 'string',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Document Label', 'woocommerce-pos' ),
					),
					'is_reprint'        => array(
						'type'  => 'boolean',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Is Reprint', 'woocommerce-pos' ),
					),
					'reprint_count'     => array(
						'type'  => 'number',
						'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Reprint Count', 'woocommerce-pos' ),
					),
					'extra_fields'      => array(
						'type'     => 'array',
						'label'    => /* translators: Label for a receipt data field in the template editor. */ __( 'Extra Fields', 'woocommerce-pos' ),
						'is_array' => true,
						'fields'   => array(
							'label' => array(
								'type'  => 'string',
								'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Label', 'woocommerce-pos' ),
							),
							'value' => array(
								'type'  => 'string',
								'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Value', 'woocommerce-pos' ),
							),
						),
					),
				),
			),
			'i18n'        => array(
				'label'  => /* translators: Label for a receipt data field in the template editor. */ __( 'Labels (i18n)', 'woocommerce-pos' ),
				'fields' => self::get_i18n_field_tree_fields(),
			),
		);
	}


	/**
	 * Get field metadata for every canonical i18n receipt label.
	 *
	 * @return array<string, array{type: string, label: string}>
	 */
	private static function get_i18n_field_tree_fields(): array {
		$fields = array();

		foreach ( Receipt_I18n_Labels::get_labels() as $key => $label ) {
			$fields[ $key ] = array(
				'type'  => 'string',
				'label' => $label,
			);
		}

		return $fields;
	}

	/**
	 * Get field metadata for a semantic date section.
	 *
	 * @return array<string, array{type: string, label: string}>
	 */
	private static function get_date_field_tree_fields(): array {
		return array(
			'datetime'       => array(
				'type'  => 'string',
				'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Date & Time', 'woocommerce-pos' ),
			),
			'date'           => array(
				'type'  => 'string',
				'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Date', 'woocommerce-pos' ),
			),
			'time'           => array(
				'type'  => 'string',
				'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Time', 'woocommerce-pos' ),
			),
			'datetime_short' => array(
				'type'  => 'string',
				'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Short Date & Time', 'woocommerce-pos' ),
			),
			'datetime_long'  => array(
				'type'  => 'string',
				'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Long Date & Time', 'woocommerce-pos' ),
			),
			'datetime_full'  => array(
				'type'  => 'string',
				'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Full Date & Time', 'woocommerce-pos' ),
			),
			'date_short'     => array(
				'type'  => 'string',
				'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Short Date', 'woocommerce-pos' ),
			),
			'date_long'      => array(
				'type'  => 'string',
				'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Long Date', 'woocommerce-pos' ),
			),
			'date_full'      => array(
				'type'  => 'string',
				'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Full Date', 'woocommerce-pos' ),
			),
			'date_ymd'       => array(
				'type'  => 'string',
				'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'YYYY-MM-DD', 'woocommerce-pos' ),
			),
			'date_dmy'       => array(
				'type'  => 'string',
				'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'DD/MM/YYYY', 'woocommerce-pos' ),
			),
			'date_mdy'       => array(
				'type'  => 'string',
				'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'MM/DD/YYYY', 'woocommerce-pos' ),
			),
			'weekday_short'  => array(
				'type'  => 'string',
				'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Weekday Short', 'woocommerce-pos' ),
			),
			'weekday_long'   => array(
				'type'  => 'string',
				'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Weekday Long', 'woocommerce-pos' ),
			),
			'day'            => array(
				'type'  => 'string',
				'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Day', 'woocommerce-pos' ),
			),
			'month'          => array(
				'type'  => 'string',
				'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Month Number', 'woocommerce-pos' ),
			),
			'month_short'    => array(
				'type'  => 'string',
				'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Month Short', 'woocommerce-pos' ),
			),
			'month_long'     => array(
				'type'  => 'string',
				'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Month Long', 'woocommerce-pos' ),
			),
			'year'           => array(
				'type'  => 'string',
				'label' => /* translators: Label for a receipt data field in the template editor. */ __( 'Year', 'woocommerce-pos' ),
			),
		);
	}

	/**
	 * Get the JSON Schema for canonical receipt_data payloads.
	 *
	 * PHP remains the source of truth in this repository. This export is used by
	 * generated TypeScript artifacts and downstream renderer/studio checks.
	 *
	 * @return array<string, mixed> JSON-Schema-compatible receipt data schema.
	 */
	public static function get_json_schema(): array {
		$schema = array(
			'$schema'              => 'https://json-schema.org/draft/2020-12/schema',
			'$id'                  => 'https://wcpos.com/schemas/receipt-data.schema.json',
			'x-schema-version'     => self::SCHEMA_VERSION,
			'title'                => 'ReceiptData',
			'type'                 => 'object',
			'additionalProperties' => true,
			'required'             => self::REQUIRED_KEYS,
			'properties'           => array(),
		);

		foreach ( self::REQUIRED_KEYS as $key ) {
			$schema['properties'][ $key ] = self::get_default_section_schema( $key );
		}

		foreach ( self::get_field_tree() as $path => $section ) {
			self::merge_field_tree_section_schema( $schema, $path, $section );
		}

		unset( $schema['properties']['presentation_hints']['properties'] );

		return $schema;
	}

	/**
	 * Get a default schema for a top-level receipt section.
	 *
	 * @param string $key Top-level receipt data key.
	 *
	 * @return array<string, mixed>
	 */
	private static function get_default_section_schema( string $key ): array {
		if ( 'has_tax_summary' === $key ) {
			return array(
				'type'        => 'boolean',
				'description' => 'Whether tax_summary contains at least one row.',
			);
		}

		if ( \in_array( $key, array( 'lines', 'fees', 'shipping', 'discounts', 'tax_summary', 'payments', 'refunds' ), true ) ) {
			return array(
				'type'                 => 'array',
				'items'                => array(
					'type'                 => 'object',
					'additionalProperties' => true,
					'properties'           => array(),
				),
				'additionalProperties' => true,
			);
		}

		return array(
			'type'                 => 'object',
			'additionalProperties' => true,
			'properties'           => array(),
		);
	}

	/**
	 * Merge a template editor field-tree section into the JSON Schema.
	 *
	 * @param array<string, mixed> $schema  Full schema, passed by reference.
	 * @param string               $path    Dot path for the field-tree section.
	 * @param array<string, mixed> $section Field-tree section metadata.
	 *
	 * @return void
	 */
	private static function merge_field_tree_section_schema( array &$schema, string $path, array $section ): void {
		$segments = explode( '.', $path );
		$top_key  = array_shift( $segments );

		if ( ! \is_string( $top_key ) || '' === $top_key ) {
			return;
		}

		if ( ! isset( $schema['properties'][ $top_key ] ) ) {
			$schema['properties'][ $top_key ] = self::get_default_section_schema( $top_key );
		}

		$target                    =& $schema['properties'][ $top_key ];
		$target_is_collection_item = false;

		if ( 'array' === ( $target['type'] ?? null ) ) {
			$target                    =& $target['items'];
			$target_is_collection_item = true;
		}

		foreach ( $segments as $segment ) {
			if ( ! isset( $target['properties'][ $segment ] ) ) {
				$target['properties'][ $segment ] = array(
					'type'                 => 'object',
					'additionalProperties' => true,
					'properties'           => array(),
				);
			}
			$target =& $target['properties'][ $segment ];
		}

		$target['description'] = isset( $section['label'] ) ? (string) $section['label'] : $path;

		if ( isset( $section['type'] ) && empty( $section['fields'] ) && empty( $segments ) ) {
			$target = self::field_metadata_to_json_schema( $section );
			return;
		}

		if ( ! empty( $section['is_array'] ) && ! $target_is_collection_item ) {
			$target['type']  = 'array';
			$target['items'] = $target['items'] ?? array(
				'type'                 => 'object',
				'additionalProperties' => true,
				'properties'           => array(),
			);

			// Strip object-only keywords that may have been seeded by the
			// segment-walk above; they are invalid on an array schema.
			unset( $target['additionalProperties'], $target['properties'] );
		} else {
			$target['type']                 = 'object';
			$target['additionalProperties'] = true;
			$target['properties']           = $target['properties'] ?? array();
		}

		$field_target =& $target;
		if ( 'array' === ( $target['type'] ?? null ) ) {
			$field_target =& $target['items'];
		}

		foreach ( $section['fields'] ?? array() as $field_name => $field ) {
			$field_target['properties'][ $field_name ] = self::field_metadata_to_json_schema( $field );
		}
	}

	/**
	 * Convert one field-tree field to a JSON Schema property.
	 *
	 * @param array<string,mixed> $field Field metadata.
	 *
	 * @return array<string,mixed>
	 */
	private static function field_metadata_to_json_schema( array $field ): array {
		$type        = isset( $field['type'] ) ? (string) $field['type'] : 'string';
		$schema_type = self::field_type_to_json_type( $type );

		// Honor a nullable flag from the field-tree metadata: producers may
		// legitimately emit null for a field whose JSON Schema type would
		// otherwise reject it (e.g. refunds[].refunded_by_id when no user).
		if ( ! empty( $field['nullable'] ) ) {
			if ( \is_array( $schema_type ) ) {
				if ( ! \in_array( 'null', $schema_type, true ) ) {
					$schema_type[] = 'null';
				}
			} else {
				$schema_type = array( $schema_type, 'null' );
			}
		}

		$schema = array(
			'type'        => $schema_type,
			'description' => isset( $field['label'] ) ? (string) $field['label'] : '',
		);

		if ( \in_array( $type, array( 'string[]', 'array' ), true ) ) {
			$schema['items'] = array( 'type' => 'string[]' === $type ? 'string' : array( 'string', 'number', 'boolean', 'object', 'array', 'null' ) );
		}

		if ( ! empty( $field['is_array'] ) && ! empty( $field['fields'] ) ) {
			$schema['type']  = 'array';
			$schema['items'] = array(
				'type'                 => 'object',
				'additionalProperties' => true,
				'properties'           => array(),
			);

			foreach ( $field['fields'] as $child_name => $child_field ) {
				$schema['items']['properties'][ $child_name ] = self::field_metadata_to_json_schema( $child_field );
			}
		}

		return $schema;
	}

	/**
	 * Map template field-tree scalar types to JSON Schema types.
	 *
	 * @param string $type Field-tree type.
	 *
	 * @return string|array<int,string>
	 */
	private static function field_type_to_json_type( string $type ) {
		switch ( $type ) {
			case 'number':
				return 'number';
			case 'boolean':
				return 'boolean';
			case 'money':
				return array( 'number', 'string' );
			case 'object':
				return 'object';
			case 'array':
			case 'string[]':
				return 'array';
			case 'string':
			default:
				return 'string';
		}
	}

	/**
	 * Get mock receipt data for template preview.
	 *
	 * Returns a representative receipt payload with realistic values
	 * for use in the template editor preview and tests.
	 *
	 * @return array Mock receipt data.
	 */
	public static function get_mock_receipt_data(): array {
		$created   = Receipt_Date_Formatter::from_timestamp( strtotime( '2024-01-15 10:30:00 UTC' ) );
		$paid      = Receipt_Date_Formatter::from_timestamp( strtotime( '2024-01-15 10:35:00 UTC' ) );
		$completed = Receipt_Date_Formatter::from_timestamp( strtotime( '2024-01-15 10:42:00 UTC' ) );
		$printed   = Receipt_Date_Formatter::from_timestamp( strtotime( '2024-01-15 10:45:00 UTC' ) );

		return array(
			'has_tax_summary' => true,
			'order'   => array(
				'id'            => 1001,
				'number'        => '1001',
				'currency'      => 'USD',
				'customer_note' => '',
				'wc_status'     => 'completed',
				'status_label'  => 'Completed',
				'created_via'   => 'woocommerce-pos',
				'created'       => $created,
				'paid'          => $paid,
				'completed'     => $completed,
				'printed'       => $printed,
				'needs_payment' => false,
				'payment_url'   => '',
			),
			'store'   => array(
				'id'                      => 1,
				'name'                    => 'My Store',
				'address'                 => array(
					'address_1' => '123 Main St',
					'address_2' => '',
					'city'      => 'Anytown',
					'state'     => 'CA',
					'postcode'  => '90210',
					'country'   => 'US',
				),
				'address_lines'           => array( '123 Main St', 'Anytown, CA 90210' ),
				'tax_ids'                 => array(
					array(
						'type'    => 'us_ein',
						'value'   => '12-3456789',
						'country' => 'US',
						'label'   => 'EIN',
					),
				),
				'phone'                   => '+1 (555) 123-4567',
				'email'                   => 'hello@mystore.com',
				'logo'                    => 'https://example.com/logo.png',
				'opening_hours'           => "Mon\u{2013}Fri 9:00 AM \u{2013} 5:00 PM\nSat 10:00 AM \u{2013} 4:00 PM\nSun Closed",
				'opening_hours_vertical'  => "Mon 9:00 AM \u{2013} 5:00 PM\nTue 9:00 AM \u{2013} 5:00 PM\nWed 9:00 AM \u{2013} 5:00 PM\nThu 9:00 AM \u{2013} 5:00 PM\nFri 9:00 AM \u{2013} 5:00 PM\nSat 10:00 AM \u{2013} 4:00 PM\nSun Closed",
				'opening_hours_inline'    => "Mon\u{2013}Fri 9:00 AM \u{2013} 5:00 PM, Sat 10:00 AM \u{2013} 4:00 PM, Sun Closed",
				'opening_hours_notes'     => 'Closed on public holidays',
				'personal_notes'          => '',
				'policies_and_conditions' => '',
				'footer_imprint'          => '',
			),
			'cashier' => array(
				'id'   => 1,
				'name' => 'Admin',
			),
		);
	}
}

```
