Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
68.29% covered (warning)
68.29%
28 / 41
50.00% covered (danger)
50.00%
2 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
Background_Jobs
68.29% covered (warning)
68.29%
28 / 41
50.00% covered (danger)
50.00%
2 / 4
10.04
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 check_unpaid_order
68.57% covered (warning)
68.57%
24 / 35
0.00% covered (danger)
0.00%
0 / 1
5.78
 generate_new_addresses
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 check_new_addresses_for_transactions
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * After five minutes check the unpaid order for payments.
4 *  - TODO After x unpaid time, mark unpaid orders as failed/cancelled.
5 * When the fresh address list falls below the cache threshold, generate new addresses.
6 *
7 * @package    brianhenryie/bh-wp-bitcoin-gateway
8 */
9
10namespace BrianHenryIE\WP_Bitcoin_Gateway\Action_Scheduler;
11
12use ActionScheduler;
13use Exception;
14use BrianHenryIE\WP_Bitcoin_Gateway\API_Interface;
15use Psr\Log\LoggerAwareTrait;
16use Psr\Log\LoggerInterface;
17use WC_Order;
18
19/**
20 * Handles do_action initiated from Action Scheduler.
21 */
22class Background_Jobs {
23    use LoggerAwareTrait;
24
25    const CHECK_UNPAID_ORDER_HOOK               = 'bh_wp_bitcoin_gateway_check_unpaid_order';
26    const GENERATE_NEW_ADDRESSES_HOOK           = 'bh_wp_bitcoin_gateway_generate_new_addresses';
27    const CHECK_NEW_ADDRESSES_TRANSACTIONS_HOOK = 'bh_wp_bitcoin_gateway_check_new_addresses_transactions';
28
29    /**
30     * Main class for carrying out the jobs.
31     *
32     * @var API_Interface
33     */
34    protected API_Interface $api;
35
36    /**
37     * Constructor
38     *
39     * @param API_Interface   $api Main plugin class.
40     * @param LoggerInterface $logger PSR logger.
41     */
42    public function __construct( API_Interface $api, LoggerInterface $logger ) {
43        $this->setLogger( $logger );
44        $this->api = $api;
45    }
46
47    /**
48     * Query a Blockchain API for updates to the order. If the order is still awaiting payment, schedule another job
49     * to check again soon.
50     *
51     * @hooked bh_wp_bitcoin_gateway_check_unpaid_order
52     * @see self::CHECK_UNPAID_ORDER_HOOK
53     *
54     * @param int $order_id WooCommerce order id to check.
55     */
56    public function check_unpaid_order( int $order_id ): void {
57
58        $context = array();
59
60        // How to find the action_id of the action currently being run?
61        $query = array(
62            'hook' => self::CHECK_UNPAID_ORDER_HOOK,
63            'args' => array( 'order_id' => $order_id ),
64        );
65
66        $context['query'] = $query;
67
68        $action_id = ActionScheduler::store()->query_action( $query );
69        $claim_id  = ActionScheduler::store()->get_claim_id( $action_id );
70
71        $context['order_id']  = $order_id;
72        $context['task']      = $query;
73        $context['action_id'] = $action_id;
74        $context['claim_id']  = $claim_id;
75
76        $this->logger->debug(
77            "Running check_unpaid_order background task for `shop_order:{$order_id}` action id: {$action_id}, claim id: {$claim_id}",
78            $context
79        );
80
81        $order = wc_get_order( $order_id );
82
83        if ( ! ( $order instanceof WC_Order ) ) {
84            $this->logger->error( 'Invalid order id ' . $order_id . ' passed to check_unpaid_order() background job', array( 'order_id' => $order_id ) );
85            return;
86        }
87
88        if ( in_array( $order->get_status(), wc_get_is_paid_statuses(), true ) ) {
89            $this->logger->info( "`shop_order:{$order_id}` already paid, status: {$order->get_status()}.", array( 'order_id' => $order_id ) );
90
91            add_action(
92                'action_scheduler_after_process_queue',
93                function () use ( $query, $action_id, $order ) {
94                    $this->logger->info( "Cancellilng future update checks for `shop_order:{$order->get_id()}`, status: {$order->get_status()}." );
95                    try {
96                        as_unschedule_all_actions( $query['hook'], $query['args'] );
97                    } catch ( \InvalidArgumentException $exception ) {
98                        $this->logger->error( "Failed to as_unschedule_all_actions for action {$action_id}", array( 'exception' => $exception ) );
99                    }
100                }
101            );
102            return;
103        }
104
105        try {
106            $result = $this->api->get_order_details( $order );
107        } catch ( Exception $exception ) {
108
109            // 403.
110            // TODO: Log better.
111            $this->logger->error( 'Error getting details for `shop_order:' . $order_id . '`', array( 'order_id' => $order_id ) );
112        }
113    }
114
115
116    /**
117     * When available addresses fall below a threshold, more are generated on a background job.
118     *
119     * @hooked bh_wp_bitcoin_gateway_generate_new_addresses
120     * @see self::GENERATE_NEW_ADDRESSES_HOOK
121     */
122    public function generate_new_addresses(): void {
123
124        $this->logger->debug( 'Starting generate_new_addresses() background job.' );
125
126        $result = $this->api->generate_new_addresses();
127    }
128
129
130    /**
131     * After new addresses have been created, we check to see are they fresh/available to use.
132     * TODO It's not unlikely we'll hit 429 rate limits during this, so we'll loop through as many as we can,
133     * then schedule a new job when we're told to stop.
134     *
135     * @hooked bh_wp_bitcoin_gateway_check_new_addresses_transactions
136     * @see self::CHECK_NEW_ADDRESSES_TRANSACTIONS_HOOK
137     */
138    public function check_new_addresses_for_transactions(): void {
139
140        $this->logger->debug( 'Starting check_new_addresses_for_transactions() background job.' );
141
142        $result = $this->api->check_new_addresses_for_transactions();
143    }
144}