Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
80.95% covered (warning)
80.95%
34 / 42
40.00% covered (danger)
40.00%
2 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
Admin_Order_UI
80.95% covered (warning)
80.95%
34 / 42
40.00% covered (danger)
40.00%
2 / 5
19.00
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 is_hpos_enabled
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 get_order_id
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
30
 register_address_transactions_meta_box
87.50% covered (warning)
87.50%
14 / 16
0.00% covered (danger)
0.00%
0 / 1
4.03
 print_address_transactions_metabox
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
5
1<?php
2/**
3 * Add a metabox with the payment details on the admin order page.
4 *
5 * @package    brianhenryie/bh-wp-bitcoin-gateway
6 */
7
8namespace BrianHenryIE\WP_Bitcoin_Gateway\Integrations\WooCommerce;
9
10use Automattic\WooCommerce\Utilities\OrderUtil;
11use Psr\Log\LoggerAwareTrait;
12use Psr\Log\LoggerInterface;
13use WC_Order;
14use WP_Post;
15
16/**
17 * Register and print a metabox on the shop_order page, display it only when the order is a Bitcoin order.
18 */
19class Admin_Order_UI {
20    use LoggerAwareTrait;
21
22    const TEMPLATE_NAME = 'admin/single-order-ui-bitcoin-details-metabox.php';
23
24    /**
25     * Constructor
26     *
27     * @param API_WooCommerce_Interface $api Instance of the main plugin class. Required for order details.
28     * @param LoggerInterface           $logger PSR logger.
29     */
30    public function __construct(
31        protected API_WooCommerce_Interface $api,
32        LoggerInterface $logger
33    ) {
34        $this->setLogger( $logger );
35    }
36
37    /**
38     * The admin order page before WooCommerce HPOS is a standard WP_List_Table for the registered post type,
39     * at `wp-admin/edit.php?post_type=wc_order&...`. HPOS is enabled by default for new sites since October 2023
40     * and uses
41     *
42     * @see https://developer.woocommerce.com/2023/10/10/woocommerce-8-2-0-released/
43     */
44    protected function is_hpos_enabled(): bool {
45        return class_exists( OrderUtil::class ) && OrderUtil::custom_orders_table_usage_is_enabled();
46    }
47
48    /**
49     * Get the id (presume order id) from the URL.
50     *
51     * @example `wp-admin/admin.php?page=wc-orders&action=edit&id=123` returns 123.
52     * @example `wp-admin/edit.php?post_type=wc-order&post=321` returns 321.
53     *
54     * phpcs:disable WordPress.Security.NonceVerification.Recommended
55     */
56    protected function get_order_id(): ?int {
57        if ( isset( $_GET['id'] ) && is_numeric( $_GET['id'] ) ) {
58            return absint( $_GET['id'] );
59        }
60
61        if ( isset( $_GET['post'] ) && is_numeric( $_GET['post'] ) ) {
62            return absint( $_GET['post'] );
63        }
64
65        return null;
66    }
67
68    /**
69     * Register the Bitcoin order details metabox on shop_order admin edit view.
70     *
71     * @hooked add_meta_boxes
72     *
73     * @return void
74     */
75    public function register_address_transactions_meta_box(): void {
76
77        $order_id = $this->get_order_id();
78
79        if ( is_null( $order_id ) ) {
80            return;
81        }
82
83        if ( ! $this->api->is_order_has_bitcoin_gateway( $order_id ) ) {
84            return;
85        }
86
87        /**
88         * Get the correct `screen` name/id for the meta box.
89         *
90         * WooCommerce with HPOS no longer uses the standard WordPress `wp-admin/edit.php?...` page.
91         *
92         * @see OrderUtil::custom_orders_table_usage_is_enabled()
93         *
94         * @var string $screen 'woocommerce_page_wc-orders'|'shop_order'.
95         */
96        $screen = function_exists( 'wc_get_page_screen_id' )
97            ? wc_get_page_screen_id( 'shop-order' )
98            : 'shop_order';
99
100        add_meta_box(
101            'bh-wp-bitcoin-gateway',
102            'Bitcoin', // TODO: translate.
103            $this->print_address_transactions_metabox( ... ),
104            $screen,
105            'normal',
106            'core'
107        );
108    }
109
110    /**
111     * Print a box of information showing the Bitcoin address, amount expcted, paid, transactions, last checked date.
112     *
113     * TODO: Display the difference between amount required and amount paid?
114     * TODO: "Check now" button.
115     *
116     * @see Admin_Order_UI::register_address_transactions_meta_box();
117     *
118     * @param WP_Post|WC_Order $post The post this edit page is running for.
119     */
120    public function print_address_transactions_metabox( $post ): void {
121
122        /**
123         * This is almost sure to be a valid order object, since this only runs on the order page.
124         *
125         * @var WC_Order $order
126         */
127        $order = $post instanceof WP_Post ? wc_get_order( $post->ID ) : $post;
128
129        $order_id = $order->get_id();
130
131        if ( ! $this->api->is_order_has_bitcoin_gateway( $order_id ) ) {
132            return;
133        }
134
135        // Once the order has been paid, no longer poll for new transactions, unless manually pressing refresh.
136        $refresh = ! $order->is_paid();
137
138        try {
139            if ( $refresh ) {
140                $this->api->check_order_for_payment( $order );
141            }
142            $template_args = $this->api->get_formatted_order_details( $order );
143        } catch ( \Exception $exception ) {
144            $this->logger->warning(
145                "Failed to get `shop_order:{$order_id}` details for admin order ui metabox template: {$exception->getMessage()}",
146                array(
147                    'order_id'  => $order_id,
148                    'exception' => $exception,
149                )
150            );
151            return;
152        }
153
154        $template_args['template'] = self::TEMPLATE_NAME;
155
156        wc_get_template( self::TEMPLATE_NAME, $template_args );
157    }
158}