*/
private $admin_order_quote_cache = array();
public function __construct()
{
if (!is_admin()) {
return false;
}
$this->init();
}
public function init()
{
add_action('woocommerce_order_item_add_action_buttons', array($this, 'routeapp_custom_admin_button'), 10, 1);
add_action('woocommerce_new_order_item', array($this, 'recalculate_route_fee'), 10, 1);
add_action('woocommerce_add_order_tax', array($this, 'recalculate_route_fee'), 10, 1);
add_action('woocommerce_saved_order_items', array($this, 'recalculate_route_fee'), 10, 1);
add_action('woocommerce_delete_order_item', array($this, 'recalculate_route_fee'), 10, 1);
}
public static function get_route_public_instance(){
global $routeapp_public;
return $routeapp_public;
}
public function routeapp_custom_admin_button($order)
{
echo $this->get_route_fee_button_html($order);
}
public function get_route_fee_button_html($order)
{
if (!$this->can_show_route_fee_buttons($order)) {
return '';
}
if ($this->has_route_fee_applied($order)) {
return '';
}
if ($this->is_order_eligible_for_route_coverage($order)) {
return '';
}
return '';
}
public function routeapp_refresh_admin_fee_button()
{
check_ajax_referer( 'order-item', 'security' );
if (!isset($_POST['order_id'])) {
wp_send_json_error('Missing order_id in the request.');
return;
}
$order = wc_get_order(absint($_POST['order_id']));
if (!$order) {
wp_send_json_error('Invalid order_id.');
return;
}
wp_send_json_success(array(
'html' => $this->get_route_fee_button_html($order),
));
}
private function get_admin_order_cart_ref($order, $cart_total, $cart_items)
{
$items_hash = substr(md5(wp_json_encode($cart_items)), 0, 8);
return 'admin-' . $order->get_id() . '-' . $cart_total . '-' . $items_hash;
}
private function get_admin_order_quote_context($order)
{
$routeapp_public = self::get_route_public_instance();
$cart_total = round($routeapp_public->get_cart_subtotal_with_only_shippable_items($order, 'order'), 2);
$cart_items = $routeapp_public->get_cart_shippable_items($order, 'order');
return array(
'total' => $cart_total,
'items' => $cart_items,
'ref' => $this->get_admin_order_cart_ref($order, $cart_total, $cart_items),
'currency' => get_woocommerce_currency(),
'public' => $routeapp_public,
);
}
private function fetch_admin_order_quote($order)
{
$context = $this->get_admin_order_quote_context($order);
if ($context['total'] <= 0) {
return false;
}
if (array_key_exists($context['ref'], $this->admin_order_quote_cache)) {
return $this->admin_order_quote_cache[$context['ref']];
}
$quote = $context['public']->routeapp_get_quote_from_api(
$context['ref'],
$context['total'],
$context['currency'],
$context['items']
);
$this->admin_order_quote_cache[$context['ref']] = $quote;
return $quote;
}
public function is_order_eligible_for_route_coverage($order)
{
if (!$order) {
return false;
}
$routeapp_public = self::get_route_public_instance();
$route_insurance_quote = $this->fetch_admin_order_quote($order);
return $this->is_quote_eligible_for_customer_coverage($route_insurance_quote, $routeapp_public);
}
private function is_quote_eligible_for_customer_coverage($route_insurance_quote, $routeapp_public)
{
if (!$route_insurance_quote) {
return false;
}
if (!isset($route_insurance_quote->premium->amount) || $route_insurance_quote->premium->amount <= 0) {
return false;
}
return isset($route_insurance_quote->payment_responsible->type)
&& $route_insurance_quote->payment_responsible->type === $routeapp_public->get_allowed_quote_type();
}
private function routeapp_handle_admin_fee($order)
{
if (!$this->can_add_fee($order)) {
return false;
}
$routeapp_public = self::get_route_public_instance();
$route_insurance_quote = $this->fetch_admin_order_quote($order);
$route_insurance_amount = false;
if ($this->is_quote_eligible_for_customer_coverage($route_insurance_quote, $routeapp_public)) {
$route_insurance_amount = $route_insurance_quote->premium->amount;
}
if ($route_insurance_amount > 0) {
$this->routeapp_create_fee($order, $route_insurance_amount);
$order->calculate_totals();
if ($order->save()) {
$acceptedOrderStatuses = get_option('routeapp_included_order_statuses') ? get_option('routeapp_included_order_statuses') : [];
$acceptedCanceledStatuses = get_option('routeapp_cancel_order_statuses') ? get_option('routeapp_cancel_order_statuses') : [];
if ( class_exists('Automattic\WooCommerce\Utilities\OrderUtil')
&& OrderUtil::custom_orders_table_usage_is_enabled() ) {
// HPOS usage is enabled.
$order->update_meta_data(self::ROUTE_CHARGE_POST_META, $route_insurance_amount );
$order->update_meta_data(self::ROUTE_PROTECTION_POST_META, true );
$order->update_meta_data('_routeapp_included_order_statuses', json_encode($acceptedOrderStatuses));
$order->update_meta_data( '_routeapp_cancel_order_statuses', json_encode($acceptedCanceledStatuses));
$order->save();
} else {
// Traditional CPT-based orders are in use.
update_post_meta( $order->get_id(), self::ROUTE_CHARGE_POST_META, $route_insurance_amount );
update_post_meta( $order->get_id(), self::ROUTE_PROTECTION_POST_META, true );
update_post_meta( $order->get_id(), '_routeapp_included_order_statuses', json_encode($acceptedOrderStatuses));
update_post_meta( $order->get_id(), '_routeapp_cancel_order_statuses', json_encode($acceptedCanceledStatuses));
}
return true;
}
} else {
if ($this->has_route_fee_applied($order)) {
$this->routeapp_remove_route_fee($order);
$order->calculate_totals();
$order->save();
}
}
return false;
}
private function routeapp_create_fee($order, $fee_amount) {
$routeapp_public = self::get_route_public_instance();
if (!$this->has_route_fee_applied($order)) {
$item_fee = new WC_Order_Item_Fee();
$item_fee->set_name( Routeapp_Public::ROUTE_LABEL );
$item_fee->set_tax_class( $routeapp_public->routeapp_get_taxable_class() );
$item_fee->set_tax_status( $routeapp_public->routeapp_get_fee_taxable() ? 'taxable' : 'none' );
$item_fee->set_amount( $fee_amount );
$item_fee->set_total( $fee_amount );
Routeapp_Public::routeapp_mark_protection_fee_item( $item_fee );
$order->add_item( $item_fee );
} else {
$fees = $this->get_route_fees($order);
foreach($fees as $fee_id => $fee) {
if ($fee) {
$fee->set_amount($fee_amount);
$fee->set_total($fee_amount);
Routeapp_Public::routeapp_mark_protection_fee_item( $fee );
$fee->save();
}
}
}
}
public function routeapp_add_admin_fee()
{
check_ajax_referer( 'order-item', 'security' );
if (!isset($_POST) || !$_POST['order_id']) {
wp_send_json_error('Missing order_id in the request.');
return;
}
$order_id = isset($_POST['order_id']) ? $_POST['order_id'] : 0;
$order = wc_get_order( $order_id );
if (!$order) {
wp_send_json_error('Invalid order_id.');
return;
}
$response = $this->routeapp_handle_admin_fee($order);
if ($response) {
wp_send_json_success( 'order updated!' );
return;
}
wp_send_json_error('error while adding route fee to the order');
}
function routeapp_remove_admin_fee()
{
check_ajax_referer( 'order-item', 'security' );
if (!isset($_POST) || !$_POST['order_id']) {
wp_send_json_error('Missing order_id in the request.');
return;
}
$order_id = isset($_POST['order_id']) ? $_POST['order_id'] : 0;
$order = wc_get_order( $order_id );
if (!$order) {
wp_send_json_error('Invalid order_id.');
return;
}
if ($this->has_route_fee_applied($order)) {
$this->routeapp_remove_route_fee($order);
$order->calculate_totals();
$order->save();
}
wp_send_json_success('route fee removed from the order');
}
private function routeapp_remove_route_fee($order)
{
$fees = $this->get_route_fees($order);
foreach($fees as $fee_id => $fee) {
if ($fee) {
wc_delete_order_item($fee_id);
}
}
if ( class_exists('Automattic\WooCommerce\Utilities\OrderUtil')
&& OrderUtil::custom_orders_table_usage_is_enabled() ) {
$order->delete_meta_data(self::ROUTE_CHARGE_POST_META);
$order->delete_meta_data(self::ROUTE_PROTECTION_POST_META);
} else {
delete_post_meta( $order->get_id(), self::ROUTE_CHARGE_POST_META );
delete_post_meta( $order->get_id(), self::ROUTE_PROTECTION_POST_META );
}
}
public function recalculate_route_fee($order_id)
{
$order = wc_get_order( $order_id );
if ($this->has_route_fee_applied($order)) {
$this->routeapp_handle_admin_fee($order);
}
}
private function get_route_fees($order)
{
if (!$order) {
return [];
}
$fees = $order->get_fees();
$route_fees = [];
foreach($fees as $fee_id => $fee) {
if (Routeapp_Public::routeapp_is_route_protection_fee($fee)) {
$route_fees[$fee_id] = $fee;
}
}
return $route_fees;
}
public function can_show_route_fee_buttons($order)
{
return $order
&& count($order->get_items()) > 0
&& is_admin()
&& in_array($order->get_status(), array('pending', 'on-hold', 'auto-draft'), true);
}
public function can_add_fee($order)
{
return $this->can_show_route_fee_buttons($order);
}
private function has_route_fee_applied($order)
{
$routeFees = $this->get_route_fees($order);
if (is_array($routeFees) || $routeFees instanceof Countable) {
return count($routeFees) > 0;
}
return false;
}
}