PluginProbe
Route ‑ Shipping Protection / 2.4.18
Route ‑ Shipping Protection v2.4.18
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
← All changes | includes/class-routeapp-admin-route-fee.php +176 -40 2.2.4 → 2.4.18 View file →
@@ -1,11 +1,20 @@
1 1 <?php
2 2
3 +use Automattic\WooCommerce\Utilities\OrderUtil;
4 +
3 5 class Routeapp_Admin_Route_Fee {
4 6
5 7 const ROUTE_CHARGE_POST_META = '_routeapp_route_charge';
6 8 const ROUTE_PROTECTION_POST_META = '_routeapp_route_protection';
7 9
10 + /**
11 + * Per-request quote cache keyed by admin cart ref.
12 + *
13 + * @var array<string, object|false>
14 + */
15 + private $admin_order_quote_cache = array();
16 +
8 17 public function __construct()
9 18 {
10 19 if (!is_admin()) {
11 20 return false;
@@ -28,21 +37,120 @@
28 37 }
29 38
30 39 public function routeapp_custom_admin_button($order)
31 40 {
32 - if (!$this->can_add_fee($order)) {
41 + echo $this->get_route_fee_button_html($order);
42 + }
43 +
44 + public function get_route_fee_button_html($order)
45 + {
46 + if (!$this->can_show_route_fee_buttons($order)) {
47 + return '';
48 + }
49 +
50 + if ($this->has_route_fee_applied($order)) {
51 + return '<button type="button" id="remove-route-fee" class="button generate-items">' . esc_html__( 'Remove Route Fee', 'routeapp' ) . '</button>';
52 + }
53 +
54 + if ($this->is_order_eligible_for_route_coverage($order)) {
55 + return '<button type="button" id="add-route-fee" class="button generate-items">' . esc_html__( 'Add Route Fee', 'routeapp' ) . '</button>';
56 + }
57 +
58 + return '';
59 + }
60 +
61 + public function routeapp_refresh_admin_fee_button()
62 + {
63 + check_ajax_referer( 'order-item', 'security' );
64 +
65 + if (!isset($_POST['order_id'])) {
66 + wp_send_json_error('Missing order_id in the request.');
67 + return;
68 + }
69 +
70 + $order = wc_get_order(absint($_POST['order_id']));
71 + if (!$order) {
72 + wp_send_json_error('Invalid order_id.');
73 + return;
74 + }
75 +
76 + wp_send_json_success(array(
77 + 'html' => $this->get_route_fee_button_html($order),
78 + ));
79 + }
80 +
81 + private function get_admin_order_cart_ref($order, $cart_total, $cart_items)
82 + {
83 + $items_hash = substr(md5(wp_json_encode($cart_items)), 0, 8);
84 +
85 + return 'admin-' . $order->get_id() . '-' . $cart_total . '-' . $items_hash;
86 + }
87 +
88 + private function get_admin_order_quote_context($order)
89 + {
90 + $routeapp_public = self::get_route_public_instance();
91 + $cart_total = round($routeapp_public->get_cart_subtotal_with_only_shippable_items($order, 'order'), 2);
92 + $cart_items = $routeapp_public->get_cart_shippable_items($order, 'order');
93 +
94 + return array(
95 + 'total' => $cart_total,
96 + 'items' => $cart_items,
97 + 'ref' => $this->get_admin_order_cart_ref($order, $cart_total, $cart_items),
98 + 'currency' => get_woocommerce_currency(),
99 + 'public' => $routeapp_public,
100 + );
101 + }
102 +
103 + private function fetch_admin_order_quote($order)
104 + {
105 + $context = $this->get_admin_order_quote_context($order);
106 +
107 + if ($context['total'] <= 0) {
33 108 return false;
34 109 }
35 110
36 - if ( is_admin() && in_array($order->get_status(), ['pending', 'on-hold', 'auto-draft']) ) {
37 - if ($this->has_route_fee_applied($order)) {
38 - echo '<button type="button" id="remove-route-fee" class="button generate-items">' . __( 'Remove Route Fee') . '</button>';
39 - } else {
40 - echo '<button type="button" id="add-route-fee" class="button generate-items">' . __( 'Add Route Fee') . '</button>';
41 - }
111 + if (array_key_exists($context['ref'], $this->admin_order_quote_cache)) {
112 + return $this->admin_order_quote_cache[$context['ref']];
42 113 }
114 +
115 + $quote = $context['public']->routeapp_get_quote_from_api(
116 + $context['ref'],
117 + $context['total'],
118 + $context['currency'],
119 + $context['items']
120 + );
121 +
122 + $this->admin_order_quote_cache[$context['ref']] = $quote;
123 +
124 + return $quote;
43 125 }
44 126
127 + public function is_order_eligible_for_route_coverage($order)
128 + {
129 + if (!$order) {
130 + return false;
131 + }
132 +
133 + $routeapp_public = self::get_route_public_instance();
134 + $route_insurance_quote = $this->fetch_admin_order_quote($order);
135 +
136 + return $this->is_quote_eligible_for_customer_coverage($route_insurance_quote, $routeapp_public);
137 + }
138 +
139 + private function is_quote_eligible_for_customer_coverage($route_insurance_quote, $routeapp_public)
140 + {
141 + if (!$route_insurance_quote) {
142 + return false;
143 + }
144 +
145 + if (!isset($route_insurance_quote->premium->amount) || $route_insurance_quote->premium->amount <= 0) {
146 + return false;
147 + }
148 +
149 + return isset($route_insurance_quote->payment_responsible->type)
150 + && $route_insurance_quote->payment_responsible->type === $routeapp_public->get_allowed_quote_type();
151 + }
152 +
45 153 private function routeapp_handle_admin_fee($order)
46 154 {
47 155 if (!$this->can_add_fee($order)) {
48 156 return false;
@@ -47,19 +155,12 @@
47 155 if (!$this->can_add_fee($order)) {
48 156 return false;
49 157 }
50 158 $routeapp_public = self::get_route_public_instance();
51 - //order doesn't have a hash, we use time to auto-generate one
52 - $cartRef = time();
53 - $cartTotal = round($routeapp_public->get_cart_subtotal_with_only_shippable_items($order, 'order'), 2);
54 - $currency = get_woocommerce_currency();
55 - $cartItems = $routeapp_public->get_cart_shippable_items($order, 'order');
56 - $route_insurance_quote = $routeapp_public->routeapp_get_quote_from_api($cartRef, $cartTotal, $currency, $cartItems);
159 + $route_insurance_quote = $this->fetch_admin_order_quote($order);
57 160
58 161 $route_insurance_amount = false;
59 - //only add fee if the quote is covered by customer and has a valid amount
60 - if (isset($route_insurance_quote->premium->amount) &&
61 - (isset($route_insurance_quote->payment_responsible->type)) && $route_insurance_quote->payment_responsible->type==$routeapp_public->get_allowed_quote_type()) {
162 + if ($this->is_quote_eligible_for_customer_coverage($route_insurance_quote, $routeapp_public)) {
62 163 $route_insurance_amount = $route_insurance_quote->premium->amount;
63 164 }
64 165 if ($route_insurance_amount > 0) {
65 166 $this->routeapp_create_fee($order, $route_insurance_amount);
@@ -64,15 +165,38 @@
64 165 if ($route_insurance_amount > 0) {
65 166 $this->routeapp_create_fee($order, $route_insurance_amount);
66 167 $order->calculate_totals();
67 168 if ($order->save()) {
68 - update_post_meta( $order->get_id(), self::ROUTE_CHARGE_POST_META, $route_insurance_amount );
69 - update_post_meta( $order->get_id(), self::ROUTE_PROTECTION_POST_META, true );
169 +
170 + $acceptedOrderStatuses = get_option('routeapp_included_order_statuses') ? get_option('routeapp_included_order_statuses') : [];
171 + $acceptedCanceledStatuses = get_option('routeapp_cancel_order_statuses') ? get_option('routeapp_cancel_order_statuses') : [];
172 +
173 + if ( class_exists('Automattic\WooCommerce\Utilities\OrderUtil')
174 + && OrderUtil::custom_orders_table_usage_is_enabled() ) {
175 + // HPOS usage is enabled.
176 + $order->update_meta_data(self::ROUTE_CHARGE_POST_META, $route_insurance_amount );
177 + $order->update_meta_data(self::ROUTE_PROTECTION_POST_META, true );
178 +
179 + $order->update_meta_data('_routeapp_included_order_statuses', json_encode($acceptedOrderStatuses));
180 + $order->update_meta_data( '_routeapp_cancel_order_statuses', json_encode($acceptedCanceledStatuses));
181 +
182 + $order->save();
183 + } else {
184 + // Traditional CPT-based orders are in use.
185 + update_post_meta( $order->get_id(), self::ROUTE_CHARGE_POST_META, $route_insurance_amount );
186 + update_post_meta( $order->get_id(), self::ROUTE_PROTECTION_POST_META, true );
187 +
188 + update_post_meta( $order->get_id(), '_routeapp_included_order_statuses', json_encode($acceptedOrderStatuses));
189 + update_post_meta( $order->get_id(), '_routeapp_cancel_order_statuses', json_encode($acceptedCanceledStatuses));
190 +
191 + }
70 192 return true;
71 193 }
72 - }else {
194 + } else {
73 195 if ($this->has_route_fee_applied($order)) {
74 196 $this->routeapp_remove_route_fee($order);
197 + $order->calculate_totals();
198 + $order->save();
75 199 }
76 200 }
77 201
78 202 return false;
@@ -86,8 +210,9 @@
86 210 $item_fee->set_tax_class( $routeapp_public->routeapp_get_taxable_class() );
87 211 $item_fee->set_tax_status( $routeapp_public->routeapp_get_fee_taxable() ? 'taxable' : 'none' );
88 212 $item_fee->set_amount( $fee_amount );
89 213 $item_fee->set_total( $fee_amount );
214 + Routeapp_Public::routeapp_mark_protection_fee_item( $item_fee );
90 215 $order->add_item( $item_fee );
91 216 } else {
92 217 $fees = $this->get_route_fees($order);
93 218 foreach($fees as $fee_id => $fee) {
@@ -93,8 +218,9 @@
93 218 foreach($fees as $fee_id => $fee) {
94 219 if ($fee) {
95 220 $fee->set_amount($fee_amount);
96 221 $fee->set_total($fee_amount);
222 + Routeapp_Public::routeapp_mark_protection_fee_item( $fee );
97 223 $fee->save();
98 224 }
99 225 }
100 226 }
@@ -104,14 +230,18 @@
104 230 {
105 231 check_ajax_referer( 'order-item', 'security' );
106 232
107 233 if (!isset($_POST) || !$_POST['order_id']) {
108 - wp_send_json_error('its missing order id on the request');
234 + wp_send_json_error('Missing order_id in the request.');
109 235 return;
110 236 }
111 237
112 238 $order_id = isset($_POST['order_id']) ? $_POST['order_id'] : 0;
113 239 $order = wc_get_order( $order_id );
240 + if (!$order) {
241 + wp_send_json_error('Invalid order_id.');
242 + return;
243 + }
114 244
115 245 $response = $this->routeapp_handle_admin_fee($order);
116 246
117 247 if ($response) {
@@ -126,17 +256,23 @@
126 256 {
127 257 check_ajax_referer( 'order-item', 'security' );
128 258
129 259 if (!isset($_POST) || !$_POST['order_id']) {
130 - wp_send_json_error('its missing order id on the request');
260 + wp_send_json_error('Missing order_id in the request.');
131 261 return;
132 262 }
133 263
134 264 $order_id = isset($_POST['order_id']) ? $_POST['order_id'] : 0;
135 265 $order = wc_get_order( $order_id );
266 + if (!$order) {
267 + wp_send_json_error('Invalid order_id.');
268 + return;
269 + }
136 270
137 271 if ($this->has_route_fee_applied($order)) {
138 272 $this->routeapp_remove_route_fee($order);
273 + $order->calculate_totals();
274 + $order->save();
139 275 }
140 276
141 277 wp_send_json_success('route fee removed from the order');
142 278 }
@@ -149,10 +285,17 @@
149 285 if ($fee) {
150 286 wc_delete_order_item($fee_id);
151 287 }
152 288 }
153 - delete_post_meta( $order->get_id(), self::ROUTE_CHARGE_POST_META );
154 - delete_post_meta( $order->get_id(), self::ROUTE_PROTECTION_POST_META );
289 +
290 + if ( class_exists('Automattic\WooCommerce\Utilities\OrderUtil')
291 + && OrderUtil::custom_orders_table_usage_is_enabled() ) {
292 + $order->delete_meta_data(self::ROUTE_CHARGE_POST_META);
293 + $order->delete_meta_data(self::ROUTE_PROTECTION_POST_META);
294 + } else {
295 + delete_post_meta( $order->get_id(), self::ROUTE_CHARGE_POST_META );
296 + delete_post_meta( $order->get_id(), self::ROUTE_PROTECTION_POST_META );
297 + }
155 298 }
156 299
157 300 public function recalculate_route_fee($order_id)
158 301 {
@@ -162,23 +305,8 @@
162 305 $this->routeapp_handle_admin_fee($order);
163 306 }
164 307 }
165 308
166 - private function get_quote_from_api($order_total)
167 - {
168 - $response = Routeapp_API_Client::getInstance()->get_quote($order_total, get_woocommerce_currency());
169 -
170 - if (is_wp_error($response)) {
171 - return false;
172 - } else {
173 - if ($response['response']['code'] == 401) {
174 - return false;
175 - }
176 - $price_data = json_decode($response['body']);
177 - return $price_data;
178 - }
179 - }
180 -
181 309 private function get_route_fees($order)
182 310 {
183 311 if (!$order) {
184 312 return [];
@@ -186,9 +314,9 @@
186 314
187 315 $fees = $order->get_fees();
188 316 $route_fees = [];
189 317 foreach($fees as $fee_id => $fee) {
190 - if($fee['name'] == Routeapp_Public::ROUTE_LABEL) {
318 + if (Routeapp_Public::routeapp_is_route_protection_fee($fee)) {
191 319 $route_fees[$fee_id] = $fee;
192 320 }
193 321 }
194 322 return $route_fees;
@@ -193,11 +321,19 @@
193 321 }
194 322 return $route_fees;
195 323 }
196 324
325 + public function can_show_route_fee_buttons($order)
326 + {
327 + return $order
328 + && count($order->get_items()) > 0
329 + && is_admin()
330 + && in_array($order->get_status(), array('pending', 'on-hold', 'auto-draft'), true);
331 + }
332 +
197 333 public function can_add_fee($order)
198 334 {
199 - return $order && count($order->get_items()) > 0 && $order->get_status() == 'auto-draft';
335 + return $this->can_show_route_fee_buttons($order);
200 336 }
201 337
202 338 private function has_route_fee_applied($order)
203 339 {