Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 47
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
CLI
0.00% covered (danger)
0.00%
0 / 47
0.00% covered (danger)
0.00%
0 / 3
156
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 generate_new_addresses
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 check_transactions
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 1
110
1<?php
2/**
3 * WP CLI commands for invoking API functions.
4 *
5 * Most useful to check an order for payment without waiting for Action Scheduler.
6 *
7 * @package    brianhenryie/bh-wp-bitcoin-gateway
8 */
9
10namespace BrianHenryIE\WP_Bitcoin_Gateway\WP_Includes;
11
12use BrianHenryIE\WP_Bitcoin_Gateway\API\Addresses\Bitcoin_Address;
13use BrianHenryIE\WP_Bitcoin_Gateway\API\Addresses\Bitcoin_Address_Factory;
14use BrianHenryIE\WP_Bitcoin_Gateway\API_Interface;
15use BrianHenryIE\WP_Bitcoin_Gateway\Settings_Interface;
16use BrianHenryIE\WP_Bitcoin_Gateway\WooCommerce\Order;
17use Psr\Log\LoggerAwareTrait;
18use Psr\Log\LoggerInterface;
19use WC_Order;
20use WP_CLI;
21use WP_CLI_Command;
22
23/**
24 * Run `wp bh-bitcoin help` for documentation.
25 */
26class CLI extends WP_CLI_Command {
27    use LoggerAwareTrait;
28
29    /**
30     * Not used.
31     *
32     * @var Settings_Interface
33     */
34    protected Settings_Interface $settings;
35
36    /**
37     * All CLI functions call into an instance of the API_Interface.
38     *
39     * @var API_Interface $api The main plugin API definition.
40     */
41    protected API_Interface $api;
42
43    /**
44     * Constructor.
45     *
46     * @param API_Interface      $api The main plugin functions.
47     * @param Settings_Interface $settings The plugin's settings.
48     * @param LoggerInterface    $logger A PSR logger.
49     */
50    public function __construct( API_Interface $api, Settings_Interface $settings, LoggerInterface $logger ) {
51        parent::__construct();
52        $this->setLogger( $logger );
53        $this->settings = $settings;
54        $this->api      = $api;
55    }
56
57    /**
58     * Generate new addresses for all gateways.
59     *
60     * ## OPTIONS
61     *
62     * [--<debug>=bh-wp-bitcoin-gateway]
63     * : Show detailed progress.
64     *
65     * ## EXAMPLES
66     *
67     *   # Check for new transactions for all gateways.
68     *   $ wp bh-bitcoin generate-new-addresses
69     *
70     *   # Check for new transactions for all gateways and show detailed progress.
71     *   $ wp bh-bitcoin generate-new-addresses --debug=bh-wp-bitcoin-gateway
72     *
73     * @param array<int|string, string> $args Takes no arguments.
74     */
75    public function generate_new_addresses( array $args ): void {
76
77        $result = $this->api->generate_new_addresses();
78        $this->api->check_new_addresses_for_transactions();
79
80        // TODO: Print a table of new addresses and their status.
81        // Print a summary of the table.
82
83        WP_CLI::log( 'Finished generate-new-addresses.' );
84    }
85
86    /**
87     * Query the blockchain for updates for an address or order.
88     *
89     * TODO: This doesn't seem to actually update the order!
90     *
91     * See also: `wp post list --post_type=shop_order --post_status=wc-on-hold --meta_key=_payment_gateway --meta_value=bitcoin_gateway --format=ids`.
92     * `wp post list --post_type=shop_order --post_status=wc-on-hold --meta_key=_payment_gateway --meta_value=bitcoin_gateway --format=ids | xargs -0 -d ' ' -I % wp bh-bitcoin check-transactions % --debug=bh-wp-bitcoin-gateway`
93     *
94     *
95     * ## OPTIONS
96     *
97     * <input>
98     * : The order id or Bitcoin address.
99     *
100     * [--format=<format>]
101     * Render output in a specific format.
102     * ---
103     * default: table
104     * options:
105     * - table
106     * - json
107     * - csv
108     * - yaml
109     * ---
110     *
111     * [--<debug>=bh-wp-bitcoin-gateway]
112     * : Show detailed progress.
113     *
114     * ## EXAMPLES
115     *
116     *   # Check for new transactions for the provided Bitcoin address
117     *   $ wp bh-bitcoin check-transactions 0a1b2c3e4f6g7h9
118     *
119     *   # Check for new transactions for the provided order
120     *   $ wp bh-bitcoin check-transactions 123
121     *
122     *   # Check for new transactions for the provided order, showing detailed progress.
123     *   $ wp bh-bitcoin check-transactions 123 --debug=bh-wp-bitcoin-gateway
124     *
125     * @param string[]             $args The address.
126     * @param array<string,string> $assoc_args List of named arguments.
127     *
128     * @throws WP_CLI\ExitException When given input that does not match a known xpub, or post_id for a bitcoin address or relevant WooCommerce order.
129     */
130    public function check_transactions( array $args, array $assoc_args ): void {
131
132        $input  = $args[0];
133        $format = isset( $assoc_args['format'] ) ? $assoc_args['format'] : 'table';
134
135        $address_factory = new Bitcoin_Address_Factory();
136
137        try {
138            switch ( get_post_type( intval( $input ) ) ) {
139                case Bitcoin_Address::POST_TYPE:
140                    $this->logger->debug( "CLI input was `bh-bitcoin-address:{$input}`" );
141                    $bitcoin_address = new Bitcoin_Address( intval( $input ) );
142                    break;
143                case 'shop_order':
144                    $order_id = intval( $input );
145                    $this->logger->debug( "CLI input was WooCommerce `shop_order:{$order_id}`" );
146                    /**
147                     * This was already determined to be an order!
148                     *
149                     * @var WC_Order $order
150                     */
151                    $order = wc_get_order( $order_id );
152                    if ( ! $this->api->is_order_has_bitcoin_gateway( $order_id ) ) {
153                        $this->logger->error( "`shop_order:{$order_id}` is not a Bitcoin order" );
154                        return;
155                    }
156                    $address                 = $order->get_meta( Order::BITCOIN_ADDRESS_META_KEY );
157                    $bitcoin_address_post_id = $address_factory->get_post_id_for_address( $address );
158                    if ( is_null( $bitcoin_address_post_id ) ) {
159                        $this->logger->error( "Could not find Bitcoin address object for address {$address} from order id {$input}." );
160                        return;
161                    }
162                    $bitcoin_address = $address_factory->get_by_post_id( $bitcoin_address_post_id );
163                    break;
164                default:
165                    // Assuming a raw address has been input.
166                    $bitcoin_address_post_id = $address_factory->get_post_id_for_address( $input );
167                    if ( is_null( $bitcoin_address_post_id ) ) {
168                        $this->logger->error( "Could not find Bitcoin address object for {$input}." );
169                        return;
170                    }
171                    $bitcoin_address = $address_factory->get_by_post_id( $bitcoin_address_post_id );
172            }
173
174            $result = $this->api->update_address_transactions( $bitcoin_address );
175
176            // TODO: Check for WooCommerce active.
177
178            $formatted = array(
179                'address' => $result['address']->get_raw_address(),
180                'updated' => wc_bool_to_string( $result['updated'] ),
181            );
182
183            if ( $result['updated'] ) {
184                $formatted['new_transactions']  = $result['updates']['new_transactions'];
185                $formatted['new_confirmations'] = $result['updates']['new_confirmations'];
186            }
187
188            $formatted['balance'] = $result['address']->get_balance();
189
190            WP_CLI\Utils\format_items( $format, $formatted, array_keys( $formatted ) );
191
192            WP_CLI::log( 'Finished update-address.' );
193
194        } catch ( \Exception $exception ) {
195            WP_CLI::error( $exception->getMessage() );
196        }
197    }
198}