Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
21.62% covered (danger)
21.62%
8 / 37
42.86% covered (danger)
42.86%
3 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
Order
21.62% covered (danger)
21.62%
8 / 37
42.86% covered (danger)
42.86%
3 / 7
139.26
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 check_address_on_single_order_processing
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 check_address_on_bulk_order_processing
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 add_admin_ui_order_action
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 check_address_on_admin_order_action
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 print_link_to_usps_tools_zip_lookup
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
12
 add_previous_address_to_order
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2/**
3 * When an order is paid, check its address.
4 * When an order is marked processing via the order list page bulk actions "Mark processing", check its address.
5 * Add a "Validate address" option on the order page's order actions
6 */
7
8namespace BrianHenryIE\WC_Address_Validation\WooCommerce;
9
10use BrianHenryIE\WC_Address_Validation\API_Interface;
11use BrianHenryIE\WC_Address_Validation\Settings_Interface;
12use BrianHenryIE\WC_Address_Validation\WP_Includes\Cron;
13use Psr\Log\LoggerAwareTrait;
14use Psr\Log\LoggerInterface;
15use WC_Order;
16
17/**
18 * Class Order
19 *
20 * @package BrianHenryIE\WC_Address_Validation\WooCommerce
21 */
22class Order {
23
24    use LoggerAwareTrait;
25
26    /**
27     * @var Settings_Interface
28     */
29    protected Settings_Interface $settings;
30
31    /**
32     * @var API_Interface
33     */
34    protected API_Interface $api;
35
36    /**
37     * Order constructor.
38     *
39     * @param API_Interface      $api
40     * @param Settings_Interface $settings
41     * @param LoggerInterface    $logger
42     */
43    public function __construct( API_Interface $api, Settings_Interface $settings, LoggerInterface $logger ) {
44
45        $this->setLogger( $logger );
46        $this->settings = $settings;
47        $this->api      = $api;
48    }
49
50    /**
51     * When an order is paid, validate the address.
52     *
53     * Runs when the order status has changed from an unpaid to a paid status.
54     *
55     * TODO: Do not run on bulk updates.
56     *
57     * @hooked woocommerce_order_status_changed
58     * @see WC_Order::status_transition()
59     *
60     * @param int    $order_id
61     * @param string $status_from
62     * @param string $status_to
63     */
64    public function check_address_on_single_order_processing( $order_id, $status_from, $status_to ): void {
65
66        // TODO: This is also running on the bulk update action... only one is needed.
67        // if ( isset( $_REQUEST['_wp_http_referer'] ) && '/wp-admin/edit.php?post_type=shop_order' === $_REQUEST['_wp_http_referer'] ) {
68        // return;
69        // }
70
71        if ( ! in_array( $status_from, wc_get_is_paid_statuses(), true ) && in_array( $status_to, wc_get_is_paid_statuses(), true ) ) {
72
73            $args = array( $order_id );
74
75            $this->logger->debug( 'Scheduling background process to check order ' . $order_id, array( 'order_id' => $order_id ) );
76
77            wp_schedule_single_event( time() - 60, Cron::CHECK_SINGLE_ADDRESS_CRON_JOB, $args );
78        }
79    }
80
81    /**
82     *
83     * This runs asynchronously.
84     *
85     * TODO: Maybe check nonce.
86     *
87     * @hooked admin_action_mark_processing
88     */
89    public function check_address_on_bulk_order_processing(): void {
90
91        // The bulk update should have an array of post (order) ids.
92        if ( ! isset( $_REQUEST['post'] ) || ! is_array( $_REQUEST['post'] ) ) {
93            return;
94        }
95
96        $order_ids = array_map( 'intval', $_REQUEST['post'] );
97
98        $args = array( $order_ids );
99
100        $this->logger->debug( 'Scheduling background process to check orders ' . implode( ', ', $order_ids ), array( 'order_ids' => $order_ids ) );
101
102        wp_schedule_single_event( time() - 60, Cron::CHECK_MULTIPLE_ADDRESSES_CRON_JOB, $args );
103    }
104
105    /**
106     * Add "Validate address" to order actions in admin UI order edit page.
107     *
108     * TODO: Do not add if settings are not configured!
109     *
110     * @hooked woocommerce_order_actions
111     * @see class-wc-meta-box-order-actions.php
112     *
113     * @param string[] $actions
114     * @return string[]
115     */
116    public function add_admin_ui_order_action( $actions ): array {
117
118        // global $order?
119
120        $actions['bh_wc_address_validate'] = __( 'Validate address', 'bh-wc-address-validation' );
121
122        return $actions;
123    }
124
125    /**
126     * This runs synchronously.
127     *
128     * @hooked woocommerce_order_action_bh_wc_address_validate
129     *
130     * @param WC_Order $order
131     */
132    public function check_address_on_admin_order_action( $order ): void {
133
134        $this->logger->debug( $order->get_id() . ' check address started from edit order page.', array( 'order_id' => $order->get_id() ) );
135
136        $is_manual = true;
137
138        $this->api->check_address_for_order( $order, $is_manual );
139
140        // TODO: Add admin notice.
141    }
142
143
144    /**
145     * On the single order admin UI screen, if the order status is bad-address, and it is a US order, show a link
146     * to the USPS Zip Code Lookup Tool.
147     *
148     * @see https://tools.usps.com/zip-code-lookup.htm?byaddress
149     *
150     * @hooked woocommerce_admin_order_data_after_shipping_address
151     * @see class-wc-meta-box-order-data.php
152     *
153     * @param WC_Order $order
154     */
155    public function print_link_to_usps_tools_zip_lookup( WC_Order $order ): void {
156
157        if ( Order_Status::BAD_ADDRESS_STATUS === $order->get_status() && 'US' === $order->get_shipping_country() ) {
158
159            echo '<a target="_blank" href="https://tools.usps.com/zip-code-lookup.htm?byaddress">USPS Zip Code Lookup Tool</a>';
160        }
161    }
162
163    /**
164     * Show "previous customer address" when possible for bad-address orders.
165     *
166     * When viewing a bad-address order, using the customer's past orders is useful to find the correct address.
167     *
168     * @hooked woocommerce_admin_order_data_after_shipping_address
169     * @see class-wc-meta-box-order-data.php
170     *
171     * @param WC_Order $order
172     */
173    public function add_previous_address_to_order( WC_Order $order ) {
174
175        if ( Order_Status::BAD_ADDRESS_STATUS !== $order->get_status() ) {
176            return;
177        }
178
179        // TODO: sort by most recent.
180        $customer_orders = wc_get_orders(
181            array(
182                'status'        => 'wc-completed',
183                'billing_email' => $order->get_billing_email(),
184                'limit'         => 1,
185            )
186        );
187
188        if ( 0 === count( $customer_orders ) ) {
189            echo '<p class="none_set" style="clear:both;"><strong>' . esc_html__( 'Previous Order\'s Address:', 'bh-wc-address-validation' ) . '</strong> ' . esc_html__( 'No previous order.', 'bh-wc-address-validation' ) . '</p>';
190            return;
191        }
192
193        $previous_order = array_pop( $customer_orders );
194
195        if ( $previous_order->get_formatted_shipping_address() ) {
196
197            echo '<p class="none_set" style="clear:both;"><strong>' . esc_html__( 'Previous Order\'s Address:', 'bh-wc-address-validation' ) . '</strong> ' . '</p>';
198
199            echo '<p>' . wp_kses( $previous_order->get_formatted_shipping_address(), array( 'br' => array() ) ) . '</p>';
200
201            echo '<p class="none_set">Order <a href="' . $previous_order->get_edit_order_url() . '">#' . $previous_order->get_id() . '</a>.' . '</p>';
202        }
203    }
204}