PluginProbe
Route ‑ Shipping Protection / 2.4.13
Route ‑ Shipping Protection v2.4.13
2.4.19 2.4.18 2.4.17 2.4.16 2.4.15 2.4.14 2.4.13 2.4.12 2.4.11 2.4.10 2.4.9 2.4.8 2.4.7 2.4.6 2.4.5 2.4.4 2.4.3 2.4.2 2.2.4 2.2.5 2.2.6 2.2.8 2.2.9 2.3.0 2.3.1 All 153 releases
routeapp / includes / tracking-providers / class-routeapp-ups-shipping.php

class-routeapp-ups-shipping.php in Route ‑ Shipping Protection 2.4.13, at includes/tracking-providers/class-routeapp-ups-shipping.php

207 lines 7.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * WooCommerce UPS Shipping Method tracking provider integration.
5 *
6 * Reads UPS tracking numbers stored by the official WooCommerce UPS Shipping
7 * Method plugin under the `ups_shipment_ids` order meta key and syncs them
8 * with the Route API. Follows the meta-based pattern used by the USPS provider.
9 *
10 * @package Routeapp\TrackingProviders
11 * @since 2.4.2
12 */
13 class Routeapp_UPS_Shipping extends Routeapp_WooCommerce_Common_Tracking_Provider implements Routeapp_WooCommerce_Tracking_Provider {
14
15 /**
16 * Courier ID sent to the Route API for all shipments handled by this provider.
17 */
18 const COURIER_ID = 'ups';
19
20 /**
21 * Order meta key written by the WooCommerce UPS Shipping Method plugin.
22 */
23 const META_KEY = 'ups_shipment_ids';
24
25 /**
26 * Check if the WooCommerce UPS Shipping Method plugin is active.
27 *
28 * @return bool True if the UPS Shipping Method plugin is in active_plugins.
29 */
30 public function is_active() {
31 return in_array(
32 'ups-woocommerce-shipping/ups-woocommerce-shipping.php',
33 (array) get_option( 'active_plugins', array() )
34 );
35 }
36
37 /**
38 * Get the global Routeapp_Public instance.
39 *
40 * @return Routeapp_Public|null The public plugin instance or null.
41 */
42 public static function get_route_public_instance() {
43 global $routeapp_public;
44 return $routeapp_public;
45 }
46
47 /**
48 * Get shipping provider names for the tracking numbers on an order.
49 *
50 * Returns an associative array mapping each tracking number to the UPS
51 * courier ID. Returns false when the order has no UPS tracking numbers.
52 *
53 * @param int $order_id The WooCommerce order ID.
54 * @return array|false Associative array of [tracking_number => 'ups'] or false when empty.
55 */
56 public function get_shipping_provider_name( $order_id ) {
57 $tracking_numbers = $this->get_ups_tracking_numbers( $order_id );
58 if ( empty( $tracking_numbers ) ) {
59 return false;
60 }
61 $couriers_array = array();
62 foreach ( $tracking_numbers as $tracking_number ) {
63 $couriers_array[ $tracking_number ] = self::COURIER_ID;
64 }
65 return $couriers_array;
66 }
67
68 /**
69 * Get shipping info from UPS order meta for Route API shipment sync.
70 *
71 * @param int $order_id The WooCommerce order ID.
72 * @return array|false Array of shipping info arrays with source_order_id,
73 * source_product_ids, courier_id, and tracking_number,
74 * or false when the order has no UPS tracking numbers.
75 */
76 public function get_shipping_info( $order_id ) {
77 $tracking_numbers = $this->get_ups_tracking_numbers( $order_id );
78 if ( empty( $tracking_numbers ) ) {
79 return false;
80 }
81 $product_ids = $this->get_order_products( $order_id );
82 $shipping_info = array();
83 foreach ( $tracking_numbers as $tracking_number ) {
84 $shipping_info[] = array(
85 'source_order_id' => $order_id,
86 'source_product_ids' => $product_ids,
87 'courier_id' => self::COURIER_ID,
88 'tracking_number' => $tracking_number,
89 );
90 }
91 return $shipping_info;
92 }
93
94 /**
95 * Sync UPS tracking numbers with the Route API.
96 *
97 * Reads `ups_shipment_ids`, creates Route shipments for any new tracking
98 * numbers, and cancels shipments for tracking numbers that have been
99 * removed from the meta.
100 *
101 * @param int $order_id The WooCommerce order ID.
102 * @param object $routeapp The Route app instance with routeapp_api_client.
103 * @return void|false False on API error, void on success or no data.
104 */
105 public function update( $order_id, $routeapp ) {
106 $tracking_numbers = $this->get_ups_tracking_numbers( $order_id );
107 if ( empty( $tracking_numbers ) ) {
108 return;
109 }
110
111 $product_ids = $this->get_order_products( $order_id );
112 $existing_tracking_numbers = (array) explode(
113 self::SEPARATOR_PIPE,
114 $this->get_meta_data( $order_id, 'routeapp_shipment_tracking_number' )
115 );
116 $tracking_numbers_array = array();
117
118 foreach ( $tracking_numbers as $tracking_number ) {
119 $tracking_numbers_array[] = $tracking_number;
120 if ( in_array( $tracking_number, $existing_tracking_numbers ) ) {
121 continue;
122 }
123
124 $shipment_response = $routeapp->routeapp_api_client->get_shipment( $tracking_number, $order_id );
125
126 if ( ! is_wp_error( $shipment_response )
127 && isset( $shipment_response['response']['code'] )
128 && 200 === (int) $shipment_response['response']['code'] ) {
129 $body = json_decode( wp_remote_retrieve_body( $shipment_response ), true );
130 if ( isset( $body['status'] ) && 'Cancelled' !== $body['status'] ) {
131 continue;
132 }
133 }
134
135 $params = array(
136 'source_order_id' => $order_id,
137 'source_product_ids' => $product_ids,
138 'courier_id' => self::COURIER_ID,
139 );
140
141 $response = $routeapp->routeapp_api_client->create_shipment( $tracking_number, $params );
142
143 try {
144 if ( is_wp_error( $response ) ) {
145 throw new Exception( $response->get_error_message() );
146 }
147 } catch ( Exception $exception ) {
148 $routeapp_public = self::get_route_public_instance();
149 if ( $routeapp_public ) {
150 $params['tracking_id'] = $tracking_number;
151 $routeapp_public->routeapp_log(
152 $exception,
153 array( 'params' => $params, 'method' => 'POST', 'endpoint' => 'shipments' )
154 );
155 }
156 return false;
157 }
158 }
159
160 if ( '' !== $existing_tracking_numbers[0] && ! empty( $tracking_numbers_array ) ) {
161 foreach ( $existing_tracking_numbers as $existing_tracking_number ) {
162 if ( ! in_array( $existing_tracking_number, $tracking_numbers_array ) ) {
163 $routeapp->routeapp_cancel_tracking_order( $order_id, $existing_tracking_number, $product_ids );
164 }
165 }
166 }
167
168 $joined = implode( self::SEPARATOR_PIPE, $tracking_numbers_array );
169 if ( '' !== $joined ) {
170 $this->add_custom_post_meta( $order_id, $joined );
171 }
172 }
173
174 /**
175 * No-op — UPS tracking data is read from order meta, not order notes.
176 *
177 * @param int $order_id The WooCommerce order ID.
178 * @param object $route_app The Route app instance.
179 * @return void
180 */
181 public function parse_order_notes( $order_id, $route_app ) {
182 return;
183 }
184
185 /**
186 * Read and normalize UPS tracking numbers from order meta.
187 *
188 * Handles three storage formats since the WooCommerce UPS Shipping Method
189 * plugin can persist the value differently depending on HPOS state:
190 * a PHP array (most common), a serialized string, or a single plain string.
191 *
192 * @param int $order_id The WooCommerce order ID.
193 * @return array List of tracking number strings (may be empty).
194 */
195 private function get_ups_tracking_numbers( $order_id ) {
196 $raw = $this->get_meta_data( $order_id, self::META_KEY );
197 if ( is_array( $raw ) ) {
198 return array_values( array_filter( $raw ) );
199 }
200 $unserialized = maybe_unserialize( $raw );
201 if ( is_array( $unserialized ) ) {
202 return array_values( array_filter( $unserialized ) );
203 }
204 return ! empty( $raw ) ? array( $raw ) : array();
205 }
206 }
207