Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 57
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 / 57
0.00% covered (danger)
0.00%
0 / 3
132
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 generate_new_addresses
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 check_transactions
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 1
90
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\Helpers\JsonMapper\JsonMapper_Helper;
13use BrianHenryIE\WP_Bitcoin_Gateway\API\Model\Wallet\Bitcoin_Address;
14use BrianHenryIE\WP_Bitcoin_Gateway\API\Repositories\Factories\Bitcoin_Address_Factory;
15use BrianHenryIE\WP_Bitcoin_Gateway\API\Repositories\Bitcoin_Address_Repository;
16use BrianHenryIE\WP_Bitcoin_Gateway\API\Model\Wallet\Bitcoin_Address_WP_Post_Interface;
17use BrianHenryIE\WP_Bitcoin_Gateway\API_Interface;
18use BrianHenryIE\WP_Bitcoin_Gateway\Settings_Interface;
19use BrianHenryIE\WP_Bitcoin_Gateway\WP_CLI_Logger\WP_CLI_Logger;
20use Exception;
21use InvalidArgumentException;
22use Psr\Log\LoggerAwareTrait;
23use Psr\Log\LoggerInterface;
24use Psr\Log\NullLogger;
25use WP_CLI;
26use WP_CLI\ExitException;
27use WP_CLI_Command;
28
29/**
30 * Run `wp bh-bitcoin help` for documentation.
31 */
32class CLI extends WP_CLI_Command {
33    use LoggerAwareTrait;
34
35    /**
36     * Constructor.
37     *
38     * @param API_Interface      $api The main plugin functions.
39     * @param Settings_Interface $settings The plugin's settings.
40     * @param LoggerInterface    $logger A PSR logger.
41     */
42    public function __construct(
43        protected API_Interface $api,
44        protected Settings_Interface $settings,
45        LoggerInterface $logger
46    ) {
47        parent::__construct();
48        $this->setLogger( $logger );
49    }
50
51    /**
52     * Generate new addresses.
53     *
54     * TODO: Should be an option to mark it used (i.e. generate it for external use).
55     *
56     * ## OPTIONS
57     *
58     * [--debug=bh-wp-bitcoin-gateway]
59     * : Show detailed progress.
60     *
61     * ## EXAMPLES
62     *
63     *   # Check for new transactions for all gateways.
64     *   $ wp bh-bitcoin generate-new-addresses
65     *
66     *   # Check for new transactions for all gateways and show detailed progress.
67     *   $ wp bh-bitcoin generate-new-addresses --debug=bh-wp-bitcoin-gateway
68     *
69     * @param array<int|string, string> $args Takes no arguments.
70     */
71    public function generate_new_addresses( array $args ): void {
72
73        $result = $this->api->generate_new_addresses();
74        $this->api->check_new_addresses_for_transactions();
75
76        // TODO: Print a table of new addresses and their status.
77        // Print a summary of the table.
78
79        WP_CLI::log( 'Finished generate-new-addresses.' );
80        WP_CLI::log( 'Success' );
81    }
82
83    /**
84     * Query the blockchain for updates for an address or order.
85     *
86     * See also: `wp post list --post_type=shop_order --post_status=wc-on-hold --meta_key=_payment_gateway --meta_value=bitcoin_gateway --format=ids`.
87     * `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`
88     *
89     *
90     * ## OPTIONS
91     *
92     * <input>
93     * : A payment address string, payment address post_id, or order id.
94     *
95     * [--format=<format>]
96     * Render output in a specific format.
97     * ---
98     * default: table
99     * options:
100     * - table
101     * - json
102     * - csv
103     * - yaml
104     * ---
105     *
106     * [--debug=<bh-wp-bitcoin-gateway>]
107     * : Show detailed progress.
108     *
109     * ## EXAMPLES
110     *
111     *   # Check for new transactions for the provided Bitcoin address
112     *   $ wp bh-bitcoin check-transactions 0a1b2c3e4f6g7h9
113     *
114     *   # Check for new transactions for the provided order
115     *   $ wp bh-bitcoin check-transactions 123
116     *
117     *   # Check for new transactions for the provided order, showing detailed progress.
118     *   $ wp bh-bitcoin check-transactions 123 --debug=bh-wp-bitcoin-gateway
119     *
120     * @param string[]             $args The address.
121     * @param array<string,string> $assoc_args List of named arguments.
122     *
123     * @throws ExitException When given input that does not match a known xpub, or post_id for a bitcoin address or relevant WooCommerce order.
124     * @throws InvalidArgumentException When the input does not match an existing object.
125     */
126    public function check_transactions( array $args, array $assoc_args ): void {
127
128        /** @var string $input */
129        $input  = $args[0];
130        $format = $assoc_args['format'] ?? 'table';
131
132        // TODO: use BH WP_CLI_Logger here.
133        $bitcoin_address_factory    = new Bitcoin_Address_Factory( new JsonMapper_Helper()->build(), new NullLogger() );
134        $bitcoin_address_repository = new Bitcoin_Address_Repository( $bitcoin_address_factory );
135
136        try {
137            if ( ! is_numeric( $input ) ) {
138                // Assuming a raw address has been input.
139                $bitcoin_address_post_id = $bitcoin_address_repository->get_post_id_for_address( $input );
140                if ( is_null( $bitcoin_address_post_id ) ) {
141                    $this->logger->error( 'Could not find Bitcoin address object for {input}.', array( 'input' => $input ) );
142                    WP_CLI::error(
143                        sprintf(
144                            'Could not find Bitcoin address object for %s.',
145                            $input
146                        )
147                    );
148                }
149                try {
150                    $payment_address = $bitcoin_address_repository->get_by_post_id( $bitcoin_address_post_id );
151                } catch ( Exception $exception ) {
152                    $this->logger->error(
153                        'Could not find Bitcoin address object for {input}.',
154                        array(
155                            'exception' => $exception,
156                            'input'     => $input,
157                        )
158                    );
159                    WP_CLI::error(
160                        sprintf(
161                            'Could not find Bitcoin address object for %s.',
162                            $input
163                        )
164                    );
165                }
166            } elseif ( Bitcoin_Address_WP_Post_Interface::POST_TYPE === get_post_type( intval( $input ) ) ) {
167                $this->logger->debug( 'CLI input was `bh-bitcoin-address:{input}`', array( 'input' => $input ) );
168                $payment_address = $bitcoin_address_factory->get_by_wp_post_id( intval( $input ) );
169
170            } else {
171
172                $input_order_id = intval( $input );
173                /**
174                 * @param int $input_order_id The CLI input, presumed to be an order id.
175                 * @var ?Bitcoin_Address $payment_address
176                 */
177                $payment_address = apply_filters( 'bh_wp_bitcoin_gateway_get_address_for_order', null, $input_order_id );
178
179                if ( is_null( $payment_address ) ) {
180                    WP_CLI::error( 'Unable to determine payment address from input.' );
181                }
182
183                if ( ! ( $payment_address instanceof Bitcoin_Address ) ) {
184                    WP_CLI::error( 'Invalid value returned from filter.' );
185                }
186            }
187
188            $result = $this->api->check_address_for_payment( $payment_address );
189
190            $is_updated = $result->is_updated();
191
192            $formatted = array(
193                'address' => $result->queried_address->get_raw_address(),
194                'updated' => wc_bool_to_string( $is_updated ),
195            );
196
197            if ( $is_updated ) {
198                $formatted['new_transactions'] = $result->get_new_transactions();
199            }
200
201            $formatted['confirmed_received'] = $result->queried_address->get_amount_received();
202
203            WP_CLI\Utils\format_items( $format, $formatted, array_keys( $formatted ) );
204
205            WP_CLI::log( 'Finished update-address.' );
206
207        } catch ( Exception $exception ) {
208            WP_CLI::error( $exception->getMessage() );
209        }
210    }
211}