| @@ -62,12 +62,16 @@ | ||
| 62 | 62 | |
| 63 | 63 | $orders = $this->getOrdersBatch($batchSize, $offset, $recoverTo, $recoverFrom); |
| 64 | 64 | |
| 65 | 65 | if (!empty($orders)) { |
| 66 | - $this->processOrders($orders); | |
| 67 | - wp_send_json_success(array( | |
| 66 | + $process_result = $this->processOrders($orders); | |
| 67 | + $response = array( | |
| 68 | 68 | 'processed' => count($orders), |
| 69 | - )); | |
| 69 | + ); | |
| 70 | + if (!empty($process_result['tracking_warning'])) { | |
| 71 | + $response['tracking_warning'] = $process_result['tracking_warning']; | |
| 72 | + } | |
| 73 | + wp_send_json_success($response); | |
| 70 | 74 | } else { |
| 71 | 75 | wp_send_json_error(array( |
| 72 | 76 | 'message' => __('No more orders to process.', 'routeapp'), |
| 73 | 77 | )); |
| @@ -110,16 +114,110 @@ | ||
| 110 | 114 | } |
| 111 | 115 | |
| 112 | 116 | /** |
| 113 | 117 | * Processes the fetched orders by either updating order post meta or performing a massive order save operation. |
| 118 | + * Optionally syncs tracking/shipments when the Sync tracking numbers checkbox is enabled. | |
| 114 | 119 | * |
| 115 | 120 | * @param array $orders The fetched orders to be processed. |
| 121 | + * @return array{ | |
| 122 | + * tracking_warning?: string | |
| 123 | + * } | |
| 116 | 124 | */ |
| 117 | 125 | private function processOrders($orders) { |
| 118 | - if (isset($_POST['routeapp_order_recover_reconcile_backend'])) { | |
| 126 | + $result = array(); | |
| 127 | + | |
| 128 | + if (isset($_POST['routeapp_order_recover_reconcile_backend']) && $_POST['routeapp_order_recover_reconcile_backend']) { | |
| 119 | 129 | $this->updateOrderPostMeta($orders); |
| 120 | 130 | } else { |
| 121 | 131 | $this->massiveOrderSave($orders); |
| 132 | + } | |
| 133 | + | |
| 134 | + if (isset($_POST['routeapp_order_recover_sync_tracking']) && $_POST['routeapp_order_recover_sync_tracking']) { | |
| 135 | + $tracking_warning = $this->syncOrderTrackings($orders); | |
| 136 | + if ($tracking_warning) { | |
| 137 | + $result['tracking_warning'] = $tracking_warning; | |
| 138 | + } | |
| 139 | + } | |
| 140 | + | |
| 141 | + return $result; | |
| 142 | + } | |
| 143 | + | |
| 144 | + /** | |
| 145 | + * Force-sync tracking numbers / shipments to Route for the given orders. | |
| 146 | + * Clears local shipment sync flags first so providers re-check Route and | |
| 147 | + * create missing shipments, then runs the original provider update paths. | |
| 148 | + * | |
| 149 | + * @param array $orders Orders to sync tracking for. | |
| 150 | + * @return string|null Warning message when tracking sync could not run, otherwise null. | |
| 151 | + */ | |
| 152 | + private function syncOrderTrackings($orders) { | |
| 153 | + $routeapp = Routeapp_Cron_Schedules::get_route_public_instance(); | |
| 154 | + if (!$routeapp) { | |
| 155 | + $warning = __( 'Tracking sync skipped: Route App instance is unavailable. Confirm the plugin is active and configured.', 'routeapp' ); | |
| 156 | + error_log( '[routeapp] order_recover_sync_tracking: ' . $warning ); | |
| 157 | + return $warning; | |
| 158 | + } | |
| 159 | + | |
| 160 | + $shipment_tracking = new Routeapp_Shipment_Tracking(); | |
| 161 | + | |
| 162 | + foreach ($orders as $order) { | |
| 163 | + if (!$order) { | |
| 164 | + continue; | |
| 165 | + } | |
| 166 | + | |
| 167 | + $order_id = $order->get_id(); | |
| 168 | + | |
| 169 | + try { | |
| 170 | + $this->clearLocalShipmentSyncMeta($order); | |
| 171 | + $shipment_tracking->update($order_id, $routeapp); | |
| 172 | + $shipment_tracking->parse_order_notes($order_id, $routeapp); | |
| 173 | + } catch (Exception $exception) { | |
| 174 | + // Keep processing the rest of the batch if one order fails. | |
| 175 | + $routeapp->routeapp_log($exception, array( | |
| 176 | + 'endpoint' => 'order_recover_sync_tracking', | |
| 177 | + 'params' => array( | |
| 178 | + 'source_order_id' => $order_id, | |
| 179 | + ), | |
| 180 | + 'method' => 'POST', | |
| 181 | + )); | |
| 182 | + continue; | |
| 183 | + } | |
| 184 | + } | |
| 185 | + | |
| 186 | + return null; | |
| 187 | + } | |
| 188 | + | |
| 189 | + /** | |
| 190 | + * Remove local meta that marks shipment sync as already completed. | |
| 191 | + * Needed to force a resync when Woo meta says success but Route has no shipment. | |
| 192 | + * | |
| 193 | + * @param \WC_Order $order Order to clear. | |
| 194 | + * @return void | |
| 195 | + */ | |
| 196 | + private function clearLocalShipmentSyncMeta($order) { | |
| 197 | + $meta_keys = array( | |
| 198 | + 'routeapp_shipment_api_called', | |
| 199 | + 'routeapp_shipment_tracking_number', | |
| 200 | + 'routeapp_shipment_tracking_provider', | |
| 201 | + 'routeapp_shipment_cron_api_called', | |
| 202 | + ); | |
| 203 | + | |
| 204 | + if ( $this->is_hpos_enabled() ) { | |
| 205 | + $deleted = false; | |
| 206 | + foreach ( $meta_keys as $meta_key ) { | |
| 207 | + if ( $order->meta_exists( $meta_key ) ) { | |
| 208 | + $order->delete_meta_data( $meta_key ); | |
| 209 | + $deleted = true; | |
| 210 | + } | |
| 211 | + } | |
| 212 | + if ( $deleted ) { | |
| 213 | + $order->save(); | |
| 214 | + } | |
| 215 | + return; | |
| 216 | + } | |
| 217 | + | |
| 218 | + foreach ( $meta_keys as $meta_key ) { | |
| 219 | + delete_post_meta( $order->get_id(), $meta_key ); | |
| 122 | 220 | } |
| 123 | 221 | } |
| 124 | 222 | |
| 125 | 223 | /** |