PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / trunk
WCPOS – Point of Sale (POS) plugin for WooCommerce vtrunk
1.10.13 1.10.14 1.10.12 1.10.11 1.10.10 1.10.9 1.10.8 untagged-3d9b7ccddc54df87c672 1.10.7 1.10.6 1.10.5 1.10.3 1.10.4 1.10.2 1.10.1 1.10.0 1.9.17 1.9.15 1.9.16 1.9.14 1.9.13 1.9.12 1.9.11 1.9.10 1.9.9 All 158 releases
woocommerce-pos / includes / Abstracts / Store.php

Store.php in WCPOS – Point of Sale (POS) plugin for WooCommerce trunk, at includes/Abstracts/Store.php

682 lines 21.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Abstract Store class.
4 *
5 * @package WooCommerce\POS\Abstracts
6 */
7
8 namespace WCPOS\WooCommercePOS\Abstracts;
9
10 use WCPOS\WooCommercePOS\Interfaces\StoreInterface;
11 use WCPOS\WooCommercePOS\Services\Receipt_I18n_Labels;
12 use WCPOS\WooCommercePOS\Services\Settings;
13 use WCPOS\WooCommercePOS\Services\Store_Defaults;
14 use WC_Countries;
15 use function wc_format_country_state_string;
16
17 if ( ! defined( 'ABSPATH' ) ) {
18 exit;
19 }
20
21 /**
22 * Abstract Store class.
23 *
24 * Handles the store data, and provides CRUD methods.
25 * Implements StoreInterface to ensure API consistency with Pro version.
26 */
27 class Store extends \WC_Data implements StoreInterface {
28 /**
29 * This is the name of this object type.
30 *
31 * @var string
32 */
33 protected $object_type = 'store';
34
35 /**
36 * Stores product data.
37 *
38 * @var array
39 */
40 protected $data = array(
41 'name' => '',
42 'locale' => '',
43 'timezone' => '',
44 'store_address' => '',
45 'store_address_2' => '',
46 'store_city' => '',
47 'store_postcode' => '',
48 'store_state' => '',
49 'store_country' => '',
50 'default_customer_address' => '',
51 'calc_taxes' => '',
52 'enable_coupons' => '',
53 'calc_discounts_sequentially' => '',
54 'currency' => '',
55 'currency_pos' => '',
56 'price_thousand_sep' => '',
57 'price_decimal_sep' => '',
58 'price_num_decimals' => '',
59 'prevent_overselling' => false,
60 'prices_include_tax' => '',
61 'tax_based_on' => '',
62 'tax_address' => array(
63 'country' => '',
64 'state' => '',
65 'postcode' => '',
66 'city' => '',
67 ),
68 'shipping_tax_class' => '',
69 'tax_round_at_subtotal' => '',
70 'tax_display_shop' => '',
71 'tax_display_cart' => '',
72 'price_display_suffix' => '',
73 'tax_total_display' => '',
74 'default_customer' => 0,
75 'default_customer_is_cashier' => false,
76 // The merchant's consent to anonymous usage data + error reports. The POS
77 // client reads it from here so its own error reporting follows the same
78 // switch as the plugin's analytics (POS > Settings > General).
79 'tracking_consent' => 'undecided',
80 // Pro properties (with WooCommerce defaults in free version).
81 'url' => '',
82 'phone' => '',
83 'email' => '',
84 'opening_hours' => array(),
85 'opening_hours_notes' => '',
86 'personal_notes' => '',
87 'policies_and_conditions' => '',
88 'footer_imprint' => '',
89 'tax_ids' => array(),
90 );
91
92 /**
93 * Construct the default POS store.
94 */
95 public function __construct() {
96 parent::__construct();
97 $this->set_wordpress_settings();
98 $this->set_woocommerce_general_settings();
99 $this->set_woocommerce_tax_settings();
100 $this->set_woocommerce_pos_settings();
101 $this->set_pro_property_defaults();
102 }
103
104 /**
105 * Set WordPress settings.
106 */
107 public function set_wordpress_settings() {
108 $this->set_prop( 'locale', \get_locale() );
109 $this->set_prop( 'timezone', \wp_timezone_string() );
110 }
111
112 /**
113 * Set WooCommerce general settings.
114 */
115 public function set_woocommerce_general_settings() {
116 $default_country = \WC_Admin_Settings::get_option( 'woocommerce_default_country' );
117 $country_state_array = wc_format_country_state_string( $default_country );
118
119 $this->set_prop( 'store_address', \WC_Admin_Settings::get_option( 'woocommerce_store_address' ) );
120 $this->set_prop( 'store_address_2', \WC_Admin_Settings::get_option( 'woocommerce_store_address_2' ) );
121 $this->set_prop( 'store_city', \WC_Admin_Settings::get_option( 'woocommerce_store_city' ) );
122 $this->set_prop( 'store_state', $country_state_array['state'] );
123 $this->set_prop( 'store_country', $country_state_array['country'] );
124 // $this->set_prop( 'default_country', $default_country );
125 $this->set_prop( 'store_postcode', \WC_Admin_Settings::get_option( 'woocommerce_store_postcode' ) );
126 $this->set_prop( 'default_customer_address', \WC_Admin_Settings::get_option( 'woocommerce_default_customer_address' ) );
127 $this->set_prop( 'calc_taxes', \WC_Admin_Settings::get_option( 'woocommerce_calc_taxes' ) );
128 $this->set_prop( 'enable_coupons', \WC_Admin_Settings::get_option( 'woocommerce_enable_coupons' ) );
129 $this->set_prop( 'calc_discounts_sequentially', \WC_Admin_Settings::get_option( 'woocommerce_calc_discounts_sequentially' ) );
130 $this->set_prop( 'currency', \WC_Admin_Settings::get_option( 'woocommerce_currency' ) );
131 $this->set_prop( 'currency_pos', \WC_Admin_Settings::get_option( 'woocommerce_currency_pos' ) );
132 $this->set_prop( 'price_thousand_sep', \WC_Admin_Settings::get_option( 'woocommerce_price_thousand_sep' ) );
133 $this->set_prop( 'price_decimal_sep', \WC_Admin_Settings::get_option( 'woocommerce_price_decimal_sep' ) );
134 $this->set_prop( 'price_num_decimals', (int) \WC_Admin_Settings::get_option( 'woocommerce_price_num_decimals', 2 ) );
135 }
136
137 /**
138 * Set WooCommerce tax settings.
139 */
140 public function set_woocommerce_tax_settings() {
141 $this->set_prop( 'prices_include_tax', \WC_Admin_Settings::get_option( 'woocommerce_prices_include_tax' ) );
142 $this->set_prop( 'tax_based_on', 'base' ); // default should be base, perhaps have a setting for this?
143 $this->set_prop( 'shipping_tax_class', \WC_Admin_Settings::get_option( 'woocommerce_shipping_tax_class' ) );
144 $this->set_prop( 'tax_round_at_subtotal', \WC_Admin_Settings::get_option( 'woocommerce_tax_round_at_subtotal' ) );
145 $this->set_prop( 'tax_display_shop', \WC_Admin_Settings::get_option( 'woocommerce_tax_display_shop' ) );
146 $this->set_prop( 'tax_display_cart', \WC_Admin_Settings::get_option( 'woocommerce_tax_display_cart' ) );
147 $this->set_prop( 'price_display_suffix', \WC_Admin_Settings::get_option( 'woocommerce_price_display_suffix' ) );
148 $this->set_prop( 'tax_total_display', \WC_Admin_Settings::get_option( 'woocommerce_tax_total_display' ) );
149
150 // tax address is same as WooCommerce address by default.
151 $country_state_array = wc_format_country_state_string( \WC_Admin_Settings::get_option( 'woocommerce_default_country' ) );
152
153 $this->set_prop(
154 'tax_address',
155 array(
156 'country' => $country_state_array['country'],
157 'state' => $country_state_array['state'],
158 'postcode' => \WC_Admin_Settings::get_option( 'woocommerce_store_postcode' ),
159 'city' => \WC_Admin_Settings::get_option( 'woocommerce_store_city' ),
160 )
161 );
162 }
163
164 /**
165 * Set WooCommerce POS settings.
166 */
167 public function set_woocommerce_pos_settings() {
168 $this->set_prop( 'default_customer', Settings::instance()->default_customer_id() );
169 $this->set_prop( 'default_customer_is_cashier', Settings::instance()->default_customer_is_cashier() );
170 $this->set_prop( 'prevent_overselling', Settings::instance()->prevent_overselling_enabled() );
171 // The POS client gates its OWN error reporting on this value, so it is a
172 // send gate one hop away: read the persisted answer, not the filtered view.
173 $this->set_prop( 'tracking_consent', Settings::instance()->raw_tracking_consent() );
174 }
175
176 /**
177 * Get the store data as an array.
178 *
179 * Extends the raw prop data with `receipt_i18n`, the receipt label
180 * dictionary resolved for this store's locale. The client persists it on
181 * the store record so offline/fallback receipt renders use the same
182 * translated labels as server-built receipt payloads (issue mono#1252).
183 * Computed here (not stored as a prop) so Pro's per-outlet locale
184 * override is applied before resolution.
185 *
186 * @return array
187 */
188 public function get_data() {
189 $data = parent::get_data();
190 $data['receipt_i18n'] = Receipt_I18n_Labels::get_labels( (string) $this->get_locale() );
191
192 return $data;
193 }
194
195 /**
196 * Get Store name.
197 *
198 * @param string $context What the value is for. Valid values are view and edit.
199 * @return string
200 */
201 public function get_name( $context = 'view' ) {
202 return $this->get_prop( 'name', $context );
203 }
204
205 /**
206 * Get Store locale.
207 *
208 * @param string $context What the value is for. Valid values are view and edit.
209 * @return string
210 */
211 public function get_locale( $context = 'view' ) {
212 return $this->get_prop( 'locale', $context );
213 }
214
215
216 /**
217 * Get Store timezone.
218 *
219 * Empty string means inherit the WordPress site timezone.
220 *
221 * @param string $context What the value is for. Valid values are view and edit.
222 * @return string
223 */
224 public function get_timezone( $context = 'view' ) {
225 $value = $this->get_prop( 'timezone', $context );
226 return is_string( $value ) ? $value : '';
227 }
228
229 /**
230 * Get Store address.
231 *
232 * @param string $context What the value is for. Valid values are view and edit.
233 * @return string
234 */
235 public function get_store_address( $context = 'view' ) {
236 return $this->get_prop( 'store_address', $context );
237 }
238
239 /**
240 * Get Store address 2.
241 *
242 * @param string $context What the value is for. Valid values are view and edit.
243 * @return string
244 */
245 public function get_store_address_2( $context = 'view' ) {
246 return $this->get_prop( 'store_address_2', $context );
247 }
248
249 /**
250 * Get Store city.
251 *
252 * @param string $context What the value is for. Valid values are view and edit.
253 * @return string
254 */
255 public function get_store_city( $context = 'view' ) {
256 return $this->get_prop( 'store_city', $context );
257 }
258
259 /**
260 * Get Store postcode.
261 *
262 * @param string $context What the value is for. Valid values are view and edit.
263 * @return string
264 */
265 public function get_store_postcode( $context = 'view' ) {
266 return $this->get_prop( 'store_postcode', $context );
267 }
268
269 /**
270 * Get Store country, eg: US:AL.
271 * This is of the form COUNTRYCODE:STATECODE to be consistent with the WooCommerce settings.
272 *
273 * @param string $context What the value is for. Valid values are view and edit.
274 * @return string
275 */
276 // phpcs:disable Squiz.Commenting.InlineComment.InvalidEndChar -- Commented-out code.
277 // public function get_default_country( $context = 'view' ) {
278 // return $this->get_prop( 'default_country', $context );
279 // }
280 // phpcs:enable Squiz.Commenting.InlineComment.InvalidEndChar
281
282 /**
283 * Get Store state code.
284 *
285 * @param string $context What the value is for. Valid values are view and edit.
286 * @return string
287 */
288 public function get_store_state( $context = 'view' ) {
289 return $this->get_prop( 'store_state', $context );
290 }
291
292 /**
293 * Get Store country code.
294 *
295 * @param string $context What the value is for. Valid values are view and edit.
296 * @return string
297 */
298 public function get_store_country( $context = 'view' ) {
299 return $this->get_prop( 'store_country', $context );
300 }
301
302 /**
303 * Get Store customer address.
304 *
305 * @param string $context What the value is for. Valid values are view and edit.
306 * @return string
307 */
308 public function get_default_customer_address( $context = 'view' ) {
309 return $this->get_prop( 'default_customer_address', $context );
310 }
311
312 /**
313 * Get Store calculate taxes.
314 *
315 * @param string $context What the value is for. Valid values are view and edit.
316 * @return string
317 */
318 public function get_calc_taxes( $context = 'view' ) {
319 return $this->get_prop( 'calc_taxes', $context );
320 }
321
322 /**
323 * Get Store enable coupons.
324 *
325 * @param string $context What the value is for. Valid values are view and edit.
326 * @return string
327 */
328 public function get_enable_coupons( $context = 'view' ) {
329 return $this->get_prop( 'enable_coupons', $context );
330 }
331
332 /**
333 * Get Store calculate discounts sequentially.
334 *
335 * @param string $context What the value is for. Valid values are view and edit.
336 * @return string
337 */
338 public function get_calc_discounts_sequentially( $context = 'view' ) {
339 return $this->get_prop( 'calc_discounts_sequentially', $context );
340 }
341
342 /**
343 * Get Store currency.
344 *
345 * @param string $context What the value is for. Valid values are view and edit.
346 * @return string
347 */
348 public function get_currency( $context = 'view' ) {
349 return $this->get_prop( 'currency', $context );
350 }
351
352 /**
353 * Get Store currency position.
354 *
355 * @param string $context What the value is for. Valid values are view and edit.
356 * @return string
357 */
358 public function get_currency_position( $context = 'view' ) {
359 return $this->get_prop( 'currency_pos', $context );
360 }
361
362 /**
363 * Get Store price thousand separator.
364 *
365 * @param string $context What the value is for. Valid values are view and edit.
366 * @return string
367 */
368 public function get_price_thousand_separator( $context = 'view' ) {
369 return $this->get_prop( 'price_thousand_sep', $context );
370 }
371
372 /**
373 * Get Store price decimal separator.
374 *
375 * @param string $context What the value is for. Valid values are view and edit.
376 * @return string
377 */
378 public function get_price_decimal_separator( $context = 'view' ) {
379 return $this->get_prop( 'price_decimal_sep', $context );
380 }
381
382 /**
383 * Get Store price number of decimals.
384 *
385 * @param string $context What the value is for. Valid values are view and edit.
386 * @return int
387 */
388 public function get_price_number_of_decimals( $context = 'view' ) {
389 return $this->get_prop( 'price_num_decimals', $context );
390 }
391
392 /**
393 * Get Store prices include tax.
394 *
395 * @param string $context What the value is for. Valid values are view and edit.
396 * @return string
397 */
398 public function get_prices_include_tax( $context = 'view' ) {
399 return $this->get_prop( 'prices_include_tax', $context );
400 }
401
402 /**
403 * Get Store tax based on.
404 *
405 * @param string $context What the value is for. Valid values are view and edit.
406 * @return string
407 */
408 public function get_tax_based_on( $context = 'view' ) {
409 return $this->get_prop( 'tax_based_on', $context );
410 }
411
412 /**
413 * Get Store tax address.
414 *
415 * @param string $context What the value is for. Valid values are view and edit.
416 * @return array
417 */
418 public function get_tax_address( $context = 'view' ) {
419 return $this->get_prop( 'tax_address', $context );
420 }
421
422 /**
423 * Get Store shipping tax class.
424 *
425 * @param string $context What the value is for. Valid values are view and edit.
426 * @return string
427 */
428 public function get_shipping_tax_class( $context = 'view' ) {
429 return $this->get_prop( 'shipping_tax_class', $context );
430 }
431
432 /**
433 * Get Store tax round at subtotal.
434 *
435 * @param string $context What the value is for. Valid values are view and edit.
436 * @return string
437 */
438 public function get_tax_round_at_subtotal( $context = 'view' ) {
439 return $this->get_prop( 'tax_round_at_subtotal', $context );
440 }
441
442 /**
443 * Get Store tax display shop.
444 *
445 * @param string $context What the value is for. Valid values are view and edit.
446 * @return string
447 */
448 public function get_tax_display_shop( $context = 'view' ) {
449 return $this->get_prop( 'tax_display_shop', $context );
450 }
451
452 /**
453 * Get Store tax display cart.
454 *
455 * @param string $context What the value is for. Valid values are view and edit.
456 * @return string
457 */
458 public function get_tax_display_cart( $context = 'view' ) {
459 return $this->get_prop( 'tax_display_cart', $context );
460 }
461
462 /**
463 * Get Store price display suffix.
464 *
465 * @param string $context What the value is for. Valid values are view and edit.
466 * @return string
467 */
468 public function get_price_display_suffix( $context = 'view' ) {
469 return $this->get_prop( 'price_display_suffix', $context );
470 }
471
472 /**
473 * Get Store tax total display.
474 *
475 * @param string $context What the value is for. Valid values are view and edit.
476 * @return string
477 */
478 public function get_tax_total_display( $context = 'view' ) {
479 return $this->get_prop( 'tax_total_display', $context );
480 }
481
482
483 /**
484 * Get Store default customer.
485 *
486 * @param string $context What the value is for. Valid values are view and edit.
487 * @return int
488 */
489 public function get_default_customer( $context = 'view' ) {
490 return $this->get_prop( 'default_customer', $context );
491 }
492
493 /**
494 * Get Store default customer is cashier.
495 *
496 * @param string $context What the value is for. Valid values are view and edit.
497 * @return bool
498 */
499 public function get_default_customer_is_cashier( $context = 'view' ) {
500 return $this->get_prop( 'default_customer_is_cashier', $context );
501 }
502
503 /**
504 * Get the merchant's tracking consent: 'undecided', 'allowed' or 'denied'.
505 *
506 * @param string $context What the value is for. Valid values are view and edit.
507 * @return string
508 */
509 public function get_tracking_consent( $context = 'view' ) {
510 return $this->get_prop( 'tracking_consent', $context );
511 }
512
513 /**
514 * Set Pro property defaults from WooCommerce settings.
515 *
516 * These properties are fully customizable in the Pro version,
517 * but in the free version we derive sensible defaults via
518 * Store_Defaults: WCPOS general settings → WC POS core options
519 * → WordPress / WooCommerce fallbacks.
520 */
521 protected function set_pro_property_defaults() {
522 $this->set_prop( 'name', Store_Defaults::name() );
523 $this->set_prop( 'url', \home_url() );
524 $this->set_prop( 'phone', Store_Defaults::phone() );
525 $this->set_prop( 'email', Store_Defaults::email() );
526 $this->set_prop( 'opening_hours', array() );
527 $this->set_prop( 'opening_hours_notes', '' );
528 $this->set_prop( 'personal_notes', '' );
529 $this->set_prop( 'policies_and_conditions', Store_Defaults::policies_and_conditions() );
530 $this->set_prop( 'footer_imprint', '' );
531 $this->set_prop( 'tax_ids', Store_Defaults::tax_ids() );
532 }
533
534 /**
535 * Get Store URL.
536 *
537 * @param string $context What the value is for. Valid values are view and edit.
538 * @return string
539 */
540 public function get_url( $context = 'view' ) {
541 return $this->get_prop( 'url', $context );
542 }
543
544 /**
545 * Get Store phone number.
546 *
547 * @param string $context What the value is for. Valid values are view and edit.
548 * @return string
549 */
550 public function get_phone( $context = 'view' ) {
551 return $this->get_prop( 'phone', $context );
552 }
553
554 /**
555 * Get Store email address.
556 *
557 * @param string $context What the value is for. Valid values are view and edit.
558 * @return string
559 */
560 public function get_email( $context = 'view' ) {
561 return $this->get_prop( 'email', $context );
562 }
563
564 /**
565 * Get Store opening hours.
566 *
567 * @param string $context What the value is for. Valid values are view and edit.
568 * @return array|string
569 */
570 public function get_opening_hours( $context = 'view' ) {
571 return $this->get_prop( 'opening_hours', $context );
572 }
573
574 /**
575 * Get Store opening hours notes.
576 *
577 * @param string $context What the value is for. Valid values are view and edit.
578 * @return string
579 */
580 public function get_opening_hours_notes( $context = 'view' ) {
581 return $this->get_prop( 'opening_hours_notes', $context );
582 }
583
584 /**
585 * Get Store personal notes.
586 *
587 * @param string $context What the value is for. Valid values are view and edit.
588 * @return string
589 */
590 public function get_personal_notes( $context = 'view' ) {
591 return $this->get_prop( 'personal_notes', $context );
592 }
593
594 /**
595 * Get Store policies and conditions.
596 *
597 * @param string $context What the value is for. Valid values are view and edit.
598 * @return string
599 */
600 public function get_policies_and_conditions( $context = 'view' ) {
601 return $this->get_prop( 'policies_and_conditions', $context );
602 }
603
604 /**
605 * Get Store footer imprint.
606 *
607 * @param string $context What the value is for. Valid values are view and edit.
608 * @return string
609 */
610 public function get_footer_imprint( $context = 'view' ) {
611 return $this->get_prop( 'footer_imprint', $context );
612 }
613
614 /**
615 * Get Store formatted address.
616 *
617 * @return string
618 */
619 public function get_formatted_address() {
620 $countries = new WC_Countries();
621
622 return $countries->get_formatted_address(
623 array(
624 'address_1' => $this->get_store_address(),
625 'address_2' => $this->get_store_address_2(),
626 'city' => $this->get_store_city(),
627 'state' => $this->get_store_state(),
628 'postcode' => $this->get_store_postcode(),
629 'country' => $this->get_store_country(),
630 )
631 );
632 }
633
634 /**
635 * Get Store tax IDs as a structured array.
636 *
637 * @param string $context What the value is for. Valid values are view and edit.
638 * @return array<int,array<string,string>>
639 */
640 public function get_tax_ids( $context = 'view' ) {
641 $value = $this->get_prop( 'tax_ids', $context );
642 return is_array( $value ) ? $value : array();
643 }
644
645 /**
646 * Get the primary tax ID as a formatted scalar.
647 *
648 * Back-compat helper for templates using {{store.tax_id}}.
649 * Returns the first entry's value (verbatim — country prefix is preserved
650 * exactly as stored), or empty string when no entries exist.
651 *
652 * @param string $context What the value is for. Valid values are view and edit.
653 * @return string
654 */
655 public function get_tax_id( $context = 'view' ) {
656 $tax_ids = $this->get_tax_ids( $context );
657 if ( empty( $tax_ids ) ) {
658 return '';
659 }
660 $primary = reset( $tax_ids );
661 return isset( $primary['value'] ) ? (string) $primary['value'] : '';
662 }
663
664 /**
665 * Get Store logo image source.
666 *
667 * In the free version, this returns the site's custom logo if set.
668 *
669 * @param string $size Image size. Default 'full'.
670 * @return array|false Array of image data, or false if no image.
671 */
672 public function get_logo_image_src( $size = 'full' ) {
673 $custom_logo_id = \get_theme_mod( 'custom_logo' );
674
675 if ( $custom_logo_id ) {
676 return \wp_get_attachment_image_src( $custom_logo_id, $size );
677 }
678
679 return false;
680 }
681 }
682