'', 'locale' => '', 'timezone' => '', 'store_address' => '', 'store_address_2' => '', 'store_city' => '', 'store_postcode' => '', 'store_state' => '', 'store_country' => '', 'default_customer_address' => '', 'calc_taxes' => '', 'enable_coupons' => '', 'calc_discounts_sequentially' => '', 'currency' => '', 'currency_pos' => '', 'price_thousand_sep' => '', 'price_decimal_sep' => '', 'price_num_decimals' => '', 'prevent_overselling' => false, 'prices_include_tax' => '', 'tax_based_on' => '', 'tax_address' => array( 'country' => '', 'state' => '', 'postcode' => '', 'city' => '', ), 'shipping_tax_class' => '', 'tax_round_at_subtotal' => '', 'tax_display_shop' => '', 'tax_display_cart' => '', 'price_display_suffix' => '', 'tax_total_display' => '', 'default_customer' => 0, 'default_customer_is_cashier' => false, // The merchant's consent to anonymous usage data + error reports. The POS // client reads it from here so its own error reporting follows the same // switch as the plugin's analytics (POS > Settings > General). 'tracking_consent' => 'undecided', // Pro properties (with WooCommerce defaults in free version). 'url' => '', 'phone' => '', 'email' => '', 'opening_hours' => array(), 'opening_hours_notes' => '', 'personal_notes' => '', 'policies_and_conditions' => '', 'footer_imprint' => '', 'tax_ids' => array(), ); /** * Construct the default POS store. */ public function __construct() { parent::__construct(); $this->set_wordpress_settings(); $this->set_woocommerce_general_settings(); $this->set_woocommerce_tax_settings(); $this->set_woocommerce_pos_settings(); $this->set_pro_property_defaults(); } /** * Set WordPress settings. */ public function set_wordpress_settings() { $this->set_prop( 'locale', \get_locale() ); $this->set_prop( 'timezone', \wp_timezone_string() ); } /** * Set WooCommerce general settings. */ public function set_woocommerce_general_settings() { $default_country = \WC_Admin_Settings::get_option( 'woocommerce_default_country' ); $country_state_array = wc_format_country_state_string( $default_country ); $this->set_prop( 'store_address', \WC_Admin_Settings::get_option( 'woocommerce_store_address' ) ); $this->set_prop( 'store_address_2', \WC_Admin_Settings::get_option( 'woocommerce_store_address_2' ) ); $this->set_prop( 'store_city', \WC_Admin_Settings::get_option( 'woocommerce_store_city' ) ); $this->set_prop( 'store_state', $country_state_array['state'] ); $this->set_prop( 'store_country', $country_state_array['country'] ); // $this->set_prop( 'default_country', $default_country ); $this->set_prop( 'store_postcode', \WC_Admin_Settings::get_option( 'woocommerce_store_postcode' ) ); $this->set_prop( 'default_customer_address', \WC_Admin_Settings::get_option( 'woocommerce_default_customer_address' ) ); $this->set_prop( 'calc_taxes', \WC_Admin_Settings::get_option( 'woocommerce_calc_taxes' ) ); $this->set_prop( 'enable_coupons', \WC_Admin_Settings::get_option( 'woocommerce_enable_coupons' ) ); $this->set_prop( 'calc_discounts_sequentially', \WC_Admin_Settings::get_option( 'woocommerce_calc_discounts_sequentially' ) ); $this->set_prop( 'currency', \WC_Admin_Settings::get_option( 'woocommerce_currency' ) ); $this->set_prop( 'currency_pos', \WC_Admin_Settings::get_option( 'woocommerce_currency_pos' ) ); $this->set_prop( 'price_thousand_sep', \WC_Admin_Settings::get_option( 'woocommerce_price_thousand_sep' ) ); $this->set_prop( 'price_decimal_sep', \WC_Admin_Settings::get_option( 'woocommerce_price_decimal_sep' ) ); $this->set_prop( 'price_num_decimals', (int) \WC_Admin_Settings::get_option( 'woocommerce_price_num_decimals', 2 ) ); } /** * Set WooCommerce tax settings. */ public function set_woocommerce_tax_settings() { $this->set_prop( 'prices_include_tax', \WC_Admin_Settings::get_option( 'woocommerce_prices_include_tax' ) ); $this->set_prop( 'tax_based_on', 'base' ); // default should be base, perhaps have a setting for this? $this->set_prop( 'shipping_tax_class', \WC_Admin_Settings::get_option( 'woocommerce_shipping_tax_class' ) ); $this->set_prop( 'tax_round_at_subtotal', \WC_Admin_Settings::get_option( 'woocommerce_tax_round_at_subtotal' ) ); $this->set_prop( 'tax_display_shop', \WC_Admin_Settings::get_option( 'woocommerce_tax_display_shop' ) ); $this->set_prop( 'tax_display_cart', \WC_Admin_Settings::get_option( 'woocommerce_tax_display_cart' ) ); $this->set_prop( 'price_display_suffix', \WC_Admin_Settings::get_option( 'woocommerce_price_display_suffix' ) ); $this->set_prop( 'tax_total_display', \WC_Admin_Settings::get_option( 'woocommerce_tax_total_display' ) ); // tax address is same as WooCommerce address by default. $country_state_array = wc_format_country_state_string( \WC_Admin_Settings::get_option( 'woocommerce_default_country' ) ); $this->set_prop( 'tax_address', array( 'country' => $country_state_array['country'], 'state' => $country_state_array['state'], 'postcode' => \WC_Admin_Settings::get_option( 'woocommerce_store_postcode' ), 'city' => \WC_Admin_Settings::get_option( 'woocommerce_store_city' ), ) ); } /** * Set WooCommerce POS settings. */ public function set_woocommerce_pos_settings() { $this->set_prop( 'default_customer', Settings::instance()->default_customer_id() ); $this->set_prop( 'default_customer_is_cashier', Settings::instance()->default_customer_is_cashier() ); $this->set_prop( 'prevent_overselling', Settings::instance()->prevent_overselling_enabled() ); // The POS client gates its OWN error reporting on this value, so it is a // send gate one hop away: read the persisted answer, not the filtered view. $this->set_prop( 'tracking_consent', Settings::instance()->raw_tracking_consent() ); } /** * Get the store data as an array. * * Extends the raw prop data with `receipt_i18n`, the receipt label * dictionary resolved for this store's locale. The client persists it on * the store record so offline/fallback receipt renders use the same * translated labels as server-built receipt payloads (issue mono#1252). * Computed here (not stored as a prop) so Pro's per-outlet locale * override is applied before resolution. * * @return array */ public function get_data() { $data = parent::get_data(); $data['receipt_i18n'] = Receipt_I18n_Labels::get_labels( (string) $this->get_locale() ); return $data; } /** * Get Store name. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_name( $context = 'view' ) { return $this->get_prop( 'name', $context ); } /** * Get Store locale. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_locale( $context = 'view' ) { return $this->get_prop( 'locale', $context ); } /** * Get Store timezone. * * Empty string means inherit the WordPress site timezone. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_timezone( $context = 'view' ) { $value = $this->get_prop( 'timezone', $context ); return is_string( $value ) ? $value : ''; } /** * Get Store address. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_store_address( $context = 'view' ) { return $this->get_prop( 'store_address', $context ); } /** * Get Store address 2. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_store_address_2( $context = 'view' ) { return $this->get_prop( 'store_address_2', $context ); } /** * Get Store city. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_store_city( $context = 'view' ) { return $this->get_prop( 'store_city', $context ); } /** * Get Store postcode. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_store_postcode( $context = 'view' ) { return $this->get_prop( 'store_postcode', $context ); } /** * Get Store country, eg: US:AL. * This is of the form COUNTRYCODE:STATECODE to be consistent with the WooCommerce settings. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ // phpcs:disable Squiz.Commenting.InlineComment.InvalidEndChar -- Commented-out code. // public function get_default_country( $context = 'view' ) { // return $this->get_prop( 'default_country', $context ); // } // phpcs:enable Squiz.Commenting.InlineComment.InvalidEndChar /** * Get Store state code. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_store_state( $context = 'view' ) { return $this->get_prop( 'store_state', $context ); } /** * Get Store country code. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_store_country( $context = 'view' ) { return $this->get_prop( 'store_country', $context ); } /** * Get Store customer address. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_default_customer_address( $context = 'view' ) { return $this->get_prop( 'default_customer_address', $context ); } /** * Get Store calculate taxes. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_calc_taxes( $context = 'view' ) { return $this->get_prop( 'calc_taxes', $context ); } /** * Get Store enable coupons. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_enable_coupons( $context = 'view' ) { return $this->get_prop( 'enable_coupons', $context ); } /** * Get Store calculate discounts sequentially. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_calc_discounts_sequentially( $context = 'view' ) { return $this->get_prop( 'calc_discounts_sequentially', $context ); } /** * Get Store currency. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_currency( $context = 'view' ) { return $this->get_prop( 'currency', $context ); } /** * Get Store currency position. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_currency_position( $context = 'view' ) { return $this->get_prop( 'currency_pos', $context ); } /** * Get Store price thousand separator. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_price_thousand_separator( $context = 'view' ) { return $this->get_prop( 'price_thousand_sep', $context ); } /** * Get Store price decimal separator. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_price_decimal_separator( $context = 'view' ) { return $this->get_prop( 'price_decimal_sep', $context ); } /** * Get Store price number of decimals. * * @param string $context What the value is for. Valid values are view and edit. * @return int */ public function get_price_number_of_decimals( $context = 'view' ) { return $this->get_prop( 'price_num_decimals', $context ); } /** * Get Store prices include tax. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_prices_include_tax( $context = 'view' ) { return $this->get_prop( 'prices_include_tax', $context ); } /** * Get Store tax based on. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_tax_based_on( $context = 'view' ) { return $this->get_prop( 'tax_based_on', $context ); } /** * Get Store tax address. * * @param string $context What the value is for. Valid values are view and edit. * @return array */ public function get_tax_address( $context = 'view' ) { return $this->get_prop( 'tax_address', $context ); } /** * Get Store shipping tax class. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_shipping_tax_class( $context = 'view' ) { return $this->get_prop( 'shipping_tax_class', $context ); } /** * Get Store tax round at subtotal. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_tax_round_at_subtotal( $context = 'view' ) { return $this->get_prop( 'tax_round_at_subtotal', $context ); } /** * Get Store tax display shop. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_tax_display_shop( $context = 'view' ) { return $this->get_prop( 'tax_display_shop', $context ); } /** * Get Store tax display cart. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_tax_display_cart( $context = 'view' ) { return $this->get_prop( 'tax_display_cart', $context ); } /** * Get Store price display suffix. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_price_display_suffix( $context = 'view' ) { return $this->get_prop( 'price_display_suffix', $context ); } /** * Get Store tax total display. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_tax_total_display( $context = 'view' ) { return $this->get_prop( 'tax_total_display', $context ); } /** * Get Store default customer. * * @param string $context What the value is for. Valid values are view and edit. * @return int */ public function get_default_customer( $context = 'view' ) { return $this->get_prop( 'default_customer', $context ); } /** * Get Store default customer is cashier. * * @param string $context What the value is for. Valid values are view and edit. * @return bool */ public function get_default_customer_is_cashier( $context = 'view' ) { return $this->get_prop( 'default_customer_is_cashier', $context ); } /** * Get the merchant's tracking consent: 'undecided', 'allowed' or 'denied'. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_tracking_consent( $context = 'view' ) { return $this->get_prop( 'tracking_consent', $context ); } /** * Set Pro property defaults from WooCommerce settings. * * These properties are fully customizable in the Pro version, * but in the free version we derive sensible defaults via * Store_Defaults: WCPOS general settings → WC POS core options * → WordPress / WooCommerce fallbacks. */ protected function set_pro_property_defaults() { $this->set_prop( 'name', Store_Defaults::name() ); $this->set_prop( 'url', \home_url() ); $this->set_prop( 'phone', Store_Defaults::phone() ); $this->set_prop( 'email', Store_Defaults::email() ); $this->set_prop( 'opening_hours', array() ); $this->set_prop( 'opening_hours_notes', '' ); $this->set_prop( 'personal_notes', '' ); $this->set_prop( 'policies_and_conditions', Store_Defaults::policies_and_conditions() ); $this->set_prop( 'footer_imprint', '' ); $this->set_prop( 'tax_ids', Store_Defaults::tax_ids() ); } /** * Get Store URL. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_url( $context = 'view' ) { return $this->get_prop( 'url', $context ); } /** * Get Store phone number. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_phone( $context = 'view' ) { return $this->get_prop( 'phone', $context ); } /** * Get Store email address. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_email( $context = 'view' ) { return $this->get_prop( 'email', $context ); } /** * Get Store opening hours. * * @param string $context What the value is for. Valid values are view and edit. * @return array|string */ public function get_opening_hours( $context = 'view' ) { return $this->get_prop( 'opening_hours', $context ); } /** * Get Store opening hours notes. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_opening_hours_notes( $context = 'view' ) { return $this->get_prop( 'opening_hours_notes', $context ); } /** * Get Store personal notes. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_personal_notes( $context = 'view' ) { return $this->get_prop( 'personal_notes', $context ); } /** * Get Store policies and conditions. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_policies_and_conditions( $context = 'view' ) { return $this->get_prop( 'policies_and_conditions', $context ); } /** * Get Store footer imprint. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_footer_imprint( $context = 'view' ) { return $this->get_prop( 'footer_imprint', $context ); } /** * Get Store formatted address. * * @return string */ public function get_formatted_address() { $countries = new WC_Countries(); return $countries->get_formatted_address( array( 'address_1' => $this->get_store_address(), 'address_2' => $this->get_store_address_2(), 'city' => $this->get_store_city(), 'state' => $this->get_store_state(), 'postcode' => $this->get_store_postcode(), 'country' => $this->get_store_country(), ) ); } /** * Get Store tax IDs as a structured array. * * @param string $context What the value is for. Valid values are view and edit. * @return array> */ public function get_tax_ids( $context = 'view' ) { $value = $this->get_prop( 'tax_ids', $context ); return is_array( $value ) ? $value : array(); } /** * Get the primary tax ID as a formatted scalar. * * Back-compat helper for templates using {{store.tax_id}}. * Returns the first entry's value (verbatim — country prefix is preserved * exactly as stored), or empty string when no entries exist. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_tax_id( $context = 'view' ) { $tax_ids = $this->get_tax_ids( $context ); if ( empty( $tax_ids ) ) { return ''; } $primary = reset( $tax_ids ); return isset( $primary['value'] ) ? (string) $primary['value'] : ''; } /** * Get Store logo image source. * * In the free version, this returns the site's custom logo if set. * * @param string $size Image size. Default 'full'. * @return array|false Array of image data, or false if no image. */ public function get_logo_image_src( $size = 'full' ) { $custom_logo_id = \get_theme_mod( 'custom_logo' ); if ( $custom_logo_id ) { return \wp_get_attachment_image_src( $custom_logo_id, $size ); } return false; } }