PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.20
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.20
1.10.20 1.10.19 1.10.18 1.10.17 1.10.16 1.10.15 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 All 164 releases
← All changes | includes/Services/Preview_Receipt_Builder.php +216 -299 1.9.15 → 1.10.20 View file →
@@ -21,15 +21,8 @@
21 21 */
22 22 class Preview_Receipt_Builder {
23 23
24 24 /**
25 - * POS store object used to populate store fields.
26 - *
27 - * @var object
28 - */
29 - private $pos_store;
30 -
31 - /**
32 25 * Shared store resolver.
33 26 *
34 27 * @var Receipt_Store_Resolver
35 28 */
@@ -505,24 +498,53 @@
505 498 ),
506 499 );
507 500
508 501 /**
509 - * Build a preview receipt payload.
502 + * Build a preview receipt payload, filtered like a live receipt.
510 503 *
504 + * @param object|null $pos_store POS store object. Falls back to default store.
505 + *
506 + * @return array Complete receipt data array.
507 + */
508 + public function build( $pos_store = null ): array {
509 + return self::apply_receipt_data_filter( $this->sample( $pos_store ) );
510 + }
511 +
512 + /**
513 + * Run a sample payload through the receipt data filter.
514 + *
515 + * Same extension point as live receipts, so plugin-added keys show in the
516 + * editor and gallery. The unsaved order (id 0) keeps plugins written against
517 + * WC_Order from fataling and lets them tell a sample apart. Each sample path
518 + * calls this exactly once, after every override has been applied: the gallery
519 + * fixture loader replaces whole row lists, so filtering before it would drop
520 + * keys a plugin put on a row.
521 + *
522 + * @param array $data Assembled sample payload.
523 + *
524 + * @return array Filtered payload.
525 + */
526 + public static function apply_receipt_data_filter( array $data ): array {
527 + return (array) apply_filters( 'woocommerce_pos_receipt_data', $data, new \WC_Order(), 'preview' );
528 + }
529 +
530 + /**
531 + * Assemble the unfiltered sample payload.
532 + *
511 533 * Returns an array matching the receipt data schema with all sections
512 - * populated using the store's real settings, products, and tax rates.
534 + * populated using the store's real settings, products, and tax rates. The
535 + * gallery fixture loader layers its overrides on this before filtering.
513 536 *
514 537 * @param object|null $pos_store POS store object. Falls back to default store.
515 538 *
516 539 * @return array Complete receipt data array.
517 540 */
518 - public function build( $pos_store = null ): array {
541 + public function sample( $pos_store = null ): array {
519 542 $resolved_store = null === $pos_store ? wcpos_get_store() : $pos_store;
520 543 if ( ! \is_object( $resolved_store ) ) {
521 544 $resolved_store = wcpos_get_store();
522 545 }
523 - $this->pos_store = \is_object( $resolved_store ) ? $resolved_store : new Store();
524 - $this->store_resolver = new Receipt_Store_Resolver( $this->pos_store );
546 + $this->store_resolver = new Receipt_Store_Resolver( \is_object( $resolved_store ) ? $resolved_store : new Store() );
525 547 $currency = $this->resolve_currency();
526 548 $display_incl = 'incl' === $this->store_resolver->resolve_store_option_string(
527 549 'get_tax_display_cart',
528 550 get_option( 'woocommerce_tax_display_cart', 'excl' )
@@ -543,9 +565,9 @@
543 565 );
544 566 $dp = $this->store_resolver->resolve_price_num_decimals();
545 567
546 568 // Build line items.
547 - $lines = array();
569 + $priced_lines = array();
548 570 $lines_total_excl = 0.0;
549 571 $lines_total_incl = 0.0;
550 572
551 573 foreach ( $raw_products as $index => $product ) {
@@ -577,54 +599,51 @@
577 599 $line_regular_excl = round( $regular_unit_excl * $qty, $dp );
578 600 $line_savings_incl = round( $unit_savings_incl * $qty, $dp );
579 601 $line_savings_excl = round( $unit_savings_excl * $qty, $dp );
580 602
581 - $unit_price_rounded = $display_incl ? $selling_unit_incl : $selling_unit_excl;
582 -
583 - $lines[] = array(
584 - 'key' => (string) ( $index + 1 ),
585 - 'sku' => $product['sku'],
586 - 'name' => $product['name'],
587 - 'qty' => (float) $qty,
588 - 'qty_refunded' => 0.0,
589 - 'regular_price' => $display_incl ? $regular_unit_incl : $regular_unit_excl,
590 - 'regular_price_incl' => $regular_unit_incl,
591 - 'regular_price_excl' => $regular_unit_excl,
592 - 'selling_price' => $unit_price_rounded,
593 - 'selling_price_incl' => $selling_unit_incl,
594 - 'selling_price_excl' => $selling_unit_excl,
595 - 'unit_savings' => $display_incl ? $unit_savings_incl : $unit_savings_excl,
596 - 'unit_savings_incl' => $unit_savings_incl,
597 - 'unit_savings_excl' => $unit_savings_excl,
598 - 'line_regular_total' => $display_incl ? $line_regular_incl : $line_regular_excl,
599 - 'line_regular_total_incl' => $line_regular_incl,
600 - 'line_regular_total_excl' => $line_regular_excl,
601 - 'line_selling_total' => $display_incl ? $line_total_incl : $line_total_excl,
602 - 'line_selling_total_incl' => $line_total_incl,
603 - 'line_selling_total_excl' => $line_total_excl,
604 - 'line_savings' => $display_incl ? $line_savings_incl : $line_savings_excl,
605 - 'line_savings_incl' => $line_savings_incl,
606 - 'line_savings_excl' => $line_savings_excl,
603 + $priced_lines[] = array(
604 + 'key' => (string) ( $index + 1 ),
605 + 'sku' => $product['sku'],
606 + 'name' => $product['name'],
607 + 'qty' => (float) $qty,
608 + 'qty_refunded' => 0.0,
609 + 'regular_price' => array(
610 + 'incl' => $regular_unit_incl,
611 + 'excl' => $regular_unit_excl,
612 + ),
613 + 'selling_price' => array(
614 + 'incl' => $selling_unit_incl,
615 + 'excl' => $selling_unit_excl,
616 + ),
617 + 'unit_savings' => array(
618 + 'incl' => $unit_savings_incl,
619 + 'excl' => $unit_savings_excl,
620 + ),
621 + 'line_regular_total' => array(
622 + 'incl' => $line_regular_incl,
623 + 'excl' => $line_regular_excl,
624 + ),
625 + 'line_selling_total' => array(
626 + 'incl' => $line_total_incl,
627 + 'excl' => $line_total_excl,
628 + ),
629 + 'line_savings' => array(
630 + 'incl' => $line_savings_incl,
631 + 'excl' => $line_savings_excl,
632 + ),
633 + 'unit_subtotal' => array(
634 + 'incl' => $selling_unit_incl,
635 + 'excl' => $selling_unit_excl,
636 + ),
637 + 'line_subtotal' => array(
638 + 'incl' => $line_total_incl,
639 + 'excl' => $line_total_excl,
640 + ),
607 641 'savings_in_discounts' => false,
608 - 'unit_subtotal' => $unit_price_rounded,
609 - 'unit_subtotal_incl' => $selling_unit_incl,
610 - 'unit_subtotal_excl' => $selling_unit_excl,
611 - 'unit_price' => $unit_price_rounded,
612 - 'unit_price_incl' => $selling_unit_incl,
613 - 'unit_price_excl' => $selling_unit_excl,
614 - 'line_subtotal' => $display_incl ? $line_total_incl : $line_total_excl,
615 - 'line_subtotal_incl' => $line_total_incl,
616 - 'line_subtotal_excl' => $line_total_excl,
617 - 'discounts' => 0.0,
618 - 'discounts_incl' => 0.0,
619 - 'discounts_excl' => 0.0,
620 - 'line_total' => $display_incl ? $line_total_incl : $line_total_excl,
621 - 'line_total_incl' => $line_total_incl,
622 - 'line_total_excl' => $line_total_excl,
623 - 'total_refunded' => 0.0,
624 - 'taxes' => array(),
625 - 'meta' => $product['meta'] ?? array(),
626 - 'attributes' => $product['attributes'] ?? array(),
642 + 'total_refunded' => 0.0,
643 + 'taxes' => array(),
644 + 'meta' => $product['meta'] ?? array(),
645 + 'attributes' => $product['attributes'] ?? array(),
627 646 );
628 647
629 648 $lines_total_excl += $line_total_excl;
630 649 $lines_total_incl += $line_total_incl;
@@ -659,52 +678,47 @@
659 678
660 679 // Distribute discount proportionally across line items with remainder correction.
661 680 $sum_discount_excl = 0.0;
662 681 $sum_discount_incl = 0.0;
663 - $last_index = count( $lines ) - 1;
682 + $last_index = count( $priced_lines ) - 1;
664 683
665 - foreach ( $lines as $i => &$line ) {
684 + foreach ( $priced_lines as $i => &$line ) {
666 685 if ( $lines_total_excl > 0 ) {
667 - $share = $line['line_subtotal_excl'] / $lines_total_excl;
686 + $share = $line['line_subtotal']['excl'] / $lines_total_excl;
668 687 } else {
669 - $share = 1.0 / count( $lines );
688 + $share = 1.0 / count( $priced_lines );
670 689 }
671 690
672 691 if ( $i < $last_index ) {
673 - $line['discounts_excl'] = round( $discount_excl * $share, $dp );
674 - $line['discounts_incl'] = round( $discount_incl * $share, $dp );
675 - $sum_discount_excl += $line['discounts_excl'];
676 - $sum_discount_incl += $line['discounts_incl'];
692 + $line['discounts']['excl'] = round( $discount_excl * $share, $dp );
693 + $line['discounts']['incl'] = round( $discount_incl * $share, $dp );
694 + $sum_discount_excl += $line['discounts']['excl'];
695 + $sum_discount_incl += $line['discounts']['incl'];
677 696 } else {
678 697 // Assign remainder to last item so distributed totals match exactly.
679 - $line['discounts_excl'] = round( $discount_excl - $sum_discount_excl, $dp );
680 - $line['discounts_incl'] = round( $discount_incl - $sum_discount_incl, $dp );
698 + $line['discounts']['excl'] = round( $discount_excl - $sum_discount_excl, $dp );
699 + $line['discounts']['incl'] = round( $discount_incl - $sum_discount_incl, $dp );
681 700 }
682 701
683 - $line['discounts'] = $display_incl ? $line['discounts_incl'] : $line['discounts_excl'];
684 - $line['line_total_excl'] = round( $line['line_subtotal_excl'] - $line['discounts_excl'], $dp );
685 - $line['line_total_incl'] = round( $line['line_subtotal_incl'] - $line['discounts_incl'], $dp );
686 - $line['line_total'] = $display_incl ? $line['line_total_incl'] : $line['line_total_excl'];
687 - $line['unit_price_incl'] = round( $line['line_total_incl'] / $line['qty'], $dp );
688 - $line['unit_price_excl'] = round( $line['line_total_excl'] / $line['qty'], $dp );
689 - $line['unit_price'] = $display_incl ? $line['unit_price_incl'] : $line['unit_price_excl'];
702 + $line['line_total']['excl'] = round( $line['line_subtotal']['excl'] - $line['discounts']['excl'], $dp );
703 + $line['line_total']['incl'] = round( $line['line_subtotal']['incl'] - $line['discounts']['incl'], $dp );
704 + $line['unit_price']['incl'] = round( $line['line_total']['incl'] / $line['qty'], $dp );
705 + $line['unit_price']['excl'] = round( $line['line_total']['excl'] / $line['qty'], $dp );
690 706 }
691 707 unset( $line );
692 708
693 - // Totals.
694 - $subtotal_excl = $lines_total_excl;
695 - $subtotal_incl = $lines_total_incl;
709 + $lines = array_map(
710 + static function ( array $line ) use ( $display_incl ): array {
711 + return Receipt_Sections::line( $line, $display_incl );
712 + },
713 + $priced_lines
714 + );
696 715
697 - // Item count summaries — matches the real builder's totals.total_qty
698 - // / totals.line_count so preview mirrors the live receipt schema.
699 - $total_qty = (float) array_sum( array_column( $lines, 'qty' ) );
700 - $line_count = \count( $lines );
701 -
702 716 // Taxable base: line items - discount + shipping + fee (all excl).
703 - $taxable_excl = $subtotal_excl - $discount_excl + $shipping_excl + $fee_excl;
717 + $taxable_excl = $lines_total_excl - $discount_excl + $shipping_excl + $fee_excl;
704 718 $total_tax = round( $taxable_excl * $tax_rate / 100, $dp );
705 719
706 - $total_excl = $subtotal_excl - $discount_excl + $shipping_excl + $fee_excl;
720 + $total_excl = $lines_total_excl - $discount_excl + $shipping_excl + $fee_excl;
707 721 $total_incl = $total_excl + $total_tax;
708 722
709 723 // Payment: cash rounded up to nearest 5.
710 724 $tendered = (float) ( ceil( $total_incl / 5 ) * 5 );
@@ -721,8 +735,9 @@
721 735 'number' => '1234',
722 736 'currency' => $currency,
723 737 'customer_note' => __( 'Please gift wrap this order. Thank you!', 'woocommerce-pos' ),
724 738 'wc_status' => 'completed',
739 + 'status_label' => wc_get_order_status_name( 'completed' ),
725 740 'created_via' => 'woocommerce-pos',
726 741 'created' => Receipt_Date_Formatter::from_timestamp( $created_timestamp, $date_timezone, $date_locale ),
727 742 'paid' => Receipt_Date_Formatter::from_timestamp( $paid_timestamp, $date_timezone, $date_locale ),
728 743 'completed' => Receipt_Date_Formatter::from_timestamp( $completed_timestamp, $date_timezone, $date_locale ),
@@ -737,95 +752,72 @@
737 752
738 753 $customer = $this->get_customer();
739 754
740 755 $fees = array(
741 - array(
742 - 'label' => $fee_label,
743 - 'total' => $display_incl ? $fee_incl : $fee_excl,
744 - 'total_incl' => $fee_incl,
745 - 'total_excl' => $fee_excl,
746 - 'taxes' => array(),
747 - 'meta' => array(),
756 + Receipt_Sections::fee(
757 + $fee_label,
758 + array(
759 + 'incl' => $fee_incl,
760 + 'excl' => $fee_excl,
761 + ),
762 + array(),
763 + array(),
764 + $display_incl
748 765 ),
749 766 );
750 -
751 767 $shipping = array(
752 - array(
753 - 'label' => $shipping_label,
754 - 'method_id' => 'flat_rate',
755 - 'total' => $display_incl ? $shipping_incl : $shipping_excl,
756 - 'total_incl' => $shipping_incl,
757 - 'total_excl' => $shipping_excl,
758 - 'taxes' => array(),
759 - 'meta' => array(),
768 + Receipt_Sections::shipping(
769 + $shipping_label,
770 + 'flat_rate',
771 + array(
772 + 'incl' => $shipping_incl,
773 + 'excl' => $shipping_excl,
774 + ),
775 + array(),
776 + array(),
777 + $display_incl
760 778 ),
761 779 );
762 -
763 780 $discounts = array(
781 + Receipt_Sections::discount(
782 + $discount_label,
783 + 'SUMMER10',
784 + 'fixed_cart',
785 + array(
786 + 'incl' => $discount_incl,
787 + 'excl' => $discount_excl,
788 + ),
789 + $display_incl
790 + ),
791 + );
792 + $totals = Receipt_Sections::totals(
793 + $lines,
764 794 array(
765 - 'label' => $discount_label,
766 - 'code' => 'SUMMER10',
767 - 'total' => $display_incl ? $discount_incl : $discount_excl,
768 - 'total_incl' => $discount_incl,
769 - 'total_excl' => $discount_excl,
795 + 'discount_total' => array(
796 + 'incl' => $discount_incl,
797 + 'excl' => $discount_excl,
798 + ),
799 + 'tax_total' => $total_tax,
800 + 'total' => $total_incl,
801 + 'paid_total' => $total_incl,
802 + 'change_total' => $change_total,
803 + 'refund_total' => 0.0,
770 804 ),
805 + $display_incl
771 806 );
772 807
773 - $sale_savings_total_incl = (float) array_sum( array_column( $lines, 'line_savings_incl' ) );
774 - $sale_savings_total_excl = (float) array_sum( array_column( $lines, 'line_savings_excl' ) );
775 - $total_saved_incl = $discount_incl + $sale_savings_total_incl;
776 - $total_saved_excl = $discount_excl + $sale_savings_total_excl;
808 + $tax_summary = $tax_rate > 0 ? array(
809 + Receipt_Sections::tax_summary_entry( $tax_code, $tax_rate, $tax_label, false, $taxable_excl, $total_tax ),
810 + ) : array();
777 811
778 - $totals = array(
779 - 'subtotal' => $display_incl ? $subtotal_incl : $subtotal_excl,
780 - 'subtotal_incl' => $subtotal_incl,
781 - 'subtotal_excl' => $subtotal_excl,
782 - 'discount_total' => $display_incl ? $discount_incl : $discount_excl,
783 - 'discount_total_incl' => $discount_incl,
784 - 'discount_total_excl' => $discount_excl,
785 - 'sale_savings_total' => $display_incl ? $sale_savings_total_incl : $sale_savings_total_excl,
786 - 'sale_savings_total_incl' => $sale_savings_total_incl,
787 - 'sale_savings_total_excl' => $sale_savings_total_excl,
788 - 'total_saved' => $display_incl ? $total_saved_incl : $total_saved_excl,
789 - 'total_saved_incl' => $total_saved_incl,
790 - 'total_saved_excl' => $total_saved_excl,
791 - 'total_saved_complete' => true,
792 - 'tax_total' => $total_tax,
793 - 'total' => $display_incl ? $total_incl : $total_excl,
794 - 'total_incl' => $total_incl,
795 - 'total_excl' => $total_excl,
796 - 'paid_total' => $total_incl,
797 - 'change_total' => $change_total,
798 - 'total_qty' => $total_qty,
799 - 'line_count' => $line_count,
800 - );
801 -
802 - $taxable_amount_incl = $taxable_excl + $total_tax;
803 -
804 - if ( $tax_rate > 0 ) {
805 - $tax_summary = array(
806 - array(
807 - 'code' => $tax_code,
808 - 'rate' => $tax_rate,
809 - 'label' => $tax_label,
810 - 'compound' => false,
811 - 'taxable_amount_excl' => $taxable_excl,
812 - 'tax_amount' => $total_tax,
813 - 'taxable_amount_incl' => $taxable_amount_incl,
814 - ),
815 - );
816 - } else {
817 - $tax_summary = array();
818 - }
819 -
820 812 $payments = array(
821 - array(
822 - 'method_id' => 'pos_cash',
823 - 'method_title' => /* translators: Sample receipt label or value used in receipt template previews. */ __( 'Cash', 'woocommerce-pos' ),
824 - 'amount' => $total_incl,
825 - 'transaction_id' => '',
826 - 'tendered' => $tendered,
827 - 'change' => $change_total,
813 + Receipt_Sections::payment(
814 + 'pos_cash',
815 + /* translators: Sample receipt label or value used in receipt template previews. */ __( 'Cash', 'woocommerce-pos' ),
816 + $total_incl,
817 + '',
818 + $tendered,
819 + $change_total
828 820 ),
829 821 );
830 822
831 823 $refunds = array();
@@ -832,50 +824,52 @@
832 824
833 825 $presentation_hints = $this->store_resolver->build_presentation_hints( $currency, $prices_include_tax );
834 826 $tax = $this->store_resolver->build_tax_section();
835 827
836 - $fiscal = array(
837 - 'immutable_id' => '12345:42',
838 - 'receipt_number' => '00042',
839 - 'sequence' => 42,
840 - 'hash' => 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2',
841 - 'qr_payload' => 'https://example.com/verify?id=SAMPLE-001',
842 - 'tax_agency_code' => 'SAMPLE',
843 - 'signed_at' => gmdate( 'Y-m-d\TH:i:s\Z' ),
844 - 'signature_excerpt' => 'A1B2',
845 - 'document_label' => /* translators: Sample receipt label or value used in receipt template previews. */ __( 'Tax Receipt', 'woocommerce-pos' ),
846 - 'is_reprint' => false,
847 - 'reprint_count' => 0,
848 - 'extra_fields' => array(
849 - array(
850 - 'label' => /* translators: Sample receipt label or value used in receipt template previews. */ __( 'Tax ID', 'woocommerce-pos' ),
851 - 'value' => 'XX-1234567',
828 + $fiscal = Receipt_Payload_Assembler::fiscal(
829 + array(
830 + 'immutable_id' => '12345:42',
831 + 'receipt_number' => '00042',
832 + 'sequence' => 42,
833 + 'hash' => 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2',
834 + 'qr_payload' => 'https://example.com/verify?id=SAMPLE-001',
835 + 'tax_agency_code' => 'SAMPLE',
836 + 'signed_at' => gmdate( 'Y-m-d\TH:i:s\Z' ),
837 + 'signature_excerpt' => 'A1B2',
838 + 'document_label' => /* translators: Sample receipt label or value used in receipt template previews. */ __( 'Tax Receipt', 'woocommerce-pos' ),
839 + 'is_reprint' => false,
840 + 'reprint_count' => 0,
841 + 'extra_fields' => array(
842 + array(
843 + 'label' => /* translators: Sample receipt label or value used in receipt template previews. */ __( 'Tax ID', 'woocommerce-pos' ),
844 + 'value' => 'XX-1234567',
845 + ),
846 + array(
847 + 'label' => /* translators: Sample receipt label or value used in receipt template previews. */ __( 'Auth Code', 'woocommerce-pos' ),
848 + 'value' => 'ABC-789',
849 + ),
852 850 ),
853 - array(
854 - 'label' => /* translators: Sample receipt label or value used in receipt template previews. */ __( 'Auth Code', 'woocommerce-pos' ),
855 - 'value' => 'ABC-789',
856 - ),
857 - ),
851 + )
858 852 );
859 853
860 - return array(
861 - 'order' => $order,
862 - 'store' => $store,
863 - 'cashier' => $cashier,
864 - 'customer' => $customer,
865 - 'lines' => $lines,
866 - 'fees' => $fees,
867 - 'shipping' => $shipping,
868 - 'discounts' => $discounts,
869 - 'totals' => $totals,
870 - 'tax' => $tax,
871 - 'tax_summary' => $tax_summary,
872 - 'has_tax_summary' => ! empty( $tax_summary ),
873 - 'payments' => $payments,
874 - 'refunds' => $refunds,
875 - 'fiscal' => $fiscal,
876 - 'presentation_hints' => $presentation_hints,
877 - 'i18n' => Receipt_I18n_Labels::get_labels( $presentation_hints['locale'] ?? '' ),
854 + return Receipt_Payload_Assembler::assemble(
855 + array(
856 + 'order' => $order,
857 + 'store' => $store,
858 + 'cashier' => $cashier,
859 + 'customer' => $customer,
860 + 'lines' => $lines,
861 + 'fees' => $fees,
862 + 'shipping' => $shipping,
863 + 'discounts' => $discounts,
864 + 'totals' => $totals,
865 + 'tax' => $tax,
866 + 'tax_summary' => $tax_summary,
867 + 'payments' => $payments,
868 + 'refunds' => $refunds,
869 + 'fiscal' => $fiscal,
870 + 'presentation_hints' => $presentation_hints,
871 + )
878 872 );
879 873 }
880 874
881 875 /**
@@ -883,84 +877,26 @@
883 877 *
884 878 * @return array Store data with name, address, branding, and policy fields.
885 879 */
886 880 private function get_store_info(): array {
887 - $pos_store = $this->pos_store;
888 - $store_id = (int) $this->store_resolver->get_store_value( 'get_id', 0 );
889 - $store_name = (string) $this->store_resolver->get_store_value( 'get_name', '' );
890 - $store_address = (string) $this->store_resolver->get_store_value( 'get_store_address', '' );
891 - $store_address_2 = (string) $this->store_resolver->get_store_value( 'get_store_address_2', '' );
892 - $store_city = (string) $this->store_resolver->get_store_value( 'get_store_city', '' );
893 - $store_postcode = (string) $this->store_resolver->get_store_value( 'get_store_postcode', '' );
894 - $store_country = (string) $this->store_resolver->get_store_value( 'get_store_country', '' );
895 - $store_state = (string) $this->store_resolver->get_store_value( 'get_store_state', '' );
896 - $store_phone = (string) $this->store_resolver->get_store_value( 'get_phone', '' );
897 - $store_email = (string) $this->store_resolver->get_store_value( 'get_email', '' );
898 - $store_tax_ids = $this->store_resolver->get_store_value( 'get_tax_ids', array() );
899 - $store_tax_ids = is_array( $store_tax_ids ) ? $store_tax_ids : array();
900 - $store_tax_ids = Receipt_Store_Resolver::with_store_tax_id_labels( $store_tax_ids, $this->store_resolver->resolve_locale() );
901 -
902 - $store_address_parts = array(
903 - 'address_1' => $store_address,
904 - 'address_2' => $store_address_2,
905 - 'city' => $store_city,
906 - 'state' => $store_state,
907 - 'postcode' => $store_postcode,
908 - 'country' => $store_country,
881 + return $this->store_resolver->build_store_section(
882 + array(
883 + // Sample content stands in wherever the store has nothing configured,
884 + // so preview templates always have every section to lay out.
885 + 'opening_hours' => array(
886 + '0' => array( '09:00', '17:00' ),
887 + '1' => array( '09:00', '17:00' ),
888 + '2' => array( '09:00', '17:00' ),
889 + '3' => array( '09:00', '17:00' ),
890 + '4' => array( '09:00', '17:00' ),
891 + '5' => array( '10:00', '16:00' ),
892 + '6' => array(),
893 + ),
894 + 'personal_notes' => /* translators: Sample receipt label or value used in receipt template previews. */ __( 'Thank you for shopping with us! We appreciate your business.', 'woocommerce-pos' ),
895 + 'policies_and_conditions' => /* translators: Sample receipt label or value used in receipt template previews. */ __( 'Returns accepted within 30 days with original receipt. Items must be unused and in original packaging.', 'woocommerce-pos' ),
896 + 'footer_imprint' => /* translators: Sample receipt label or value used in receipt template previews. */ __( 'Thank you for your purchase!', 'woocommerce-pos' ),
897 + )
909 898 );
910 -
911 - $store = array(
912 - 'id' => $store_id,
913 - 'name' => '' !== $store_name ? $store_name : get_bloginfo( 'name' ),
914 - 'address' => $store_address_parts,
915 - 'address_lines' => Receipt_Store_Resolver::compose_address_lines( $store_address_parts ),
916 - 'tax_ids' => $store_tax_ids,
917 - 'phone' => $store_phone,
918 - 'email' => $store_email,
919 - );
920 -
921 - $opening_hours_raw = $this->store_resolver->get_store_value( 'get_opening_hours', array() );
922 - $personal_notes = (string) $this->store_resolver->get_store_value( 'get_personal_notes', '' );
923 - $policies_and_conditions = (string) $this->store_resolver->get_store_value( 'get_policies_and_conditions', '' );
924 - $footer_imprint = (string) $this->store_resolver->get_store_value( 'get_footer_imprint', '' );
925 -
926 - if ( ! empty( $opening_hours_raw ) && \is_array( $opening_hours_raw ) ) {
927 - $store['opening_hours'] = Opening_Hours_Formatter::format_compact( $opening_hours_raw );
928 - $store['opening_hours_vertical'] = Opening_Hours_Formatter::format_vertical( $opening_hours_raw );
929 - $store['opening_hours_inline'] = Opening_Hours_Formatter::format_inline( $opening_hours_raw );
930 - } elseif ( \is_string( $opening_hours_raw ) && '' !== trim( $opening_hours_raw ) ) {
931 - $store['opening_hours'] = $opening_hours_raw;
932 - $store['opening_hours_vertical'] = null;
933 - $store['opening_hours_inline'] = null;
934 - } else {
935 - // Sample hours for preview when none configured.
936 - $opening_hours_raw = array(
937 - '0' => array( '09:00', '17:00' ),
938 - '1' => array( '09:00', '17:00' ),
939 - '2' => array( '09:00', '17:00' ),
940 - '3' => array( '09:00', '17:00' ),
941 - '4' => array( '09:00', '17:00' ),
942 - '5' => array( '10:00', '16:00' ),
943 - '6' => array(),
944 - );
945 - $store['opening_hours'] = Opening_Hours_Formatter::format_compact( $opening_hours_raw );
946 - $store['opening_hours_vertical'] = Opening_Hours_Formatter::format_vertical( $opening_hours_raw );
947 - $store['opening_hours_inline'] = Opening_Hours_Formatter::format_inline( $opening_hours_raw );
948 - }
949 - $store['logo'] = Store_Logo_Resolver::resolve( $pos_store );
950 - $opening_hours_notes = (string) $this->store_resolver->get_store_value( 'get_opening_hours_notes', '' );
951 - $store['opening_hours_notes'] = '' !== $opening_hours_notes ? $opening_hours_notes : null;
952 - $store['personal_notes'] = ( null !== $personal_notes && '' !== $personal_notes )
953 - ? $personal_notes
954 - : __( 'Thank you for shopping with us! We appreciate your business.', 'woocommerce-pos' );
955 - $store['policies_and_conditions'] = ( null !== $policies_and_conditions && '' !== $policies_and_conditions )
956 - ? $policies_and_conditions
957 - : __( 'Returns accepted within 30 days with original receipt. Items must be unused and in original packaging.', 'woocommerce-pos' );
958 - $store['footer_imprint'] = ( null !== $footer_imprint && '' !== $footer_imprint )
959 - ? $footer_imprint
960 - : __( 'Thank you for your purchase!', 'woocommerce-pos' );
961 -
962 - return $store;
963 899 }
964 900
965 901
966 902 /**
@@ -970,12 +906,12 @@
970 906 *
971 907 * @return string ISO 4217 currency code (e.g. "USD", "EUR").
972 908 */
973 909 private function resolve_currency(): string {
974 - $fallback = get_option( 'woocommerce_currency', 'USD' );
975 - $store_currency = (string) $this->store_resolver->get_store_value( 'get_currency', '' );
976 -
977 - return '' !== $store_currency ? $store_currency : $fallback;
910 + return $this->store_resolver->resolve_store_option_string(
911 + 'get_currency',
912 + get_option( 'woocommerce_currency', 'USD' )
913 + );
978 914 }
979 915
980 916
981 917 /**
@@ -1151,19 +1087,10 @@
1151 1087 ),
1152 1088 );
1153 1089
1154 1090 $tax_ids = $samples[ $country ] ?? array();
1155 - $labels = Receipt_I18n_Labels::get_labels( $locale );
1156 1091
1157 - return array_map(
1158 - static function ( array $tax_id ) use ( $labels ): array {
1159 - $type = (string) $tax_id['type'];
1160 - $tax_id['label'] = $labels[ 'customer_tax_id_label_' . $type ] ?? $labels['customer_tax_id_label_other'];
1161 -
1162 - return $tax_id;
1163 - },
1164 - $tax_ids
1165 - );
1092 + return Receipt_Sections::label_tax_ids( $tax_ids, 'customer', $locale );
1166 1093 }
1167 1094
1168 1095 /**
1169 1096 * Get product data for line items.
@@ -1196,19 +1123,9 @@
1196 1123 if ( ! empty( $children ) ) {
1197 1124 $variation = wc_get_product( $children[0] );
1198 1125 if ( $variation instanceof \WC_Product_Variation ) {
1199 1126 $product = $variation;
1200 - foreach ( $variation->get_variation_attributes() as $attr_key => $attr_value ) {
1201 - if ( '' !== $attr_value ) {
1202 - $taxonomy = str_replace( 'attribute_', '', $attr_key );
1203 - $label = wc_attribute_label( $taxonomy, $variation );
1204 - $value = $variation->get_attribute( $taxonomy );
1205 - $meta[] = array(
1206 - 'key' => wp_strip_all_tags( $label ),
1207 - 'value' => wp_strip_all_tags( '' !== $value ? $value : $attr_value ),
1208 - );
1209 - }
1210 - }
1127 + $meta = Receipt_Sections::variation_attribute_pairs( $variation );
1211 1128 }
1212 1129 }
1213 1130 }
1214 1131