- Sidebar-Menü „Bestellungen" in „Versand" umbenannt (layout-sidenav), sonst nur Blade-Formatierung. - Entwicklungspläne in ISO-Datumsformat umbenannt (entwicklungsplan-aktualisiert-*). - dev/dhl-for-woocommerce/ (DHL-Plugin) + dev/partnercenter-api.zip + PastedGraphic hinzugefügt. - .claude/ bewusst NICHT eingecheckt (lokale Claude-Code-Konfiguration). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1683 lines
65 KiB
PHP
1683 lines
65 KiB
PHP
<?php
|
|
use PR\DHL\Utils\API_Utils;
|
|
|
|
if (! defined('ABSPATH')) {
|
|
exit; // Exit if accessed directly
|
|
}
|
|
|
|
/**
|
|
* WooCommerce DHL Shipping Order.
|
|
*
|
|
* @category Shipping
|
|
*
|
|
* @author Shadi Manna
|
|
*/
|
|
if (! class_exists('PR_DHL_WC_Order')) {
|
|
|
|
abstract class PR_DHL_WC_Order
|
|
{
|
|
const DHL_DOWNLOAD_ENDPOINT = 'dhl_download_label';
|
|
|
|
protected $shipping_dhl_settings = [];
|
|
|
|
protected $service = 'DHL';
|
|
|
|
protected $carrier = '';
|
|
|
|
/**
|
|
* Init and hook in the integration.
|
|
*/
|
|
public function __construct()
|
|
{
|
|
$this->define_constants();
|
|
$this->init_hooks();
|
|
|
|
$this->shipping_dhl_settings = PR_DHL()->get_shipping_dhl_settings();
|
|
}
|
|
|
|
protected function define_constants() {}
|
|
|
|
public function init_hooks()
|
|
{
|
|
add_action('add_meta_boxes', [$this, 'add_meta_box'], 20, 2);
|
|
add_action('woocommerce_process_shop_order_meta', [$this, 'save_meta_box'], 0, 2);
|
|
|
|
// Order page metabox actions
|
|
add_action('wp_ajax_wc_shipment_dhl_gen_label', [$this, 'save_meta_box_ajax']);
|
|
add_action('wp_ajax_wc_shipment_dhl_delete_label', [$this, 'delete_label_ajax']);
|
|
|
|
// Prevent the DHL tracking number being copied from a subscription to its renewal and resubscribe orders.
|
|
// Detect the capability rather than a version number: the data copier (and the array-based
|
|
// wc_subscriptions_{type}_data filters) were introduced together in subscriptions-core 2.5.0.
|
|
if (class_exists('WC_Subscriptions_Data_Copier')) {
|
|
// subscriptions-core 2.5.0+: the data is passed as an array keyed by meta_key.
|
|
add_filter('wc_subscriptions_renewal_order_data', [$this, 'remove_dhl_tracking_meta'], 10);
|
|
add_filter('wc_subscriptions_resubscribe_order_data', [$this, 'remove_dhl_tracking_meta'], 10);
|
|
} elseif (class_exists('WC_Subscriptions')) {
|
|
// Older WooCommerce Subscriptions: the data is filtered as a SQL meta_query string.
|
|
add_filter('wcs_renewal_order_meta_query', [$this, 'remove_dhl_tracking_meta_query'], 10);
|
|
}
|
|
|
|
// add bulk actions to the Orders screen table bulk action drop-downs
|
|
add_action('admin_footer', [$this, 'add_order_bulk_actions']);
|
|
|
|
// process orders bulk actions
|
|
// add_action( 'load-edit.php', array( $this, 'process_orders_bulk_actions' ) );
|
|
// add_action( 'handle_bulk_actions-edit-shop_order', array( $this, 'process_orders_bulk_actions' ) );
|
|
add_filter('handle_bulk_actions-woocommerce_page_wc-orders', [$this, 'process_orders_bulk_actions'], 10, 3);
|
|
add_filter('handle_bulk_actions-edit-shop_order', [$this, 'process_orders_bulk_actions'], 10, 3);
|
|
|
|
// display admin notices for bulk actions
|
|
add_action('admin_notices', [$this, 'render_messages']);
|
|
|
|
add_action('init', [$this, 'add_download_label_endpoint']);
|
|
add_action('parse_query', [$this, 'process_download_label']);
|
|
|
|
// add {tracking_note} placeholder
|
|
add_filter('woocommerce_email_format_string', [$this, 'add_tracking_note_email_placeholder'], 10, 2);
|
|
|
|
add_shortcode('pr_dhl_tracking_note', [$this, 'tracking_note_shortcode']);
|
|
add_shortcode('pr_dhl_tracking_link', [$this, 'tracking_link_shortcode']);
|
|
}
|
|
|
|
/**
|
|
* Init order object for meta box.
|
|
*
|
|
* @param WP_POST|WC_Order $metabox_object Either WP_Post or WC_Order object.
|
|
*/
|
|
public function init_order_object($metabox_object)
|
|
{
|
|
if (is_a($metabox_object, 'WP_Post')) {
|
|
return wc_get_order($metabox_object->ID);
|
|
}
|
|
|
|
if (is_a($metabox_object, 'WC_Order')) {
|
|
return $metabox_object;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Add the meta box for shipment info on the order page
|
|
*/
|
|
public function add_meta_box($post_type, $post_or_order_object)
|
|
{
|
|
$order = $this->init_order_object($post_or_order_object);
|
|
|
|
if (! is_a($order, 'WC_Order') || ! API_Utils::order_needs_shipping($order)) {
|
|
return;
|
|
}
|
|
|
|
$screen = API_Utils::is_HPOS() ? wc_get_page_screen_id('shop-order') : 'shop_order';
|
|
add_meta_box(
|
|
'woocommerce-shipment-dhl-label',
|
|
/* translators: %s is the name of the service (e.g., DHL) */
|
|
sprintf(esc_html__('%s Label & Tracking', 'dhl-for-woocommerce'), $this->service),
|
|
[$this, 'meta_box'],
|
|
$screen,
|
|
'side',
|
|
'high'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Show the meta box for shipment info on the order page
|
|
*/
|
|
public function meta_box($post_or_order_object)
|
|
{
|
|
$order = $this->init_order_object($post_or_order_object);
|
|
$order_id = $order->get_id();
|
|
|
|
// Get saved label input fields or set default values
|
|
$dhl_label_items = $this->get_dhl_label_items($order_id);
|
|
|
|
// Get saved weight, otherwise calculate it from the item weights
|
|
if (! empty($dhl_label_items['pr_dhl_weight'])) {
|
|
$selected_weight_val = $dhl_label_items['pr_dhl_weight'];
|
|
} else {
|
|
$selected_weight_val = $this->calculate_order_weight($order_id);
|
|
}
|
|
|
|
// Get saved product, otherwise get the default product in settings
|
|
if (! empty($dhl_label_items['pr_dhl_product'])) {
|
|
$selected_dhl_product = $dhl_label_items['pr_dhl_product'];
|
|
} else {
|
|
$selected_dhl_product = $this->get_default_dhl_product($order_id);
|
|
}
|
|
|
|
// Get the list of domestic and international DHL services
|
|
try {
|
|
$dhl_obj = PR_DHL()->get_dhl_factory();
|
|
|
|
if ($this->is_shipping_domestic($order_id)) {
|
|
$dhl_product_list = $dhl_obj->get_dhl_products_domestic();
|
|
} else {
|
|
$dhl_product_list = $dhl_obj->get_dhl_products_international();
|
|
}
|
|
} catch (Exception $e) {
|
|
echo '<p class="wc_dhl_error">'.esc_html($e->getMessage()).'</p>';
|
|
}
|
|
|
|
$delete_label = '';
|
|
if ($this->can_delete_label($order_id)) {
|
|
$delete_label = '<span class="wc_dhl_delete"><a href="#" id="dhl_delete_label">'.esc_html__('Delete Label', 'dhl-for-woocommerce').'</a></span>';
|
|
}
|
|
|
|
$main_button = '<button id="dhl-label-button" class="button button-primary button-save-form">'.esc_html__('Generate Label', 'dhl-for-woocommerce').'</button>';
|
|
|
|
$return_label_button = '';
|
|
|
|
// Get tracking info if it exists
|
|
$label_tracking_info = $this->get_dhl_label_tracking($order_id);
|
|
// Check whether the label has already been created or not
|
|
if (empty($label_tracking_info)) {
|
|
$is_disabled = '';
|
|
|
|
$print_button = '<a href="#" id="dhl-label-print" class="button button-primary" download target="_blank">'.esc_html__('Download Label', 'dhl-for-woocommerce').'</a>';
|
|
|
|
} else {
|
|
$is_disabled = 'disabled';
|
|
|
|
$print_button = '<a href="'.$this->get_download_label_url($order_id).'" id="dhl-label-print" class="button button-primary" download target="_blank">'.esc_html__('Download Label', 'dhl-for-woocommerce').'</a>';
|
|
|
|
// Only show when the return label was saved as its own file (setting enabled + label has a return part).
|
|
if (! empty($label_tracking_info['return_label_path'])) {
|
|
$return_label_button = '<a href="'.esc_url($this->get_download_return_label_url($order_id)).'" id="dhl-return-label-print" class="dhl-return-label-link" download target="_blank">'.esc_html__('Download Return Label', 'dhl-for-woocommerce').'</a>';
|
|
}
|
|
}
|
|
|
|
$dhl_label_data = [
|
|
'main_button' => $main_button,
|
|
'delete_label' => $delete_label,
|
|
'print_button' => $print_button,
|
|
'return_label_button' => $return_label_button,
|
|
'return_label_text' => esc_html__('Download Return Label', 'dhl-for-woocommerce'),
|
|
];
|
|
|
|
echo '<div id="shipment-dhl-label-form">';
|
|
|
|
if (! empty($dhl_product_list)) {
|
|
|
|
woocommerce_wp_hidden_input(
|
|
[
|
|
'id' => 'pr_dhl_label_nonce',
|
|
'value' => wp_create_nonce('create-dhl-label'),
|
|
]
|
|
);
|
|
|
|
echo '<div class="shipment-dhl-row-container shipment-dhl-row-service">';
|
|
echo '<div class="shipment-dhl-icon-container"><span class="shipment-dhl-icon shipment-dhl-icon-service"></span> '.esc_html__('Service', 'dhl-for-woocommerce').'</div>';
|
|
woocommerce_wp_select(
|
|
[
|
|
'id' => 'pr_dhl_product',
|
|
'label' => esc_html__('Service selected:', 'dhl-for-woocommerce'),
|
|
'description' => '',
|
|
'value' => $selected_dhl_product,
|
|
'options' => $dhl_product_list,
|
|
'custom_attributes' => [$is_disabled => $is_disabled],
|
|
]
|
|
);
|
|
echo '</div>';
|
|
|
|
echo '<div class="shipment-dhl-row-container shipment-dhl-row-weight">';
|
|
|
|
$weight_units = get_option('woocommerce_weight_unit');
|
|
|
|
// Get weight UoM and add in label
|
|
echo '<div class="shipment-dhl-icon-container"><span class="shipment-dhl-icon shipment-dhl-icon-weight"></span> '.esc_html__('Weight', 'dhl-for-woocommerce').'</div>';
|
|
|
|
woocommerce_wp_text_input(
|
|
[
|
|
'id' => 'pr_dhl_weight',
|
|
/* translators: %s is the weight unit (e.g., kg or lbs) */
|
|
'label' => sprintf(esc_html__('Estimated shipment weight (%s) based on items ordered: ', 'dhl-for-woocommerce'), $weight_units),
|
|
'placeholder' => '',
|
|
'description' => '',
|
|
'value' => $selected_weight_val,
|
|
'custom_attributes' => [$is_disabled => $is_disabled],
|
|
'class' => 'wc_input_decimal', // adds JS to validate input is in price format
|
|
]
|
|
);
|
|
echo '</div>';
|
|
|
|
$this->additional_meta_box_fields($order_id, $is_disabled, $dhl_label_items, $dhl_obj);
|
|
|
|
// A label has been generated already, allow to delete
|
|
if (empty($label_tracking_info)) {
|
|
echo $main_button;
|
|
} else {
|
|
echo $print_button;
|
|
echo $return_label_button;
|
|
echo $delete_label;
|
|
}
|
|
|
|
wp_enqueue_script('wc-shipment-dhl-label-js', PR_DHL_PLUGIN_DIR_URL.'/assets/js/pr-dhl.js', ['jquery'], PR_DHL_VERSION);
|
|
wp_localize_script('wc-shipment-dhl-label-js', 'dhl_label_data', $dhl_label_data);
|
|
|
|
} else {
|
|
echo '<p class="wc_dhl_error">'.esc_html__('There are no DHL services available for the destination country!', 'dhl-for-woocommerce').'</p>';
|
|
}
|
|
|
|
echo '</div>';
|
|
}
|
|
|
|
protected function can_delete_label($order_id)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
abstract public function additional_meta_box_fields($order_id, $is_disabled, $dhl_label_items, $dhl_obj);
|
|
|
|
public function save_meta_box($post_id, $post = null)
|
|
{
|
|
|
|
$screen = function_exists('get_current_screen') ? get_current_screen() : null;
|
|
if (! empty($screen)) {
|
|
if (isset($screen->post_type) && $screen->post_type !== 'shop_order') {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (empty($_POST['pr_dhl_label_nonce'])) {
|
|
return;
|
|
}
|
|
|
|
$nonce = sanitize_text_field(wp_unslash($_POST['pr_dhl_label_nonce']));
|
|
|
|
if (! wp_verify_nonce($nonce, 'create-dhl-label')) {
|
|
return;
|
|
}
|
|
|
|
$meta_box_ids = ['pr_dhl_product', 'pr_dhl_weight'];
|
|
|
|
$additional_meta_box_ids = $this->get_additional_meta_ids();
|
|
if (is_array($additional_meta_box_ids) && ! empty($additional_meta_box_ids)) {
|
|
$meta_box_ids = array_merge($meta_box_ids, $additional_meta_box_ids);
|
|
}
|
|
|
|
$args = [];
|
|
|
|
foreach ($meta_box_ids as $value) {
|
|
if (isset($_POST[$value])) {
|
|
$args[$value] = wc_clean($_POST[$value]);
|
|
}
|
|
}
|
|
|
|
if (! empty($args)) {
|
|
$this->save_dhl_label_items($post_id, $args);
|
|
|
|
return $args;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete label in process
|
|
*
|
|
* @param int $order_id ID of the order object.
|
|
* @return string.
|
|
*/
|
|
public function processing_delete_label($order_id)
|
|
{
|
|
$args = $this->delete_label_args($order_id);
|
|
|
|
// If no tracking number, just continue. We cannot delete the tracking.
|
|
if (empty($args['tracking_number'])) {
|
|
return '';
|
|
}
|
|
|
|
$dhl_obj = PR_DHL()->get_dhl_factory();
|
|
|
|
// Delete meta data first in case there is an error with the API call.
|
|
$this->delete_dhl_label_tracking($order_id);
|
|
|
|
if (is_array($args['tracking_number'])) {
|
|
foreach ($args['tracking_number'] as $tracking_number) {
|
|
$del_label_args = $args;
|
|
$del_label_args['tracking_number'] = $tracking_number;
|
|
$dhl_obj->delete_dhl_label($del_label_args);
|
|
}
|
|
} else {
|
|
$dhl_obj->delete_dhl_label($args);
|
|
}
|
|
|
|
$tracking_number_to_delete_note = is_array($args['tracking_number']) ? $args['tracking_number'][0] : $args['tracking_number'];
|
|
|
|
return $tracking_number_to_delete_note;
|
|
}
|
|
|
|
abstract public function get_additional_meta_ids();
|
|
|
|
/**
|
|
* Order Tracking Save AJAX
|
|
*
|
|
* Function for saving tracking items
|
|
*/
|
|
public function save_meta_box_ajax()
|
|
{
|
|
check_ajax_referer('create-dhl-label', 'pr_dhl_label_nonce');
|
|
$order_id = wc_clean($_POST['order_id']);
|
|
|
|
// Save inputted data first
|
|
$this->save_meta_box($order_id);
|
|
|
|
try {
|
|
|
|
// Gather args for DHL API call
|
|
$args = $this->get_label_args($order_id);
|
|
|
|
// Allow third parties to modify the args to the DHL APIs
|
|
$args = apply_filters('pr_shipping_dhl_label_args', $args, $order_id);
|
|
|
|
$dhl_obj = PR_DHL()->get_dhl_factory();
|
|
$label_tracking_info = $dhl_obj->get_dhl_label($args);
|
|
|
|
$this->save_dhl_label_tracking($order_id, $label_tracking_info);
|
|
$tracking_note = $this->get_tracking_note($order_id);
|
|
$tracking_note_type = $this->get_tracking_note_type();
|
|
$label_url = $this->get_download_label_url($order_id);
|
|
|
|
do_action('pr_shipping_dhl_label_created', $order_id);
|
|
|
|
wp_send_json(
|
|
[
|
|
'download_msg' => esc_html__('Your DHL label is ready to download, click the "Download Label" button above"', 'dhl-for-woocommerce'),
|
|
'button_txt' => esc_html__('Download Label', 'dhl-for-woocommerce'),
|
|
'label_url' => $label_url,
|
|
'return_label_url' => $this->get_download_return_label_url($order_id),
|
|
'tracking_note' => $tracking_note,
|
|
'tracking_note_type' => $tracking_note_type,
|
|
]
|
|
);
|
|
|
|
} catch (Exception $e) {
|
|
|
|
wp_send_json(['error' => $e->getMessage()]);
|
|
}
|
|
|
|
wp_die();
|
|
}
|
|
|
|
public function delete_label_ajax()
|
|
{
|
|
check_ajax_referer('create-dhl-label', 'pr_dhl_label_nonce');
|
|
$order_id = wc_clean($_POST['order_id']);
|
|
|
|
try {
|
|
|
|
$tracking_num = $this->processing_delete_label($order_id);
|
|
|
|
if (empty($tracking_num)) {
|
|
throw new Exception(esc_html__('There are no tracking number to delete.', 'dhl-for-woocommerce'));
|
|
}
|
|
|
|
wp_send_json(
|
|
[
|
|
'download_msg' => esc_html__('Your DHL label is ready to download, click the "Download Label" button above"', 'dhl-for-woocommerce'),
|
|
'button_txt' => esc_html__('Generate Label', 'dhl-for-woocommerce'),
|
|
'dhl_tracking_num' => $tracking_num,
|
|
]
|
|
);
|
|
|
|
} catch (Exception $e) {
|
|
|
|
wp_send_json(['error' => $e->getMessage()]);
|
|
}
|
|
}
|
|
|
|
protected function get_download_label_url($order_id)
|
|
{
|
|
|
|
if (empty($order_id)) {
|
|
return '';
|
|
}
|
|
|
|
$label_tracking_info = $this->get_dhl_label_tracking($order_id);
|
|
// Check whether the label has already been created or not
|
|
if (empty($label_tracking_info)) {
|
|
return '';
|
|
}
|
|
|
|
// If no 'label_path' isset but a 'label_url' is set them return it...
|
|
// ... this indicates an old download style label!
|
|
if (! isset($label_tracking_info['label_path']) && isset($label_tracking_info['label_url'])) {
|
|
return $label_tracking_info['label_url'];
|
|
}
|
|
|
|
// Override URL with our solution's download label endpoint:
|
|
return $this->generate_download_url('/'.self::DHL_DOWNLOAD_ENDPOINT.'/'.$order_id);
|
|
}
|
|
|
|
/**
|
|
* Builds the download URL for the separate return label, if one was saved.
|
|
*
|
|
* @param int $order_id The order ID.
|
|
* @return string The download URL, or an empty string when no separate return label exists.
|
|
*/
|
|
protected function get_download_return_label_url($order_id)
|
|
{
|
|
|
|
if (empty($order_id)) {
|
|
return '';
|
|
}
|
|
|
|
$label_tracking_info = $this->get_dhl_label_tracking($order_id);
|
|
// Only build the URL when a separate return label file exists.
|
|
if (empty($label_tracking_info['return_label_path'])) {
|
|
return '';
|
|
}
|
|
|
|
return add_query_arg(
|
|
'dhl_label_type',
|
|
'return',
|
|
$this->generate_download_url('/'.self::DHL_DOWNLOAD_ENDPOINT.'/'.$order_id)
|
|
);
|
|
}
|
|
|
|
protected function get_tracking_note($order_id)
|
|
{
|
|
|
|
if (! empty($this->shipping_dhl_settings['dhl_tracking_note_txt'])) {
|
|
$tracking_note = $this->shipping_dhl_settings['dhl_tracking_note_txt'];
|
|
} else {
|
|
/* translators: %s is the tracking link */
|
|
$tracking_note = sprintf(esc_html__('%s Tracking Number: {tracking-link}', 'dhl-for-woocommerce'), $this->service);
|
|
}
|
|
|
|
$tracking_link = $this->get_tracking_link($order_id);
|
|
|
|
if (empty($tracking_link)) {
|
|
return '';
|
|
}
|
|
|
|
$tracking_note_new = str_replace('{tracking-link}', $tracking_link, $tracking_note, $count);
|
|
|
|
if ($count == 0) {
|
|
$tracking_note_new = $tracking_note.' '.$tracking_link;
|
|
}
|
|
|
|
$return_label_number = $this->get_return_label_number($order_id);
|
|
if ($return_label_number) {
|
|
if (is_array($return_label_number)) {
|
|
$return_label_number = implode(', ', $return_label_number);
|
|
}
|
|
|
|
/* translators: %s is the return label number */
|
|
$tracking_note_return_label = sprintf(esc_html__("\n Return Label Number: %s", 'dhl-for-woocommerce'), $return_label_number);
|
|
$tracking_note_new = $tracking_note_new.$tracking_note_return_label;
|
|
}
|
|
|
|
return $tracking_note_new;
|
|
}
|
|
|
|
protected function get_tracking_link($order_id)
|
|
{
|
|
|
|
$label_tracking_info = $this->get_dhl_label_tracking($order_id);
|
|
if (empty($label_tracking_info['tracking_number'])) {
|
|
return '';
|
|
}
|
|
|
|
return sprintf(
|
|
/* translators: %1$s is the base tracking URL, %2$s is the tracking number, %3$s is the tracking number displayed as link text */
|
|
'<a href="%1$s%2$s" target="_blank">%3$s</a>',
|
|
esc_url($this->get_tracking_url()),
|
|
esc_html($label_tracking_info['tracking_number']),
|
|
esc_html($label_tracking_info['tracking_number'])
|
|
);
|
|
}
|
|
|
|
protected function get_return_label_number($order_id)
|
|
{
|
|
|
|
$label_tracking_info = $this->get_dhl_label_tracking($order_id);
|
|
if (empty($label_tracking_info['return_label_number'])) {
|
|
return '';
|
|
}
|
|
|
|
return $label_tracking_info['return_label_number'];
|
|
}
|
|
|
|
abstract protected function get_tracking_url();
|
|
|
|
protected function get_tracking_note_type()
|
|
{
|
|
if (isset($this->shipping_dhl_settings['dhl_tracking_note']) && ($this->shipping_dhl_settings['dhl_tracking_note'] == 'yes')) {
|
|
return '';
|
|
} else {
|
|
return 'customer';
|
|
}
|
|
}
|
|
|
|
public function add_tracking_note_email_placeholder($string, $email)
|
|
{
|
|
|
|
$placeholder = '{pr_dhl_tracking_note}'; // The corresponding placeholder to be used
|
|
|
|
$order = $email->object; // Get the instance of the WC_Order Object
|
|
|
|
// Ensure the object is an order and not another type
|
|
if (! ($order instanceof WC_Order)) {
|
|
return $string;
|
|
}
|
|
|
|
$tracking_note = $this->get_tracking_note($order->get_id());
|
|
|
|
// Return the clean replacement tracking_note string for "{tracking_note}" placeholder
|
|
return str_replace($placeholder, $tracking_note, $string);
|
|
}
|
|
|
|
public function tracking_note_shortcode($atts, $content)
|
|
{
|
|
|
|
extract(
|
|
shortcode_atts(
|
|
[
|
|
'order_id' => '',
|
|
],
|
|
$atts
|
|
)
|
|
);
|
|
|
|
if ($order = wc_get_order($order_id)) {
|
|
|
|
return $this->get_tracking_note($order->get_id());
|
|
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
public function tracking_link_shortcode($atts, $content)
|
|
{
|
|
|
|
extract(
|
|
shortcode_atts(
|
|
[
|
|
'order_id' => '',
|
|
],
|
|
$atts
|
|
)
|
|
);
|
|
|
|
if ($order = wc_get_order($order_id)) {
|
|
|
|
return $this->get_tracking_link($order->get_id());
|
|
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Saves the tracking items array to post_meta.
|
|
*
|
|
* @param int $order_id Order ID
|
|
* @param array $tracking_items List of tracking item
|
|
* @return void
|
|
*/
|
|
public function save_dhl_label_tracking($order_id, $tracking_items)
|
|
{
|
|
|
|
if (isset($tracking_items['label_path']) && validate_file($tracking_items['label_path']) === 2) {
|
|
$tracking_items['label_path'] = wp_slash($tracking_items['label_path']);
|
|
}
|
|
|
|
// Protect the return label path's backslashes on Windows the same way as the label path.
|
|
if (isset($tracking_items['return_label_path']) && validate_file($tracking_items['return_label_path']) === 2) {
|
|
$tracking_items['return_label_path'] = wp_slash($tracking_items['return_label_path']);
|
|
}
|
|
|
|
$order = wc_get_order($order_id);
|
|
$order->update_meta_data('_pr_shipment_dhl_label_tracking', $tracking_items);
|
|
$order->save_meta_data();
|
|
|
|
$tracking_numbers = is_array($tracking_items['tracking_number']) ? $tracking_items['tracking_number'] : [$tracking_items['tracking_number']];
|
|
$ship_date = gmdate('Y-m-d', time());
|
|
|
|
foreach ($tracking_numbers as $tracking_number) {
|
|
if (empty($tracking_number)) {
|
|
continue;
|
|
}
|
|
|
|
$tracking_details = [
|
|
'carrier' => $this->carrier,
|
|
'tracking_number' => $tracking_number,
|
|
'ship_date' => $ship_date,
|
|
'tracking_url' => $this->get_tracking_url().$tracking_number,
|
|
];
|
|
|
|
// Primarily added for "Advanced Tracking" plugin integration.
|
|
// Will be triggered for each ( Label ) tracking number.
|
|
do_action('pr_save_dhl_label_tracking', $order_id, $tracking_details);
|
|
|
|
// Add support for "WooCommerce Shipment Tracking" plugin.
|
|
if (function_exists('wc_st_add_tracking_number')) {
|
|
wc_st_add_tracking_number(
|
|
$order_id,
|
|
$tracking_details['tracking_number'],
|
|
$tracking_details['carrier'],
|
|
time(),
|
|
$tracking_details['tracking_url']
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets all tracking items from the post meta array for an order.
|
|
*
|
|
* @param int $order_id Order ID
|
|
* @return array Tracking items
|
|
*/
|
|
public function get_dhl_label_tracking($order_id)
|
|
{
|
|
$order = wc_get_order($order_id);
|
|
|
|
if (! is_a($order, 'WC_Order')) {
|
|
return [];
|
|
}
|
|
|
|
$label_tracking = $order->get_meta('_pr_shipment_dhl_label_tracking');
|
|
|
|
return is_array($label_tracking) ? $label_tracking : [];
|
|
}
|
|
|
|
/**
|
|
* Delete the tracking items array to post_meta.
|
|
*
|
|
* @param int $order_id Order ID
|
|
* @return void
|
|
*/
|
|
public function delete_dhl_label_tracking($order_id)
|
|
{
|
|
$order = wc_get_order($order_id);
|
|
$order->delete_meta_data('_pr_shipment_dhl_label_tracking');
|
|
$order->save();
|
|
do_action('pr_delete_dhl_label_tracking', $order_id);
|
|
}
|
|
|
|
/**
|
|
* Saves the label items array to post_meta.
|
|
*
|
|
* @param int $order_id Order ID
|
|
* @param array $tracking_items List of tracking item
|
|
* @return void
|
|
*/
|
|
public function save_dhl_label_items($order_id, $tracking_items)
|
|
{
|
|
$order = wc_get_order($order_id);
|
|
|
|
$dhl_label_items = $order->get_meta('_pr_shipment_dhl_label_items');
|
|
|
|
if (is_array($dhl_label_items)) {
|
|
$dhl_label_items = array_merge($dhl_label_items, $tracking_items);
|
|
} else {
|
|
$dhl_label_items = $tracking_items;
|
|
}
|
|
|
|
$order->update_meta_data('_pr_shipment_dhl_label_items', $dhl_label_items);
|
|
$order->save();
|
|
}
|
|
|
|
/*
|
|
* Gets all label items fron the post meta array for an order
|
|
*
|
|
* @param int $order_id Order ID
|
|
*
|
|
* @return label items
|
|
*/
|
|
public function get_dhl_label_items($order_id)
|
|
{
|
|
$order = wc_get_order($order_id);
|
|
|
|
if (! is_a($order, 'WC_Order')) {
|
|
return [];
|
|
}
|
|
|
|
return $order->get_meta('_pr_shipment_dhl_label_items');
|
|
}
|
|
|
|
/*
|
|
* Save default fields, used by bulk create label
|
|
*
|
|
* @param int $order_id Order ID
|
|
*
|
|
* @return default label items
|
|
*/
|
|
protected function save_default_dhl_label_items($order_id)
|
|
{
|
|
$dhl_label_items = $this->get_dhl_label_items($order_id);
|
|
|
|
if (empty($dhl_label_items)) {
|
|
$dhl_label_items = [];
|
|
}
|
|
|
|
if (empty($dhl_label_items['pr_dhl_weight'])) {
|
|
// Set default weight
|
|
$dhl_label_items['pr_dhl_weight'] = $this->calculate_order_weight($order_id);
|
|
}
|
|
|
|
if (empty($dhl_label_items['pr_dhl_product'])) {
|
|
// Set default DHL product
|
|
$dhl_label_items['pr_dhl_product'] = $this->get_default_dhl_product($order_id);
|
|
}
|
|
|
|
// Save default items
|
|
$this->save_dhl_label_items($order_id, $dhl_label_items);
|
|
}
|
|
|
|
protected function get_default_dhl_product($order_id)
|
|
{
|
|
// $this->shipping_dhl_settings = PR_DHL()->get_shipping_dhl_settings();
|
|
if ($this->is_shipping_domestic($order_id)) {
|
|
return $this->shipping_dhl_settings['dhl_default_product_dom'];
|
|
} else {
|
|
return $this->shipping_dhl_settings['dhl_default_product_int'];
|
|
}
|
|
}
|
|
|
|
protected function calculate_order_weight($order_id)
|
|
{
|
|
|
|
$total_weight = 0;
|
|
$order = wc_get_order($order_id);
|
|
|
|
if ($order === false) {
|
|
return apply_filters('pr_shipping_dhl_order_weight', $total_weight, $order_id);
|
|
}
|
|
|
|
$ordered_items = $order->get_items();
|
|
|
|
if (is_array($ordered_items) && count($ordered_items) > 0) {
|
|
|
|
foreach ($ordered_items as $key => $item) {
|
|
|
|
if (! empty($item['variation_id'])) {
|
|
$product = wc_get_product($item['variation_id']);
|
|
} else {
|
|
$product = wc_get_product($item['product_id']);
|
|
}
|
|
|
|
if ($product) {
|
|
$product_weight = $product->get_weight();
|
|
if ($product_weight) {
|
|
$total_weight += ($item['qty'] * $product_weight);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (! empty($this->shipping_dhl_settings['dhl_add_weight'])) {
|
|
|
|
if ($this->shipping_dhl_settings['dhl_add_weight_type'] == 'absolute') {
|
|
$total_weight += wc_format_decimal($this->shipping_dhl_settings['dhl_add_weight']);
|
|
} elseif ($this->shipping_dhl_settings['dhl_add_weight_type'] == 'percentage') {
|
|
$total_weight += $total_weight * ($this->shipping_dhl_settings['dhl_add_weight'] / 100);
|
|
}
|
|
}
|
|
|
|
return apply_filters('pr_shipping_dhl_order_weight', $total_weight, $order_id);
|
|
}
|
|
|
|
protected function is_shipping_domestic($order_id)
|
|
{
|
|
$order = wc_get_order($order_id);
|
|
$shipping_address = $order->get_address('shipping');
|
|
$shipping_country = $shipping_address['country'];
|
|
|
|
if (PR_DHL()->is_shipping_domestic($shipping_country)) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
protected function is_crossborder_shipment($order_id)
|
|
{
|
|
$order = wc_get_order($order_id);
|
|
$shipping_address = $order->get_address('shipping');
|
|
|
|
if (PR_DHL()->is_crossborder_shipment($shipping_address)) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// This function gathers all of the data from WC to send to DHL API
|
|
protected function get_label_args($order_id)
|
|
{
|
|
|
|
$dhl_label_items = $this->get_dhl_label_items($order_id);
|
|
|
|
// Get settings from child implementation
|
|
$args = $this->get_label_args_settings($order_id, $dhl_label_items);
|
|
|
|
$order = wc_get_order($order_id);
|
|
// Get DHL service product
|
|
$args['order_details']['dhl_product'] = $dhl_label_items['pr_dhl_product'];
|
|
// $args['order_details']['duties'] = $dhl_label_items['shipping_dhl_duties'];
|
|
$args['order_details']['weight'] = $dhl_label_items['pr_dhl_weight'];
|
|
|
|
// Get WC specific details; order id, currency, units of measure, COD amount (if COD used)
|
|
$args['order_details']['order_id'] = $order_id;
|
|
// $args['order_details']['currency'] = get_woocommerce_currency();
|
|
$args['order_details']['currency'] = $this->get_wc_currency($order_id);
|
|
$weight_units = get_option('woocommerce_weight_unit');
|
|
|
|
switch ($weight_units) {
|
|
case 'lbs':
|
|
$args['order_details']['weightUom'] = 'lb';
|
|
break;
|
|
default:
|
|
$args['order_details']['weightUom'] = $weight_units;
|
|
break;
|
|
}
|
|
|
|
$args['order_details']['dimUom'] = get_option('woocommerce_dimension_unit');
|
|
|
|
if ($this->is_cod_payment_method($order_id) && empty($args['order_details']['cod_value'])) {
|
|
$args['order_details']['cod_value'] = $order->get_total();
|
|
}
|
|
|
|
// calculate the additional fee
|
|
$additional_fees = 0;
|
|
if (count($order->get_fees()) > 0) {
|
|
foreach ($order->get_fees() as $fee) {
|
|
$additional_fees += floatval($fee->get_total());
|
|
}
|
|
}
|
|
|
|
$args['order_details']['additional_fee'] = $additional_fees;
|
|
$args['order_details']['shipping_fee'] = $order->get_shipping_total();
|
|
$args['order_details']['total_value'] = $order->get_total();
|
|
|
|
// Get address related information
|
|
$billing_address = $order->get_address();
|
|
$shipping_address = $order->get_address('shipping');
|
|
|
|
// If shipping phone number doesn't exist, try to get billing phone number
|
|
if (empty($shipping_address['phone']) && ! empty($billing_address['phone'])) {
|
|
$shipping_address['phone'] = $billing_address['phone'];
|
|
}
|
|
|
|
// If shipping email doesn't exist, try to get billing email
|
|
if (empty($shipping_address['email']) && ! empty($billing_address['email'])) {
|
|
$shipping_address['email'] = $billing_address['email'];
|
|
}
|
|
|
|
// Merge first and last name into "name"
|
|
$shipping_address['name'] = '';
|
|
if (isset($shipping_address['first_name'])) {
|
|
$shipping_address['name'] = $shipping_address['first_name'];
|
|
// unset( $shipping_address['first_name'] );
|
|
}
|
|
|
|
if (isset($shipping_address['last_name'])) {
|
|
if (! empty($shipping_address['name'])) {
|
|
$shipping_address['name'] .= ' ';
|
|
}
|
|
|
|
$shipping_address['name'] .= $shipping_address['last_name'];
|
|
// unset( $shipping_address['last_name'] );
|
|
}
|
|
|
|
// If not USA, Australia or Germany, then change state from ISO code to name
|
|
if ($shipping_address['country'] !== 'US' && $shipping_address['country'] !== 'AU' && $shipping_address['country'] !== 'DE') {
|
|
// Get all states for a country
|
|
$states = WC()->countries->get_states($shipping_address['country']);
|
|
|
|
// If the state is empty, it was entered as free text
|
|
if (! empty($states) && ! empty($shipping_address['state'])) {
|
|
// Change the state to be the name and not the code
|
|
$shipping_address['state'] = $states[$shipping_address['state']];
|
|
|
|
// Remove anything in parentheses (e.g. TH)
|
|
$ind = strpos($shipping_address['state'], ' (');
|
|
if ($ind !== false) {
|
|
$shipping_address['state'] = substr($shipping_address['state'], 0, $ind);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($shipping_address['country'] === 'DE') {
|
|
$shipping_address['state'] = trim($shipping_address['state'], 'DE-');
|
|
}
|
|
|
|
// Check if post number exists then send over
|
|
if ($shipping_dhl_postnum = $order->get_meta('_shipping_dhl_postnum')) {
|
|
$shipping_address['dhl_postnum'] = $shipping_dhl_postnum;
|
|
}
|
|
|
|
$args['shipping_address'] = $shipping_address;
|
|
|
|
// Get order item specific data
|
|
$ordered_items = $order->get_items();
|
|
$args['items'] = [];
|
|
// Sum value of ordered items
|
|
$args['order_details']['items_value'] = 0;
|
|
foreach ($ordered_items as $key => $item) {
|
|
// Reset array
|
|
$new_item = [];
|
|
|
|
$refunded_qty = $order->get_qty_refunded_for_item($key);
|
|
|
|
// Deduct refunded items
|
|
$new_item['qty'] = intval($item['qty']) - abs($refunded_qty);
|
|
|
|
// If its fully refunded item, skip it.
|
|
if ($new_item['qty'] === 0) {
|
|
continue;
|
|
}
|
|
|
|
// Get 1 item value not total items, based on ordered items in case currency is different that set product price
|
|
$new_item['item_value'] = ($item['line_total'] / $item['qty']);
|
|
// Sum 'line_total' to get items total value w/ discounts!
|
|
$args['order_details']['items_value'] += $item['line_total'];
|
|
|
|
$product = wc_get_product($item['product_id']);
|
|
|
|
// If product does not exist (i.e. was deleted) OR is virtual, skip it
|
|
if (empty($product) || $product->is_virtual()) {
|
|
continue;
|
|
}
|
|
|
|
$country_value = get_post_meta($item['product_id'], '_dhl_manufacture_country', true);
|
|
if (! empty($country_value)) {
|
|
$new_item['country_origin'] = $country_value;
|
|
}
|
|
|
|
$hs_code = get_post_meta($item['product_id'], '_dhl_hs_code', true);
|
|
if (! empty($hs_code)) {
|
|
$new_item['hs_code'] = $hs_code;
|
|
}
|
|
|
|
$new_item['item_description'] = $product->get_title();
|
|
// $new_item['line_total'] = $item['line_total'];
|
|
|
|
if (! empty($item['variation_id'])) {
|
|
$product_variation = wc_get_product($item['variation_id']);
|
|
|
|
// If product variation does not exist (i.e. was deleted) OR is virtual, skip it
|
|
if (empty($product_variation) || $product_variation->is_virtual()) {
|
|
continue;
|
|
}
|
|
|
|
// place 'sku' in a variable before validating using 'empty' to be compatible with PHP v5.4
|
|
$product_sku = $product_variation->get_sku();
|
|
// Ensure id is string and not int
|
|
$new_item['product_id'] = intval($item['variation_id']);
|
|
$new_item['sku'] = empty($product_sku) ? strval($item['variation_id']) : $product_sku;
|
|
|
|
// If value is empty due to discounts, set variation price instead
|
|
if (empty($new_item['item_value'])) {
|
|
$new_item['item_value'] = $product_variation->get_price();
|
|
}
|
|
|
|
$new_item['item_weight'] = $product_variation->get_weight();
|
|
|
|
$product_attribute = wc_get_product_variation_attributes($item['variation_id']);
|
|
$new_item['item_description'] .= ' : '.current($product_attribute);
|
|
|
|
} else {
|
|
// place 'sku' in a variable before validating using 'empty' to be compatible with PHP v5.4
|
|
$product_sku = $product->get_sku();
|
|
// Ensure id is string and not int
|
|
$new_item['product_id'] = intval($item['product_id']);
|
|
$new_item['sku'] = empty($product_sku) ? strval($item['product_id']) : $product_sku;
|
|
|
|
// If value is empty due to discounts, set product price instead
|
|
if (empty($new_item['item_value'])) {
|
|
$new_item['item_value'] = $product->get_price();
|
|
}
|
|
|
|
$new_item['item_weight'] = $product->get_weight();
|
|
}
|
|
|
|
$new_item += $this->get_label_item_args($item['product_id'], $args);
|
|
// if( ! empty( $product->post->post_excerpt ) ) {
|
|
// $new_item['item_description'] = $product->post->post_excerpt;
|
|
// } elseif ( ! empty( $product->post->post_content ) ) {
|
|
// $new_item['item_description'] = $product->post->post_content;
|
|
// }
|
|
|
|
array_push($args['items'], $new_item);
|
|
}
|
|
|
|
return $args;
|
|
}
|
|
|
|
abstract protected function get_label_args_settings($order_id, $dhl_label_items);
|
|
|
|
protected function delete_label_args($order_id)
|
|
{
|
|
return $this->get_dhl_label_tracking($order_id);
|
|
}
|
|
|
|
// Pass args by reference to modify DG if needed
|
|
protected function get_label_item_args($product_id, &$args)
|
|
{
|
|
$new_item = [];
|
|
|
|
return $new_item;
|
|
}
|
|
|
|
protected function is_cod_payment_method($order_id)
|
|
{
|
|
$order = wc_get_order($order_id);
|
|
$payment_method = $order->get_payment_method();
|
|
|
|
if ($payment_method == 'cod') {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
protected function get_wc_currency($order_id)
|
|
{
|
|
$order = wc_get_order($order_id);
|
|
|
|
return $order->get_currency();
|
|
}
|
|
|
|
/**
|
|
* Prevents the DHL tracking meta being copied to subscription renewals.
|
|
*
|
|
* Used on older WooCommerce Subscriptions (subscriptions-core < 2.5.0), where the
|
|
* wcs_renewal_order_meta_query filter passes a SQL meta_query string.
|
|
*
|
|
* @param string $order_meta_query The SQL meta_query string used to copy meta to the renewal order.
|
|
* @return string
|
|
*/
|
|
public function remove_dhl_tracking_meta_query($order_meta_query)
|
|
{
|
|
$order_meta_query .= " AND `meta_key` NOT IN ( '_pr_shipment_dhl_label_tracking' )";
|
|
|
|
return $order_meta_query;
|
|
}
|
|
|
|
/**
|
|
* Removes the DHL tracking meta from the data copied to subscription renewal and resubscribe orders.
|
|
*
|
|
* Used on WooCommerce Subscriptions / subscriptions-core 2.5.0+, where the
|
|
* wc_subscriptions_renewal_order_data and wc_subscriptions_resubscribe_order_data filters pass
|
|
* an array of meta data keyed by meta_key instead of the legacy SQL meta_query string.
|
|
*
|
|
* @param array $order_data Meta data to be copied to the new order, keyed by meta_key.
|
|
* @return array
|
|
*/
|
|
public function remove_dhl_tracking_meta($order_data)
|
|
{
|
|
unset($order_data['_pr_shipment_dhl_label_tracking']);
|
|
|
|
return $order_data;
|
|
}
|
|
|
|
/**
|
|
* Bulk functions
|
|
*/
|
|
public function add_order_bulk_actions()
|
|
{
|
|
global $typenow, $pagenow, $current_screen;
|
|
|
|
$is_orders_list = API_Utils::is_HPOS()
|
|
? (wc_get_page_screen_id('shop-order') === $current_screen->id && $pagenow === 'admin.php')
|
|
: ($typenow === 'shop_order' && $pagenow === 'edit.php');
|
|
|
|
if (! $is_orders_list) {
|
|
return;
|
|
}
|
|
|
|
?>
|
|
<script type="text/javascript">
|
|
jQuery( document ).ready( function ( $ ) {
|
|
$( 'select[name^=action]' ).append(
|
|
<?php $index = count($actions = $this->get_bulk_actions()); ?>
|
|
<?php foreach ($actions as $action => $name) { ?>
|
|
$( '<option>' ).val( '<?php echo esc_js($action); ?>' ).text( '<?php echo esc_js($name); ?>' )
|
|
<?php $index--; ?>
|
|
<?php
|
|
if ($index) {
|
|
echo ',';
|
|
}
|
|
?>
|
|
<?php } ?>
|
|
);
|
|
} );
|
|
</script>
|
|
<?php
|
|
}
|
|
|
|
public function process_orders_bulk_actions($redirect, $doaction, $object_ids)
|
|
{
|
|
|
|
if (! array_key_exists($doaction, $this->get_bulk_actions())) {
|
|
return $redirect;
|
|
}
|
|
|
|
$array_messages = ['msg_user_id' => get_current_user_id()];
|
|
|
|
$message = $this->validate_bulk_actions($doaction, $object_ids);
|
|
|
|
if (! empty($message)) {
|
|
array_push(
|
|
$array_messages,
|
|
[
|
|
'message' => $message,
|
|
'type' => 'error',
|
|
]
|
|
);
|
|
} else {
|
|
try {
|
|
$array_messages += $this->process_bulk_actions($doaction, $object_ids);
|
|
} catch (Exception $e) {
|
|
array_push(
|
|
$array_messages,
|
|
[
|
|
'message' => $e->getMessage(),
|
|
'type' => 'error',
|
|
]
|
|
);
|
|
}
|
|
}
|
|
|
|
/*
|
|
@see render_messages() */
|
|
// update_option( '_pr_dhl_bulk_action_confirmation', array( get_current_user_id() => $message, 'is_error' => $is_error ) );
|
|
update_option('_pr_dhl_bulk_action_confirmation', $array_messages);
|
|
|
|
return $redirect;
|
|
}
|
|
|
|
/**
|
|
* Display messages on order view screen
|
|
*/
|
|
public function render_messages()
|
|
{
|
|
global $current_screen;
|
|
|
|
$screens = ['shop_order', 'edit-shop_order'];
|
|
if (API_Utils::is_HPOS()) {
|
|
$screens[] = wc_get_page_screen_id('shop-order');
|
|
}
|
|
|
|
if (isset($current_screen->id) && in_array($current_screen->id, $screens)) {
|
|
$bulk_action_message_opt = get_option('_pr_dhl_bulk_action_confirmation');
|
|
|
|
if (($bulk_action_message_opt) && is_array($bulk_action_message_opt)) {
|
|
// $user_id = key( $bulk_action_message_opt );
|
|
// remove first element from array and verify if it is the user id
|
|
$user_id = array_shift($bulk_action_message_opt);
|
|
if (get_current_user_id() !== (int) $user_id) {
|
|
return;
|
|
}
|
|
|
|
foreach ($bulk_action_message_opt as $key => $value) {
|
|
$message = wp_kses_post($value['message']);
|
|
|
|
switch ($value['type']) {
|
|
case 'error':
|
|
echo '<div class="notice notice-error"><ul><li>'.$message.'</li></ul></div>';
|
|
break;
|
|
case 'success':
|
|
echo '<div class="notice notice-success"><ul><li><strong>'.$message.'</strong></li></ul></div>';
|
|
break;
|
|
default:
|
|
echo '<div class="notice notice-warning"><ul><li><strong>'.$message.'</strong></li></ul></div>';
|
|
}
|
|
}
|
|
|
|
delete_option('_pr_dhl_bulk_action_confirmation');
|
|
}
|
|
}
|
|
}
|
|
|
|
abstract public function get_bulk_actions();
|
|
|
|
public function validate_bulk_actions($action, $order_ids)
|
|
{
|
|
return '';
|
|
}
|
|
|
|
public function process_bulk_actions($action, $order_ids, $dhl_force_product = false, $is_force_product_dom = false)
|
|
{
|
|
$label_count = 0;
|
|
$merge_files = [];
|
|
$array_messages = [];
|
|
$orders_args = [];
|
|
|
|
if ($action === 'pr_dhl_create_labels') {
|
|
|
|
$dhl_obj = PR_DHL()->get_dhl_factory();
|
|
|
|
foreach ($order_ids as $order_id) {
|
|
$order = wc_get_order($order_id);
|
|
|
|
try {
|
|
// Create label if one has not been created before
|
|
if (empty($label_tracking_info = $this->get_dhl_label_tracking($order_id))) {
|
|
|
|
$this->save_default_dhl_label_items($order_id);
|
|
|
|
// $dhl_label_items = $this->get_dhl_label_items( $order_id );
|
|
|
|
// Gather args for DHL API call
|
|
$args = $this->get_label_args($order_id);
|
|
|
|
// Force the use of this DHL Product for all bulk label creation
|
|
if ($dhl_force_product) {
|
|
|
|
// If forced product is domestic AND order is domestic
|
|
if ($is_force_product_dom && $this->is_shipping_domestic($order_id)) {
|
|
$args['order_details']['dhl_product'] = $dhl_force_product;
|
|
}
|
|
|
|
// If forced product is international AND order is international
|
|
if (! $is_force_product_dom && ! $this->is_shipping_domestic($order_id)) {
|
|
$args['order_details']['dhl_product'] = $dhl_force_product;
|
|
}
|
|
}
|
|
|
|
// Allow settings to override saved order data, ONLY for bulk action
|
|
$args = $this->get_bulk_settings_override($args);
|
|
|
|
// Allow third parties to modify the args to the DHL APIs
|
|
$args = apply_filters('pr_shipping_dhl_label_args', $args, $order_id);
|
|
|
|
// API request.
|
|
$label_tracking_info = $dhl_obj->get_dhl_label($args);
|
|
$this->save_dhl_label_tracking($order_id, $label_tracking_info);
|
|
$tracking_note = $this->get_tracking_note($order_id);
|
|
|
|
$tracking_note_type = $this->get_tracking_note_type();
|
|
$tracking_note_type = empty($tracking_note_type) ? 0 : 1;
|
|
|
|
$order->add_order_note($tracking_note, $tracking_note_type, true);
|
|
|
|
$label_count++;
|
|
|
|
$array_messages[] = [
|
|
/* translators: %s is the order number */
|
|
'message' => sprintf(esc_html__('Order #%s: DHL label created', 'dhl-for-woocommerce'), $order->get_order_number()),
|
|
'type' => 'success',
|
|
];
|
|
|
|
do_action('pr_shipping_dhl_label_created', $order_id);
|
|
}
|
|
|
|
if (! empty($label_tracking_info['label_path'])) {
|
|
array_push($merge_files, $label_tracking_info['label_path']);
|
|
}
|
|
} catch (Exception $e) {
|
|
$array_messages[] = [
|
|
/* translators: %1$s is the order number, %2$s is the error message */
|
|
'message' => sprintf(esc_html__('Order #%1$s: %2$s', 'dhl-for-woocommerce'), esc_html($order->get_order_number()), $e->getMessage()),
|
|
'type' => 'error',
|
|
];
|
|
}
|
|
}
|
|
try {
|
|
$file_bulk = $this->merge_label_files($merge_files);
|
|
|
|
if (file_exists($file_bulk['file_bulk_path'])) {
|
|
// We're saving the bulk file path temporarily and access it later during the download process.
|
|
// This information expires in 3 minutes (180 seconds), just enough for the user to see the
|
|
// displayed link and click it if he or she wishes to download the bulk labels
|
|
set_transient(
|
|
'_dhl_bulk_download_labels_file_'.get_current_user_id(),
|
|
$file_bulk['file_bulk_path'],
|
|
180
|
|
);
|
|
|
|
// Construct URL pointing to the download label endpoint (with bulk param):
|
|
$bulk_download_label_url = $this->generate_download_url('/'.self::DHL_DOWNLOAD_ENDPOINT.'/bulk');
|
|
|
|
$array_messages[] = [
|
|
/* translators: %1$s and %2$s are HTML tags for the download link */
|
|
'message' => wp_kses_post(sprintf(__('Bulk DHL labels file created - %1$sdownload file%2$s', 'dhl-for-woocommerce'), '<a href="'.esc_url($bulk_download_label_url).'" download>', '</a>')),
|
|
'type' => 'success',
|
|
];
|
|
} else {
|
|
$array_messages[] = [
|
|
'message' => esc_html__('Could not create bulk DHL label file, download individually.', 'dhl-for-woocommerce'),
|
|
'type' => 'error',
|
|
];
|
|
}
|
|
} catch (Exception $e) {
|
|
$array_messages[] = [
|
|
'message' => wp_kses_post($e->getMessage()),
|
|
'type' => 'error',
|
|
];
|
|
}
|
|
} elseif ($action === 'pr_dhl_delete_labels') {
|
|
$array_messages = $this->delete_label_in_bulk($order_ids);
|
|
}
|
|
|
|
return $array_messages;
|
|
}
|
|
|
|
/**
|
|
* Delete DHL in bulk.
|
|
*
|
|
* @param array<int> $order_ids List of Order IDs.
|
|
* @return array.
|
|
*/
|
|
protected function delete_label_in_bulk($order_ids)
|
|
{
|
|
if (empty($order_ids) || ! is_array($order_ids)) {
|
|
return [];
|
|
}
|
|
|
|
$array_messages = [];
|
|
|
|
foreach ($order_ids as $order_id) {
|
|
$order = wc_get_order($order_id);
|
|
|
|
if (! is_a($order, 'WC_Order')) {
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
$label_tracking = $this->get_dhl_label_tracking($order_id);
|
|
|
|
if (empty($label_tracking)) {
|
|
continue;
|
|
}
|
|
|
|
$tracking_number = $this->processing_delete_label($order_id);
|
|
|
|
// If no tracking number, just continue. We cannot delete the order notes anyway.
|
|
if (empty($tracking_number)) {
|
|
continue;
|
|
}
|
|
|
|
$order_notes = wc_get_order_notes(
|
|
[
|
|
'order_id' => $order_id,
|
|
'limit' => -1,
|
|
'type' => 'customer',
|
|
]
|
|
);
|
|
|
|
$order_notes = array_map(
|
|
function ($order_note) use ($tracking_number) {
|
|
if (empty($order_note->content)) {
|
|
return $order_note;
|
|
}
|
|
|
|
if (strpos($order_note->content, $tracking_number) !== false) {
|
|
wc_delete_order_note($order_note->id);
|
|
}
|
|
|
|
return $order_note;
|
|
},
|
|
$order_notes
|
|
);
|
|
|
|
$array_messages[] = [
|
|
/* translators: %s is the order number */
|
|
'message' => sprintf(esc_html__('Order #%s: DHL Label Deleted', 'dhl-for-woocommerce'), esc_html($order->get_order_number())),
|
|
'type' => 'success',
|
|
];
|
|
} catch (Exception $e) {
|
|
$array_messages[] = [
|
|
/* translators: %1$s is the order number, %2$s is the error message */
|
|
'message' => wp_kses_post(
|
|
sprintf(__('Order #%1$s: %2$s', 'dhl-for-woocommerce'), $order->get_order_number(), $e->getMessage())
|
|
),
|
|
'type' => 'error',
|
|
];
|
|
}
|
|
}
|
|
|
|
return $array_messages;
|
|
}
|
|
|
|
/**
|
|
* Generates the download label URL
|
|
*
|
|
* @param string $endpoint_path
|
|
* @return string - The download URL for the label
|
|
*/
|
|
public function generate_download_url($endpoint_path)
|
|
{
|
|
|
|
// If we get a different URL addresses from the General settings then we're going to
|
|
// construct the expected endpoint url for the download label feature manually
|
|
if (site_url() != home_url()) {
|
|
|
|
// You can use home_url() here as well, it really doesn't matter
|
|
// as we're only after for the "scheme" and "host" info.
|
|
$result = wp_parse_url(site_url());
|
|
|
|
if (! empty($result['scheme']) && ! empty($result['host'])) {
|
|
return $result['scheme'].'://'.$result['host'].$endpoint_path;
|
|
}
|
|
}
|
|
|
|
// Defaults to the "Site Address URL" from the general settings along
|
|
// with the the custom endpoint path (with parameters)
|
|
return home_url($endpoint_path);
|
|
}
|
|
|
|
protected function get_bulk_settings_override($args)
|
|
{
|
|
return $args;
|
|
}
|
|
|
|
protected function merge_label_files($files)
|
|
{
|
|
|
|
if (empty($files)) {
|
|
throw new Exception(esc_html__('There are no files to merge.', 'dhl-for-woocommerce'));
|
|
}
|
|
|
|
if (! empty($files[0])) {
|
|
$base_ext = pathinfo($files[0], PATHINFO_EXTENSION);
|
|
} else {
|
|
throw new Exception(esc_html__('The first file is empty.', 'dhl-for-woocommerce'));
|
|
}
|
|
|
|
if (method_exists($this, 'merge_label_files_'.$base_ext)) {
|
|
return call_user_func([$this, 'merge_label_files_'.$base_ext], $files);
|
|
} else {
|
|
throw new Exception(esc_html__('File format not supported.', 'dhl-for-woocommerce'));
|
|
}
|
|
}
|
|
|
|
protected function merge_label_files_pdf($files)
|
|
{
|
|
|
|
if (empty($files)) {
|
|
throw new Exception(esc_html__('There are no files to merge.', 'dhl-for-woocommerce'));
|
|
}
|
|
|
|
$loader = PR_DHL_Libraryloader::instance();
|
|
$pdfMerger = $loader->get_pdf_merger();
|
|
|
|
if ($pdfMerger === null) {
|
|
|
|
throw new Exception(esc_html__('Library conflict, could not merge PDF files. Please download PDF files individually.', 'dhl-for-woocommerce'));
|
|
}
|
|
|
|
foreach ($files as $key => $value) {
|
|
|
|
if (! file_exists($value)) {
|
|
// throw new Exception( __('File does not exist', 'dhl-for-woocommerce') );
|
|
continue;
|
|
}
|
|
|
|
$ext = pathinfo($value, PATHINFO_EXTENSION);
|
|
// if ( strncasecmp('pdf', $ext, strlen($ext) ) == 0 ) {
|
|
if (stripos($ext, 'pdf') === false) {
|
|
throw new Exception(esc_html__('Not all the file formats are the same.', 'dhl-for-woocommerce'));
|
|
}
|
|
|
|
$pdfMerger->addPDF($value, 'all');
|
|
}
|
|
|
|
$filename = 'dhl-label-bulk-'.time().'.pdf';
|
|
$file_bulk_path = PR_DHL()->get_dhl_label_folder_dir().$filename;
|
|
$file_bulk_url = PR_DHL()->get_dhl_label_folder_url().$filename;
|
|
$pdfMerger->merge('file', $file_bulk_path);
|
|
|
|
return [
|
|
'file_bulk_path' => $file_bulk_path,
|
|
'file_bulk_url' => $file_bulk_url,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Creates a custom endpoint to download the label
|
|
*/
|
|
public function add_download_label_endpoint()
|
|
{
|
|
add_rewrite_endpoint(self::DHL_DOWNLOAD_ENDPOINT, EP_ROOT);
|
|
|
|
// Flush permalink if it is not flushed yet.
|
|
if (! get_option('dhl_permalinks_flushed')) {
|
|
flush_rewrite_rules();
|
|
update_option('dhl_permalinks_flushed', 1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Processes the download label request
|
|
*
|
|
* @return void
|
|
*/
|
|
public function process_download_label()
|
|
{
|
|
global $wp_query;
|
|
|
|
if (! current_user_can('edit_shop_orders')) {
|
|
return;
|
|
}
|
|
|
|
if (! isset($wp_query->query_vars[self::DHL_DOWNLOAD_ENDPOINT])) {
|
|
return;
|
|
}
|
|
|
|
// If we fail to add the "DHL_DOWNLOAD_ENDPOINT" then we bail, otherwise, we
|
|
// will continue with the process below.
|
|
$endpoint_param = $wp_query->query_vars[self::DHL_DOWNLOAD_ENDPOINT];
|
|
if (! isset($endpoint_param)) {
|
|
return;
|
|
}
|
|
|
|
$array_messages = get_option('_pr_dhl_bulk_action_confirmation');
|
|
if (empty($array_messages) || ! is_array($array_messages)) {
|
|
$array_messages = ['msg_user_id' => get_current_user_id()];
|
|
}
|
|
|
|
if ($endpoint_param == 'bulk') {
|
|
|
|
$bulk_file_path = get_transient('_dhl_bulk_download_labels_file_'.get_current_user_id());
|
|
|
|
if ($this->download_label($bulk_file_path) == false) {
|
|
array_push(
|
|
$array_messages,
|
|
[
|
|
'message' => esc_html__('There are currently no bulk DHL label file to download or the download link for the bulk DHL label file has already expired. Please try again.', 'dhl-for-woocommerce'),
|
|
'type' => 'error',
|
|
]
|
|
);
|
|
}
|
|
|
|
$redirect_url = admin_url('edit.php?post_type=shop_order');
|
|
} else {
|
|
$order_id = $endpoint_param;
|
|
|
|
// Get tracking info if it exists
|
|
$label_tracking_info = $this->get_dhl_label_tracking($order_id);
|
|
// Check whether the label has already been created or not
|
|
if (empty($label_tracking_info)) {
|
|
return;
|
|
}
|
|
|
|
// Serve the separate return label when requested, otherwise the shipping label.
|
|
$label_type = isset($_GET['dhl_label_type']) ? sanitize_key(wp_unslash($_GET['dhl_label_type'])) : '';
|
|
if ($label_type === 'return' && ! empty($label_tracking_info['return_label_path'])) {
|
|
$label_path = $label_tracking_info['return_label_path'];
|
|
} else {
|
|
$label_path = $label_tracking_info['label_path'];
|
|
}
|
|
|
|
if ($this->download_label($label_path) == false) {
|
|
array_push(
|
|
$array_messages,
|
|
[
|
|
'message' => esc_html__('Unable to download file. Label appears to be invalid or is missing. Please try again.', 'dhl-for-woocommerce'),
|
|
'type' => 'error',
|
|
]
|
|
);
|
|
}
|
|
|
|
$redirect_url = admin_url('post.php?post='.$order_id.'&action=edit');
|
|
}
|
|
|
|
update_option('_pr_dhl_bulk_action_confirmation', $array_messages);
|
|
|
|
// If there are errors redirect to the shop_orders and display error
|
|
if ($this->has_error_message($array_messages)) {
|
|
wp_redirect(remove_query_arg(['_wp_http_referer', '_wpnonce'], $redirect_url));
|
|
exit;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks whether the current "messages" collection has an
|
|
* error message waiting to be rendered.
|
|
*
|
|
* @param array $messages
|
|
* @return bool
|
|
*/
|
|
protected function has_error_message($messages)
|
|
{
|
|
$has_error = false;
|
|
|
|
foreach ($messages as $key => $value) {
|
|
if ($value['type'] == 'error') {
|
|
$has_error = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $has_error;
|
|
}
|
|
|
|
/**
|
|
* Downloads the generated label file
|
|
*
|
|
* @param string $file_path
|
|
* @return bool|void
|
|
*/
|
|
protected function download_label($file_path)
|
|
{
|
|
if (! empty($file_path) && is_string($file_path) && file_exists($file_path)) {
|
|
// Check if buffer exists, then flush any buffered output to prevent it from being included in the file's content
|
|
if (ob_get_contents()) {
|
|
ob_clean();
|
|
}
|
|
|
|
$filename = basename($file_path);
|
|
|
|
header('Content-Description: File Transfer');
|
|
header('Content-Type: application/octet-stream');
|
|
header('Content-Disposition: attachment; filename="'.$filename.'"');
|
|
header('Expires: 0');
|
|
header('Cache-Control: must-revalidate');
|
|
header('Pragma: public');
|
|
header('Content-Length: '.filesize($file_path));
|
|
|
|
readfile($file_path);
|
|
exit;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|