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 / class-routeapp-admin-route-fee.php

class-routeapp-admin-route-fee.php in Route ‑ Shipping Protection 2.4.13, at includes/class-routeapp-admin-route-fee.php

347 lines 11.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 use Automattic\WooCommerce\Utilities\OrderUtil;
4
5 class Routeapp_Admin_Route_Fee {
6
7 const ROUTE_CHARGE_POST_META = '_routeapp_route_charge';
8 const ROUTE_PROTECTION_POST_META = '_routeapp_route_protection';
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
17 public function __construct()
18 {
19 if (!is_admin()) {
20 return false;
21 }
22 $this->init();
23 }
24
25 public function init()
26 {
27 add_action('woocommerce_order_item_add_action_buttons', array($this, 'routeapp_custom_admin_button'), 10, 1);
28 add_action('woocommerce_new_order_item', array($this, 'recalculate_route_fee'), 10, 1);
29 add_action('woocommerce_add_order_tax', array($this, 'recalculate_route_fee'), 10, 1);
30 add_action('woocommerce_saved_order_items', array($this, 'recalculate_route_fee'), 10, 1);
31 add_action('woocommerce_delete_order_item', array($this, 'recalculate_route_fee'), 10, 1);
32 }
33
34 public static function get_route_public_instance(){
35 global $routeapp_public;
36 return $routeapp_public;
37 }
38
39 public function routeapp_custom_admin_button($order)
40 {
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) {
108 return false;
109 }
110
111 if (array_key_exists($context['ref'], $this->admin_order_quote_cache)) {
112 return $this->admin_order_quote_cache[$context['ref']];
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;
125 }
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
153 private function routeapp_handle_admin_fee($order)
154 {
155 if (!$this->can_add_fee($order)) {
156 return false;
157 }
158 $routeapp_public = self::get_route_public_instance();
159 $route_insurance_quote = $this->fetch_admin_order_quote($order);
160
161 $route_insurance_amount = false;
162 if ($this->is_quote_eligible_for_customer_coverage($route_insurance_quote, $routeapp_public)) {
163 $route_insurance_amount = $route_insurance_quote->premium->amount;
164 }
165 if ($route_insurance_amount > 0) {
166 $this->routeapp_create_fee($order, $route_insurance_amount);
167 $order->calculate_totals();
168 if ($order->save()) {
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 }
192 return true;
193 }
194 } else {
195 if ($this->has_route_fee_applied($order)) {
196 $this->routeapp_remove_route_fee($order);
197 $order->calculate_totals();
198 $order->save();
199 }
200 }
201
202 return false;
203 }
204
205 private function routeapp_create_fee($order, $fee_amount) {
206 $routeapp_public = self::get_route_public_instance();
207 if (!$this->has_route_fee_applied($order)) {
208 $item_fee = new WC_Order_Item_Fee();
209 $item_fee->set_name( Routeapp_Public::ROUTE_LABEL );
210 $item_fee->set_tax_class( $routeapp_public->routeapp_get_taxable_class() );
211 $item_fee->set_tax_status( $routeapp_public->routeapp_get_fee_taxable() ? 'taxable' : 'none' );
212 $item_fee->set_amount( $fee_amount );
213 $item_fee->set_total( $fee_amount );
214 Routeapp_Public::routeapp_mark_protection_fee_item( $item_fee );
215 $order->add_item( $item_fee );
216 } else {
217 $fees = $this->get_route_fees($order);
218 foreach($fees as $fee_id => $fee) {
219 if ($fee) {
220 $fee->set_amount($fee_amount);
221 $fee->set_total($fee_amount);
222 Routeapp_Public::routeapp_mark_protection_fee_item( $fee );
223 $fee->save();
224 }
225 }
226 }
227 }
228
229 public function routeapp_add_admin_fee()
230 {
231 check_ajax_referer( 'order-item', 'security' );
232
233 if (!isset($_POST) || !$_POST['order_id']) {
234 wp_send_json_error('Missing order_id in the request.');
235 return;
236 }
237
238 $order_id = isset($_POST['order_id']) ? $_POST['order_id'] : 0;
239 $order = wc_get_order( $order_id );
240 if (!$order) {
241 wp_send_json_error('Invalid order_id.');
242 return;
243 }
244
245 $response = $this->routeapp_handle_admin_fee($order);
246
247 if ($response) {
248 wp_send_json_success( 'order updated!' );
249 return;
250 }
251
252 wp_send_json_error('error while adding route fee to the order');
253 }
254
255 function routeapp_remove_admin_fee()
256 {
257 check_ajax_referer( 'order-item', 'security' );
258
259 if (!isset($_POST) || !$_POST['order_id']) {
260 wp_send_json_error('Missing order_id in the request.');
261 return;
262 }
263
264 $order_id = isset($_POST['order_id']) ? $_POST['order_id'] : 0;
265 $order = wc_get_order( $order_id );
266 if (!$order) {
267 wp_send_json_error('Invalid order_id.');
268 return;
269 }
270
271 if ($this->has_route_fee_applied($order)) {
272 $this->routeapp_remove_route_fee($order);
273 $order->calculate_totals();
274 $order->save();
275 }
276
277 wp_send_json_success('route fee removed from the order');
278 }
279
280 private function routeapp_remove_route_fee($order)
281 {
282 $fees = $this->get_route_fees($order);
283
284 foreach($fees as $fee_id => $fee) {
285 if ($fee) {
286 wc_delete_order_item($fee_id);
287 }
288 }
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 }
298 }
299
300 public function recalculate_route_fee($order_id)
301 {
302 $order = wc_get_order( $order_id );
303
304 if ($this->has_route_fee_applied($order)) {
305 $this->routeapp_handle_admin_fee($order);
306 }
307 }
308
309 private function get_route_fees($order)
310 {
311 if (!$order) {
312 return [];
313 }
314
315 $fees = $order->get_fees();
316 $route_fees = [];
317 foreach($fees as $fee_id => $fee) {
318 if (Routeapp_Public::routeapp_is_route_protection_fee($fee)) {
319 $route_fees[$fee_id] = $fee;
320 }
321 }
322 return $route_fees;
323 }
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
333 public function can_add_fee($order)
334 {
335 return $this->can_show_route_fee_buttons($order);
336 }
337
338 private function has_route_fee_applied($order)
339 {
340 $routeFees = $this->get_route_fees($order);
341 if (is_array($routeFees) || $routeFees instanceof Countable) {
342 return count($routeFees) > 0;
343 }
344 return false;
345 }
346 }
347