success = array();
$this->errors = array();
$this->use_split_address_fields = array_key_exists('use_split_address_fields', get_option('woocommerce_postnl_checkout_settings'))
? isset(get_option('woocommerce_postnl_checkout_settings')['use_split_address_fields'])
: false;
include('class-wcmp-rest.php');
include('class-wcmp-api.php');
add_action('admin_notices', array($this, 'admin_notices'));
add_action('wp_ajax_wc_postnl', array($this, 'export'));
add_action('wp_ajax_wc_postnl_frontend', array($this, 'frontend_api_request'));
add_action('wp_ajax_nopriv_wc_postnl_frontend', array($this, 'frontend_api_request'));
}
public function admin_notices() {
if (isset($_GET['postnl_done'])) { // only do this when for the user that initiated this
$action_return = get_option('wcpostnl_admin_notices');
$print_queue = get_option('wcpostnl_print_queue', array());
if ( ! empty($action_return)) {
foreach ($action_return as $type => $message) {
if (in_array($type, array('success', 'error'))) {
if ($type == 'success' && ! empty($print_queue)) {
$print_queue_store = sprintf('', json_encode(array_keys($print_queue['order_ids'])));
$print_queue_offset_store = sprintf('', $print_queue['offset']);
// dequeue
delete_option('wcpostnl_print_queue');
}
printf('
%s
%s
', $type, $message, isset($print_queue_store) ? $print_queue_store . $print_queue_offset_store : '');
}
}
// destroy after reading
delete_option('wcpostnl_admin_notices');
wp_cache_delete('wcpostnl_admin_notices', 'options');
}
}
if (isset($_GET['postnl'])) {
switch($_GET['postnl']) {
case 'no_consignments':
$message = __('You have to export the orders to PostNL before you can print the labels!', 'woocommerce-postnl');
printf('
%s
', $message);
break;
default:
break;
}
}
}
/**
* Export selected orders
* @access public
* @return void
*/
public function export() {
// Check the nonce
check_ajax_referer('wc_postnl', 'security');
if ( ! is_user_logged_in()) {
wp_die(__('You do not have sufficient permissions to access this page.', 'woocommerce-postnl'));
}
$return = array();
// Check the user privileges (maybe use order ids for filter?)
if (apply_filters('wc_postnl_check_privs', ! current_user_can('manage_woocommerce_orders') && ! current_user_can('edit_shop_orders'))) {
$return['error'] = __('You do not have sufficient permissions to access this page.', 'woocommerce-postnl');
$json = json_encode($return);
echo $json;
die();
}
extract($_REQUEST); // $request, $order_ids, ...
// make sure $order_ids is a proper array
$order_ids = ! empty($order_ids) ? $this->sanitize_posted_array($order_ids) : array();
switch($request) {
case 'add_shipments':
// filter out non-postnl destinations
$order_ids = $this->filter_postnl_destination_orders($order_ids);
if (empty($order_ids)) {
$this->errors[] = __('You have not selected any orders!', 'woocommerce-postnl');
break;
}
// if we're going to print directly, we need to process the orders first, regardless of the settings
$process = (isset($print) && $print == 'yes') ? true : false;
$return = $this->add_shipments($order_ids);
break;
case 'add_return':
if (empty($postnl_options)) {
$this->errors[] = __('You have not selected any orders!', 'woocommerce-postnl');
break;
}
$return = $this->add_return($postnl_options);
break;
case 'get_labels':
$offset = ! empty($offset) && is_numeric($offset) ? $offset % 4 : 0;
if (empty($order_ids) && empty($shipment_ids)) {
$this->errors[] = __('You have not selected any orders!', 'woocommerce-postnl');
break;
}
$label_response_type = isset($label_response_type) ? $label_response_type : null;
if ( ! empty($shipment_ids)) {
$order_ids = ! empty($order_ids) ? $this->sanitize_posted_array($order_ids) : array();
$shipment_ids = $this->sanitize_posted_array($shipment_ids);
$return = $this->get_shipment_labels($shipment_ids, $order_ids, $label_response_type, $offset);
} else {
$order_ids = $this->filter_postnl_destination_orders($order_ids);
$return = $this->get_labels($order_ids, $label_response_type, $offset);
}
break;
case 'modal_dialog':
if (empty($order_ids)) {
$errors[] = __('You have not selected any orders!', 'woocommerce-postnl');
break;
}
$order_ids = $this->filter_postnl_destination_orders($order_ids);
$this->modal_dialog($order_ids, $dialog);
break;
}
// display errors directly if PDF requested or modal
if (in_array($request, array('add_return', 'get_labels', 'modal_dialog')) && ! empty($this->errors)) {
echo $this->parse_errors($this->errors);
die();
}
// format errors for html output
if ( ! empty($this->errors)) {
$return['error'] = $this->parse_errors($this->errors);
}
// When adding shipments, store $return for use in admin_notice
// This way we can refresh the page (JS) to show all new buttons
if ($request == 'add_shipments' && ! empty($print) && ($print == 'no' || $print == 'after_reload')) {
update_option('wcpostnl_admin_notices', $return);
if ($print == 'after_reload') {
$print_queue = array(
'order_ids' => $return['success_ids'],
'offset' => isset($offset) && is_numeric($offset) ? $offset % 4 : 0,
);
update_option('wcpostnl_print_queue', $print_queue);
}
}
// if we're directed here from modal, show proper result page
if (isset($modal)) {
$this->modal_success_page($request, $return);
} else {
// return JSON response
echo json_encode($return);
}
die();
}
public function sanitize_posted_array($array) {
// check for JSON
if (is_string($array) && strpos($array, '[') !== false) {
$array = json_decode(stripslashes($array));
}
// cast as array for single exports
$array = (array) $array;
return $array;
}
public function add_shipments($order_ids, $process = false) {
$return = array();
$this->log("*** Creating shipments started ***");
foreach ($order_ids as $order_id) {
$created_shipments = array();
$order = WCX::get_order($order_id);
$shipments = $this->get_order_shipment_data((array) $order_id);
$shipments = $this->validate_shipments($shipments);
if (empty($shipments)) {
$this->log("Export for order {$order_id} skipped (missing or invalidated shipment data)");
continue;
}
$this->log("Shipment data for order {$order_id}:\n" . var_export($shipments, true));
// check colli amount
$extra_params = WCX_Order::get_meta($order, '_postnl_shipment_options_extra');
$colli_amount = isset($extra_params['colli_amount']) ? $extra_params['colli_amount'] : 1;
for ($i = 0; $i < intval($colli_amount); $i++) {
try {
$api = $this->init_api();
$response = $api->add_shipments($shipments);
$this->log("API response (order {$order_id}):\n" . var_export($response, true));
if (isset($response['body']['data']['ids'])) {
$ids = array_shift($response['body']['data']['ids']);
$shipment_id = $ids['id'];
$this->success[$order_id] = $shipment_id;
$created_shipments[] = $shipment_id;
$shipment = array(
'shipment_id' => $shipment_id,
);
// save shipment data in order meta
$this->save_shipment_data($order, $shipment);
// process directly setting
if (isset(WooCommerce_PostNL()->general_settings['process_directly']) || $process === true) {
// flush cache until WC issue #13439 is fixed https://github.com/woocommerce/woocommerce/issues/13439
if (method_exists($order, 'save')) {
$order->save();
}
$this->get_labels((array) $order_id, 'url');
$this->get_shipment_data($shipment_id, $order);
}
// status automation
if (isset(WooCommerce_PostNL()->general_settings['order_status_automation']) && ! empty(WooCommerce_PostNL()->general_settings['automatic_order_status'])) {
$order->update_status(WooCommerce_PostNL()->general_settings['automatic_order_status'], __('PostNL shipment created:', 'woocommerce-postnl'));
}
} else {
$this->errors[$order_id] = __('Unknown error', 'woocommerce-postnl');
}
} catch ( Exception $e ) {
$this->errors[$order_id] = $e->getMessage();
}
}
// store shipment ids from this export
if ( ! empty($created_shipments)) {
WCX_Order::update_meta_data($order, '_postnl_last_shipment_ids', $created_shipments);
}
}
if ( ! empty($this->success)) {
$return['success'] = sprintf(__('%s shipments successfully exported to PostNL', 'woocommerce-postnl'), count($this->success));
$return['success_ids'] = $this->success;
}
return $return;
}
public function add_return($postnl_options) {
$return = array();
$this->log("*** Creating return shipments started ***");
foreach ($postnl_options as $order_id => $options) {
$return_shipments = array($this->prepare_return_shipment_data($order_id, $options));
$this->log("Return shipment data for order {$order_id}:\n" . var_export($return_shipments, true));
try {
$api = $this->init_api();
$response = $api->add_shipments($return_shipments, 'return');
$this->log("API response (order {$order_id}):\n" . var_export($response, true));
if (isset($response['body']['data']['ids'])) {
$order = WCX::get_order($order_id);
$ids = array_shift($response['body']['data']['ids']);
$shipment_id = $ids['id'];
$this->success[$order_id] = $shipment_id;
$shipment = array(
'shipment_id' => $shipment_id,
);
// save shipment data in order meta
$this->save_shipment_data($order, $shipment);
} else {
$this->errors[$order_id] = __('Unknown error', 'woocommerce-postnl');
}
} catch ( Exception $e ) {
$this->errors[$order_id] = $e->getMessage();
}
}
return $return;
}
public function get_shipment_labels($shipment_ids, $order_ids = array(), $label_response_type = null, $offset = 0) {
$return = array();
$this->log("*** Label request started ***");
$this->log("Shipment ID's: " . implode(', ', $shipment_ids));
try {
$api = $this->init_api();
$params = array();
if ( ! empty($offset) && is_numeric($offset)) {
$portrait_positions = array(2, 4, 1, 3); // positions are defined on landscape, but paper is filled portrait-wise
$params['positions'] = implode(';', array_slice($portrait_positions, $offset));
}
if (isset($label_response_type) && $label_response_type == 'url') {
$response = $api->get_shipment_labels($shipment_ids, $params, 'link');
$this->add_postnl_note_to_shipments($shipment_ids, $order_ids);
$this->log("API response:\n" . var_export($response, true));
if (isset($response['body']['data']['pdfs']['url'])) {
$url = untrailingslashit($api->APIURL) . $response['body']['data']['pdfs']['url'];
$return['url'] = $url;
} else {
$this->errors[] = __('Unknown error', 'woocommerce-postnl');
}
} else {
$response = $api->get_shipment_labels($shipment_ids, $params, 'pdf');
$this->add_postnl_note_to_shipments($shipment_ids, $order_ids);
if (isset($response['body'])) {
$this->log("PDF data received");
$pdf_data = $response['body'];
$output_mode = isset(WooCommerce_PostNL()->general_settings['download_display'])
? WooCommerce_PostNL()->general_settings['download_display']
: '';
if ($output_mode == 'display') {
$this->stream_pdf($pdf_data, $order_ids);
} else {
$this->download_pdf($pdf_data, $order_ids);
}
} else {
$this->log("Unknown error, API response:\n" . var_export($response, true));
$this->errors[] = __('Unknown error', 'woocommerce-postnl');
}
}
} catch ( Exception $e ) {
$this->errors[] = $e->getMessage();
}
return $return;
}
public function get_labels($order_ids, $label_response_type = null, $offset = 0) {
$shipment_ids = $this->get_shipment_ids($order_ids, array('only_last' => true));
if (empty($shipment_ids)) {
$this->log("*** Failed label request (not exported yet) ***");
$this->errors[] = __('The selected orders have not been exported to PostNL yet!', 'woocommerce-postnl');
return array();
}
return $this->get_shipment_labels($shipment_ids, $order_ids, $label_response_type, $offset);
}
public function modal_dialog($order_ids, $dialog) {
// check for JSON
if (is_string($order_ids) && strpos($order_ids, '[') !== false) {
$order_ids = json_decode(stripslashes($order_ids));
}
// cast as array for single exports
$order_ids = (array) $order_ids;
include('views/wcmp-bulk-options-form.php');
die();
}
public function modal_success_page($request, $result) {
include('views/wcmp-modal-result-page.php');
die();
}
public function frontend_api_request() {
// TODO: check nonce
$params = $_REQUEST;
// filter non API params
$api_params = array(
'cc' => '',
'postal_code' => '',
'number' => '',
'carrier' => '',
'delivery_time' => '',
'delivery_date' => '',
'cutoff_time' => '',
'dropoff_days' => '',
'dropoff_delay' => '',
'deliverydays_window' => '',
'exclude_delivery_type' => '',
);
$params = array_intersect_key($params, $api_params);
$api = $this->init_api();
try {
$response = $api->get_delivery_options($params, true);
@header('Content-type: application/json; charset=utf-8');
echo $response['body'];
} catch ( Exception $e ) {
@header("HTTP/1.1 503 service unavailable");
}
die();
}
public function init_api() {
// $user = WooCommerce_PostNL()->general_settings['api_username'];
if ( ! isset(WooCommerce_PostNL()->general_settings['api_key'])) {
return false;
}
$key = WooCommerce_PostNL()->general_settings['api_key'];
$api = new WC_PostNL_API($key);
return $api;
}
public function get_order_shipment_data($order_ids, $type = 'standard') {
foreach ($order_ids as $order_id) {
// get order
$order = WCX::get_order($order_id);
$shipment = array(
'reference_identifier' => $this->replace_shortcodes(WooCommerce_PostNL()->export_defaults['label_description'], $order),
'recipient' => $this->get_recipient($order),
'options' => $this->get_options($order),
'carrier' => 1, // default to POSTNL for now
);
if ($pickup = $this->is_pickup($order)) {
$shipment['pickup'] = array(
'postal_code' => $pickup['postal_code'],
'street' => $pickup['street'],
'city' => $pickup['city'],
'number' => $pickup['number'],
'location_code' => $pickup['location_code'],
'retail_network_id' => $pickup['retail_network_id'],
'location_name' => $pickup['location'],
);
}
$shipping_country = WCX_Order::get_prop($order, 'shipping_country');
if ($this->is_world_shipment_country($shipping_country)) {
$customs_declaration = $this->get_customs_declaration($order);
$shipment['customs_declaration'] = $customs_declaration;
$shipment['physical_properties'] = array(
'weight' => $customs_declaration['weight'],
);
}
if ($shipment['options']['package_type'] == self::MAILBOX_PACKAGE ) {
unset($shipment['options']['weight']);
}
$shipments[] = apply_filters('wc_postnl_order_shipment', $shipment, $order, $type, $this);
}
return $shipments;
}
public function get_recipient($order) {
$is_using_old_fields =
(string) WCX_Order::get_meta($order, '_billing_street_name') != '' ||
(string) WCX_Order::get_meta($order, '_billing_house_number') != '';
$shipping_name = method_exists($order, 'get_formatted_shipping_full_name')
? $order->get_formatted_shipping_full_name()
: trim($order->shipping_first_name . ' ' . $order->shipping_last_name);
$address = array(
'cc' => (string) WCX_Order::get_prop($order, 'shipping_country'),
'city' => (string) WCX_Order::get_prop($order, 'shipping_city'),
'person' => $shipping_name,
'company' => (string) WCX_Order::get_prop($order, 'shipping_company'),
'email' => WCX_Order::get_prop($order, 'billing_email'),
'phone' => isset(WooCommerce_PostNL()->export_defaults['connect_phone']) ? WCX_Order::get_prop($order, 'billing_phone') : '',
'street_additional_info' => WCX_Order::get_prop($order, 'shipping_address_2'),
);
$shipping_country = WCX_Order::get_prop( $order, 'shipping_country' );
if ( $shipping_country == 'NL' || $shipping_country == 'BE' ) {
// use billing address if old 'pakjegemak' (1.5.6 and older)
if ($pgaddress = WCX_Order::get_meta($order, '_postnl_pgaddress')) {
$billing_name = method_exists($order, 'get_formatted_billing_full_name')
? $order->get_formatted_billing_full_name()
: trim($order->billing_first_name . ' ' . $order->billing_last_name);
$address_intl = array(
'city' => (string) WCX_Order::get_prop($order, 'billing_city'),
'person' => $billing_name,
'company' => (string) WCX_Order::get_prop($order, 'billing_company'),
'postal_code' => (string) WCX_Order::get_prop($order, 'billing_postcode'),
);
// If not using old fields
if (!$is_using_old_fields) {
// Split the address line 1 into three parts
preg_match(
Woocommerce_PostNL_Postcode_Fields::SPLIT_STREET_REGEX,
WCX_Order::get_prop($order, 'billing_address_1'),
$address_parts
);
$address_intl['street'] = (string) $address_parts['street'];
$address_intl['number'] = (string) $address_parts['number'];
$address_intl['number_suffix'] = array_key_exists('number_suffix', $address_parts) // optional
? (string) $address_parts['number_suffix']
: '';
$address_intl['street_additional_info'] = WCX_Order::get_prop($order, 'billing_address_2');
} else {
$address_intl['street'] = (string) WCX_Order::get_meta($order, '_billing_street_name');
$address_intl['number'] = (string) WCX_Order::get_meta($order, '_billing_house_number');
$address_intl['number_suffix'] = (string) WCX_Order::get_meta($order, '_billing_house_number_suffix');
}
} else {
$address_intl = array(
'postal_code' => (string) WCX_Order::get_prop( $order, 'shipping_postcode' ),
);
// If not using old fields
if (!$is_using_old_fields) {
// Split the address line 1 into three parts
preg_match(
Woocommerce_PostNL_Postcode_Fields::SPLIT_STREET_REGEX,
WCX_Order::get_prop($order, 'shipping_address_1'),
$address_parts
);
$address_intl['street'] = (string) $address_parts['street'];
$address_intl['number'] = (string) $address_parts['number'];
$address_intl['number_suffix'] = array_key_exists('number_suffix', $address_parts) // optional
? (string) $address_parts['number_suffix']
: '';
} else {
$address_intl['street'] = (string) WCX_Order::get_meta($order, '_shipping_street_name');
$address_intl['number'] = (string) WCX_Order::get_meta($order, '_shipping_house_number');
$address_intl['number_suffix'] = (string) WCX_Order::get_meta($order, '_shipping_house_number_suffix');
}
}
} else {
$address_intl = array(
'postal_code' => (string) WCX_Order::get_prop($order, 'shipping_postcode'),
'street' => (string) WCX_Order::get_prop($order, 'shipping_address_1'),
'street_additional_info' => (string) WCX_Order::get_prop($order, 'shipping_address_2'),
'region' => (string) WCX_Order::get_prop($order, 'shipping_state'),
);
}
$address = array_merge($address, $address_intl);
return apply_filters('wc_postnl_recipient', $address, $order);
}
/**
* @param $selected_shipment_ids
* @param $order_ids
*
* @internal param $shipment_ids
*/
public function add_postnl_note_to_shipments($selected_shipment_ids, $order_ids) {
if ( ! isset(WooCommerce_PostNL()->general_settings['barcode_in_note'])) {
return;
}
// Select the barcode text of the PostNL settings
$this->prefix_message = WooCommerce_PostNL()->general_settings['barcode_in_note_title'];
foreach ($order_ids as $order_id) {
$order = WCX::get_order($order_id);
$order_shipments = WCX_Order::get_meta($order, '_postnl_shipments');
foreach ($order_shipments as $shipment) {
$shipment_id = $shipment['shipment_id'];
$this->add_postnl_note_to_shipment($selected_shipment_ids, $shipment_id, $order);
}
}
return;
}
public function get_options($order) {
// parse description
if (isset(WooCommerce_PostNL()->export_defaults['label_description'])) {
$description = $this->replace_shortcodes(WooCommerce_PostNL()->export_defaults['label_description'], $order);
} else {
$description = '';
}
// use shipment options from order when available
$shipment_options = WCX_Order::get_meta($order, '_postnl_shipment_options');
$package_type = $this->get_package_type_for_order($order);
$delivery_type = $this->get_delivery_type($order);
if ( ! empty($shipment_options)) {
$empty_defaults = array(
'package_type' => self::PACKAGE,
'only_recipient' => 0,
'signature' => 0,
'return' => 0,
'label_description' => '',
'insured_amount' => 0,
'age_check' => 0,
);
$options = array_merge($empty_defaults, $shipment_options);
} else {
if (isset(WooCommerce_PostNL()->export_defaults['insured'])
&& WooCommerce_PostNL()->export_defaults['insured_amount'] == ''
&& isset(WooCommerce_PostNL()->export_defaults['insured_amount_custom'])) {
$insured_amount = WooCommerce_PostNL()->export_defaults['insured_amount_custom'];
} else if (isset(WooCommerce_PostNL()->export_defaults['insured']) && isset( WooCommerce_PostNL()->export_defaults['insured_amount'] )) {
$insured_amount = WooCommerce_PostNL()->export_defaults['insured_amount'];
} else {
$insured_amount = 0;
}
$options = array(
'package_type' => $package_type,
'only_recipient' => (isset(WooCommerce_PostNL()->export_defaults['only_recipient'])) ? 1 : 0,
'signature' => (isset(WooCommerce_PostNL()->export_defaults['signature'])) ? 1 : 0,
'return' => (isset(WooCommerce_PostNL()->export_defaults['return']) && ($delivery_type != self::PICKUP && $delivery_type != self::PICKUP_EXPRESS)) ? 1 : 0,
'label_description' => $description,
'insured_amount' => $insured_amount,
'age_check' => (isset(WooCommerce_PostNL()->export_defaults['age_check'])) ? 1 : 0,
);
}
// convert insurance option
if ( ! isset($options['insurance']) && isset($options['insured_amount'])) {
if ($options['insured_amount'] > 0) {
$options['insurance'] = array(
'amount' => (int) $options['insured_amount'] * 100,
'currency' => 'EUR',
);
}
unset($options['insured_amount']);
unset($options['insured']);
}
// set insurance amount to int if already set
if (isset($options['insurance'])) {
$options['insurance']['amount'] = (int) $options['insurance']['amount'];
}
// remove frontend insurance option values
if (isset($options['insured_amount'])) {
unset($options['insured_amount']);
}
if (isset($options['insured'])) {
unset($options['insured']);
}
// load delivery options
$postnl_delivery_options = WCX_Order::get_meta($order, '_postnl_delivery_options');
// set delivery type
$options['delivery_type'] = $this->get_delivery_type($order, $postnl_delivery_options);
// age check cann't be used in morning and evening delivery
if ($options['age_check'] == 1) {
$age_check_options = $this->get_age_check($order, $options, $postnl_delivery_options);
$options['age_check'] = $age_check_options[0];
$options['signature'] = $age_check_options[1];
$options['only_recipient'] = $age_check_options[2];
}
// Options for Pickup and Pickup express delivery types:
// always enable signature on receipt
if ($this->is_pickup($order, $postnl_delivery_options)) {
$options['signature'] = 1;
}
// delivery date (postponed delivery & pickup)
if ($delivery_date = $this->get_delivery_date($order, $postnl_delivery_options)) {
$date_time = explode(' ', $delivery_date); // split date and time
// only add if date is in the future
$timestamp = strtotime($date_time[0]);
if ($timestamp < time()) {
$new_timestamp = $this->get_next_delivery_day($timestamp);
$delivery_date = date('Y-m-d h:i:s', $new_timestamp);
}
$options['delivery_date'] = $delivery_date;
}
// options signature & recipient only
$postnl_signature = WCX_Order::get_meta($order, '_postnl_signature');
if ( ! empty($postnl_signature)) {
$options['signature'] = 1;
}
$postnl_only_recipient = WCX_Order::get_meta($order, '_postnl_only_recipient');
if ( ! empty($postnl_only_recipient)) {
$options['only_recipient'] = 1;
}
// allow prefiltering consignment data
$options = apply_filters('wc_postnl_order_shipment_options', $options, $order);
// PREVENT ILLEGAL SETTINGS
// convert numeric strings to int
$int_options = array('package_type', 'delivery_type', 'only_recipient', 'signature', 'return', 'age_check');
foreach ($options as $key => &$value) {
if (in_array($key, $int_options)) {
$value = (int) $value;
}
}
// disable options for mailbox package, unpaid letter
if ($options['package_type'] != self::PACKAGE) {
$illegal_options = array('delivery_type', 'only_recipient', 'signature', 'return', 'insurance', 'delivery_date', 'age_check');
foreach ($options as $key => $option) {
if (in_array($key, $illegal_options)) {
unset($options[$key]);
}
}
}
return $options;
}
/**
* @param int $timestamp
*
* @return false|string
*/
private function get_next_delivery_day($timestamp) {
$weekDay = date('w', $timestamp);
$new_timestamp = strtotime( '+1 day', $timestamp );
if ($weekDay == 0 || $weekDay == 1 || $new_timestamp < time() ) {
$new_timestamp = $this->get_next_delivery_day( $new_timestamp );
}
return $new_timestamp;
}
public function get_customs_declaration($order) {
$invoice = $this->get_invoice_number($order);
$contents = (int) ((isset(WooCommerce_PostNL()->export_defaults['package_contents']))
? WooCommerce_PostNL()->export_defaults['package_contents']
: 1);
// Item defaults:
// Classification
$default_hs_code = (isset(WooCommerce_PostNL()->export_defaults['hs_code']))
? WooCommerce_PostNL()->export_defaults['hs_code']
: '';
// Country (=shop base)
$country = WC()->countries->get_base_country();
$items = array();
foreach ($order->get_items() as $item_id => $item) {
$product = $order->get_product_from_item($item);
if ( ! empty($product)) {
// Description cut after 50 chars
$description = $item['name'];
if (strlen($description) >= self::DESCRIPTION_MAX_LENGTH) {
$description = substr($item['name'], 0, 47) . '...';
}
// Amount
$amount = (int) (isset($item['qty']) ? $item['qty'] : 1);
// Weight (total item weight in grams)
$weight = (int) round($this->get_item_weight_kg($item, $order) * 1000);
// Item value (in cents)
$item_value = array(
'amount' => (int) round(($item['line_total'] + $item['line_tax']) * 100),
'currency' => WCX_Order::get_prop($order, 'currency'),
);
// Classification / HS Code
$classification = WCX_Product::get_meta($product, '_postnl_hs_code', true);
if (empty($classification)) {
$classification = $default_hs_code;
}
// add item to item list
$items[] = compact('description', 'amount', 'weight', 'item_value', 'classification', 'country');
}
}
// Get the total weight of the package
$weight = (int) round($this->get_parcel_weight($order) * 1000);
return compact('weight', 'invoice', 'contents', 'items');
}
public function validate_shipments($shipments, $output_errors = true) {
$missing_hs_codes = 0;
foreach ($shipments as $key => $shipment) {
// check customs declaration for HS codes
if (isset($shipment['customs_declaration']) && ! empty($shipment['customs_declaration']['items'])) {
foreach ($shipment['customs_declaration']['items'] as $key => $item) {
if (empty($item['classification'])) {
unset($shipments[$key]);
$missing_hs_codes++;
break;
}
}
}
if ($output_errors === true && $missing_hs_codes > 0) {
$this->errors[] = sprintf(
__('%d shipments missing HS codes - not exported.', 'woocommerce-postnl'),
$missing_hs_codes
);
}
}
return $shipments;
}
public function get_shipment_ids($order_ids, $args) {
$shipment_ids = array();
foreach ($order_ids as $order_id) {
$order = WCX::get_order($order_id);
$order_shipments = WCX_Order::get_meta($order, '_postnl_shipments');
if ( ! empty($order_shipments)) {
$order_shipment_ids = array();
// exclude concepts or only concepts
foreach ($order_shipments as $key => $shipment) {
if (isset($args['exclude_concepts']) && empty($shipment['tracktrace'])) {
continue;
}
if (isset($args['only_concepts']) && ! empty($shipment['tracktrace'])) {
continue;
}
$order_shipment_ids[] = $shipment['shipment_id'];
}
if (isset($args['only_last'])) {
$last_shipment_ids = WCX_Order::get_meta($order, '_postnl_last_shipment_ids');
if ( ! empty($last_shipment_ids) && is_array($last_shipment_ids)) {
foreach ($order_shipment_ids as $order_shipment_id) {
if (in_array($order_shipment_id, $last_shipment_ids)) {
$shipment_ids[] = $order_shipment_id;
}
}
} else {
$shipment_ids[] = array_pop($order_shipment_ids);
}
} else {
$shipment_ids[] = array_merge($shipment_ids, $order_shipment_ids);
}
}
}
return $shipment_ids;
}
/**
* @param $order
* @param $shipment
*
* @return bool|void
*/
public function save_shipment_data($order, $shipment) {
if (empty($shipment)) {
return false;
}
$new_shipments = array();
$new_shipments[$shipment['shipment_id']] = $shipment;
if (isset(WooCommerce_PostNL()->general_settings['keep_shipments'])) {
if ($old_shipments = WCX_Order::get_meta($order, '_postnl_shipments')) {
$shipments = $old_shipments;
foreach ($new_shipments as $shipment_id => $shipment) {
$shipments[$shipment_id] = $shipment;
}
}
}
$shipments = isset($shipments) ? $shipments : $new_shipments;
WCX_Order::update_meta_data($order, '_postnl_shipments', $shipments);
return;
}
public function get_package_type_from_shipping_method($shipping_method, $shipping_class, $shipping_country) {
$package_type = self::PACKAGE;
$shipping_method_id_class = "";
if (isset(WooCommerce_PostNL()->export_defaults['shipping_methods_package_types'])) {
if (strpos($shipping_method, "table_rate:") === 0 && class_exists('WC_Table_Rate_Shipping')) {
// Automattic / WooCommerce table rate
// use full method = method_id:instance_id:rate_id
$shipping_method_id = $shipping_method;
} else { // non table rates
if (strpos($shipping_method, ':') !== false) {
// means we have method_id:instance_id
$shipping_method = explode(':', $shipping_method);
$shipping_method_id = $shipping_method[0];
$shipping_method_instance = $shipping_method[1];
} else {
$shipping_method_id = $shipping_method;
}
// add class if we have one
if ( ! empty($shipping_class)) {
$shipping_method_id_class = "{$shipping_method_id}:{$shipping_class}";
}
}
foreach (WooCommerce_PostNL()->export_defaults['shipping_methods_package_types'] as $package_type_key => $package_type_shipping_methods) {
if ($this->isActiveMethod(
$shipping_method_id,
$package_type_shipping_methods,
$shipping_method_id_class,
$shipping_class
)) {
$package_type = $package_type_key;
break;
}
}
}
// disable mailbox package outside NL
if ($shipping_country != 'NL' && $package_type == self::MAILBOX_PACKAGE) {
$package_type = self::PACKAGE;
}
return $package_type;
}
// determine appropriate package type for this order
public function get_package_type_for_order($order) {
$shipping_country = WCX_Order::get_prop($order, 'shipping_country');
// get shipping methods from order
$order_shipping_methods = $order->get_items('shipping');
if ( ! empty($order_shipping_methods)) {
// we're taking the first (we're not handling multiple shipping methods as of yet)
$order_shipping_method = array_shift($order_shipping_methods);
$order_shipping_method = $order_shipping_method['method_id'];
$order_shipping_class = WCX_Order::get_meta($order, '_postnl_highest_shipping_class');
if (empty($order_shipping_class)) {
$order_shipping_class = $this->get_order_shipping_class($order, $order_shipping_method);
}
$package_type = $this->get_package_type_from_shipping_method(
$order_shipping_method,
$order_shipping_class,
$shipping_country
);
}
// fallback if no match from previous
if ( ! isset($package_type)) {
if ((isset(WooCommerce_PostNL()->export_defaults['package_type']))) {
$package_type = WooCommerce_PostNL()->export_defaults['package_type'];
} else {
$package_type = self::PACKAGE;
}
}
// always parcel for Pickup and Pickup express delivery types.
if ($this->is_pickup($order)) {
$package_type = self::PACKAGE;
}
return $package_type;
}
public function get_package_types($shipment_type = 'shipment') {
$package_types = array(
self::PACKAGE => __('Parcel', 'woocommerce-postnl'),
self::MAILBOX_PACKAGE => __('Mailbox package', 'woocommerce-postnl'),
self::LETTER => __('Unpaid letter', 'woocommerce-postnl'),
);
if ($shipment_type == 'return') {
unset($package_types[self::MAILBOX_PACKAGE]);
unset($package_types[self::LETTER]);
}
return $package_types;
}
public function get_package_name($package_type) {
$package_types = $this->get_package_types();
$package_name = isset($package_types[$package_type])
? $package_types[$package_type]
: __('Unknown', 'woocommerce-postnl');
return $package_name;
}
public function parse_errors($errors) {
$parsed_errors = array();
foreach ($errors as $key => $error) {
// check if we have an order_id
if ($key > 10) {
$parsed_errors[] = sprintf("%s %s: %s", __( 'Order', 'woocommerce-postnl' ), $key, $error );
} else {
$parsed_errors[] = $error;
}
}
if (count($parsed_errors) == 1) {
$html = array_shift($parsed_errors);
} else {
foreach ($parsed_errors as &$parsed_error) {
$parsed_error = "
{$parsed_error}
";
}
$html = sprintf("
%s
", implode("\n",$parsed_errors));
}
return $html;
}
public function stream_pdf($pdf_data, $order_ids) {
header('Content-type: application/pdf');
header('Content-Disposition: inline; filename="' . $this->get_filename($order_ids) . '"');
echo $pdf_data;
die();
}
public function download_pdf($pdf_data, $order_ids) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $this->get_filename($order_ids) . '"');
header('Content-Transfer-Encoding: binary');
header('Connection: Keep-Alive');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
echo $pdf_data;
die();
}
public function get_filename($order_ids) {
$filename = 'PostNL';
$filename .= '-' . date('Y-m-d') . '.pdf';
return apply_filters('wcpostnl_filename', $filename, $order_ids);
}
public function get_shipment_status_name($status_code) {
$shipment_statuses = array(
1 => __('pending - concept', 'woocommerce-postnl'),
2 => __('pending - registered', 'woocommerce-postnl'),
3 => __('enroute - handed to carrier', 'woocommerce-postnl'),
4 => __('enroute - sorting', 'woocommerce-postnl'),
5 => __('enroute - distribution', 'woocommerce-postnl'),
6 => __('enroute - customs', 'woocommerce-postnl'),
7 => __('delivered - at recipient', 'woocommerce-postnl'),
8 => __('delivered - ready for pickup', 'woocommerce-postnl'),
9 => __('delivered - package picked up', 'woocommerce-postnl'),
30 => __('inactive - concept', 'woocommerce-postnl'),
31 => __('inactive - registered', 'woocommerce-postnl'),
32 => __('inactive - enroute - handed to carrier', 'woocommerce-postnl'),
33 => __('inactive - enroute - sorting', 'woocommerce-postnl'),
34 => __('inactive - enroute - distribution', 'woocommerce-postnl'),
35 => __('inactive - enroute - customs', 'woocommerce-postnl'),
36 => __('inactive - delivered - at recipient', 'woocommerce-postnl'),
37 => __('inactive - delivered - ready for pickup', 'woocommerce-postnl'),
38 => __('inactive - delivered - package picked up', 'woocommerce-postnl'),
99 => __('inactive - unknown', 'woocommerce-postnl'),
);
if (isset($shipment_statuses[$status_code])) {
return $shipment_statuses[$status_code];
} else {
return __('Unknown status', 'woocommerce-postnl');
}
}
public function get_shipment_data($id, $order) {
try {
$api = $this->init_api();
$response = $api->get_shipments($id);
if ( ! empty($response['body']['data']['shipments'])) {
$shipments = $response['body']['data']['shipments'];
$shipment = array_shift($shipments);
// if shipment id matches and status is not concept, get tracktrace barcode and status name
if (isset($shipment['id']) && $shipment['id'] == $id && $shipment['status'] >= 2) {
$status = $this->get_shipment_status_name($shipment['status']);
$tracktrace = $shipment['barcode'];
$shipment_id = $id;
$shipment_data = compact('shipment_id', 'status', 'tracktrace', 'shipment');
$this->save_shipment_data($order, $shipment_data);
// If Channel Engine is active, add the created Track & Trace code and set shipping method to PostNL in their meta data
if (WC_CHANNEL_ENGINE_ACTIVE and ! WCX_Order::get_meta($order, '_shipping_ce_track_and_trace')) {
WCX_Order::update_meta_data($order, '_shipping_ce_track_and_trace', $tracktrace);
WCX_Order::update_meta_data($order, '_shipping_ce_shipping_method', 'PostNL');
}
return $shipment_data;
} else {
return false;
}
} else {
// No shipments found with this ID
return false;
}
} catch ( Exception $e ) {
return false;
}
}
public function replace_shortcodes($description, $order) {
$postnl_delivery_options = WCX_Order::get_meta($order, '_postnl_delivery_options');
$replacements = array(
'[ORDER_NR]' => $order->get_order_number(),
'[DELIVERY_DATE]' => isset($postnl_delivery_options) && isset($postnl_delivery_options['date'])
? $postnl_delivery_options['date']
: '',
);
$description = str_replace(array_keys($replacements), array_values($replacements), $description);
return $description;
}
public function get_item_display_name($item, $order) {
// set base name
$name = $item['name'];
// add variation name if available
$product = $order->get_product_from_item($item);
if ($product && isset($item['variation_id']) && $item['variation_id'] > 0 && method_exists($product, 'get_variation_attributes')) {
$name .= woocommerce_get_formatted_variation($product->get_variation_attributes());
}
return $name;
}
public function get_parcel_weight($order, $unit = 'kg') {
$parcel_weight = (isset(WooCommerce_PostNL()->general_settings['empty_parcel_weight']))
? preg_replace("/\D/", "", WooCommerce_PostNL()->general_settings['empty_parcel_weight']) / 1000
: 0;
$items = $order->get_items();
foreach ( $items as $item_id => $item ) {
switch ($unit) {
case 'kg':
$parcel_weight += $this->get_item_weight_kg($item, $order);
break;
case 'g':
$parcel_weight += $this->get_item_weight_g($item, $order);
break;
}
}
return $parcel_weight;
}
public function get_item_weight_kg($item, $order) {
$product = $order->get_product_from_item($item);
if (empty($product)) {
return 0;
}
$weight = (int) $product->get_weight();
$weight_unit = get_option('woocommerce_weight_unit');
switch($weight_unit) {
case 'kg':
$product_weight = $weight;
break;
case 'g':
$product_weight = $weight / 1000;
break;
case 'lbs':
$product_weight = $weight * 0.45359237;
break;
case 'oz':
$product_weight = $weight * 0.0283495231;
break;
default:
$product_weight = $weight;
break;
}
$item_weight = (float) $product_weight * (int) $item['qty'];
return $item_weight;
}
public function get_item_weight_g($item, $order) {
$item_weight = $this->get_item_weight_kg($item, $order);
return $item_weight * 1000;
}
public function is_pickup($order, $postnl_delivery_options = '') {
if (empty($postnl_delivery_options)) {
$postnl_delivery_options = WCX_Order::get_meta($order, '_postnl_delivery_options');
}
$pickup_types = array('retail', 'retailexpress');
if ( ! empty($postnl_delivery_options['price_comment']) && in_array($postnl_delivery_options['price_comment'],$pickup_types)) {
return $postnl_delivery_options;
}
// Backwards compatibility for pakjegemak data
$pgaddress = WCX_Order::get_meta($order, '_postnl_pgaddress');
if ( ! empty($pgaddress) && ! empty($pgaddress['postcode'])) {
$pickup = array(
'postal_code' => $pgaddress['postcode'],
'street' => $pgaddress['street'],
'city' => $pgaddress['town'],
'number' => $pgaddress['house_number'],
'location' => $pgaddress['name'],
'price_comment' => 'retail',
);
return $pickup;
}
// no pickup
return false;
}
public function get_delivery_type($order, $postnl_delivery_options = '') {
// delivery types
$delivery_types = array(
'morning' => 1,
'standard' => 2, // 'default in JS API'
'avond' => 3,
'retail' => 4, // 'pickup'
'retailexpress' => 5, // 'pickup_express'
);
if (empty($postnl_delivery_options)) {
$postnl_delivery_options = WCX_Order::get_meta($order, '_postnl_delivery_options');
}
// standard = default, overwrite if options found
$delivery_type = 'standard';
if ( ! empty($postnl_delivery_options)) {
// pickup & pickup express store the delivery type in the delivery options,
// morning & night store it in the time data (...)
if (empty($postnl_delivery_options['price_comment']) && ! empty($postnl_delivery_options['time'])) {
// check if we have a price_comment in the time option
$delivery_time = array_shift($postnl_delivery_options['time']); // take first element in time array
if (isset($delivery_time['price_comment'])) {
$delivery_type = $delivery_time['price_comment'];
}
} else {
$delivery_type = $postnl_delivery_options['price_comment'];
}
}
// backwards compatibility for pakjegemak
if ($pgaddress = WCX_Order::get_meta($order, '_postnl_pgaddress')) {
$delivery_type = 'retail';
}
// convert to int (default to 2 = standard for unknown types)
$delivery_type = isset($delivery_types[$delivery_type]) ? $delivery_types[$delivery_type] : 2;
return $delivery_type;
}
/**
* @param $order
* @param $options
* @param string $postnl_delivery_options
*
* @return array|void
*/
public function get_age_check($order, $options, $postnl_delivery_options = '') {
if (empty($postnl_delivery_options)) {
$postnl_delivery_options = WCX_Order::get_meta($order, '_postnl_delivery_options');
}
$delivery_type = $this->get_delivery_type($order, $postnl_delivery_options);
$shipping_country = WCX_Order::get_prop($order, 'shipping_country');
if ( ! empty($postnl_delivery_options) && ! in_array($delivery_type, array(1, 3)) && $shipping_country == 'NL' ) {
$age_check = $options['age_check'] = 1;
$signature = $options['signature'] = 1;
$only_recipient = $options['only_recipient'] = 1;
return [$age_check, $signature, $only_recipient];
}
return;
}
public function get_delivery_date($order, $postnl_delivery_options = '') {
if (empty($postnl_delivery_options)) {
$postnl_delivery_options = WCX_Order::get_meta($order, '_postnl_delivery_options');
}
if ( ! empty($postnl_delivery_options) && ! empty($postnl_delivery_options['date'])) {
$delivery_date = $postnl_delivery_options['date'];
$delivery_type = $this->get_delivery_type($order, $postnl_delivery_options);
if (in_array($delivery_type, array(1, 3)) && ! empty($postnl_delivery_options['time'])) {
$delivery_time_options = array_shift(
$postnl_delivery_options['time']
); // take first element in time array
$delivery_time = $delivery_time_options['start'];
} else {
$delivery_time = '00:00:00';
}
$delivery_date = "{$delivery_date} {$delivery_time}";
return $delivery_date;
} else {
return false;
}
}
public function get_order_shipping_class($order, $shipping_method_id = '') {
if (empty($shipping_method_id)) {
$order_shipping_methods = $order->get_items('shipping');
if ( ! empty($order_shipping_methods)) {
// we're taking the first (we're not handling multiple shipping methods as of yet)
$order_shipping_method = array_shift($order_shipping_methods);
$shipping_method_id = $order_shipping_method['method_id'];
} else {
return false;
}
}
$shipping_method = $this->get_shipping_method($shipping_method_id);
if (empty($shipping_method)) {
return false;
}
// get shipping classes from order
$found_shipping_classes = $this->find_order_shipping_classes($order);
$highest_class = $this->get_shipping_class($shipping_method, $found_shipping_classes);
return $highest_class;
}
public function get_shipping_method($chosen_method) {
if (version_compare(WOOCOMMERCE_VERSION, '2.6', '>=') && $chosen_method !== 'legacy_flat_rate') {
$chosen_method = explode(':', $chosen_method); // slug:instance
// only for flat rate
if ($chosen_method[0] !== 'flat_rate') {
return false;
}
if (empty($chosen_method[1])) {
return false; // no instance known (=probably manual order)
}
$method_slug = $chosen_method[0];
$method_instance = $chosen_method[1];
$shipping_method = WC_Shipping_Zones::get_shipping_method($method_instance);
} else {
// only for flat rate or legacy flat rate
if ( ! in_array($chosen_method, array('flat_rate', 'legacy_flat_rate'))) {
return false;
}
$shipping_methods = WC()->shipping->load_shipping_methods($package);
if ( ! isset($shipping_methods[$chosen_method])) {
return false;
}
$shipping_method = $shipping_methods[$chosen_method];
}
return $shipping_method;
}
public function get_shipping_class($shipping_method, $found_shipping_classes) {
// get most expensive class
// adapted from $shipping_method->calculate_shipping()
$highest_class_cost = 0;
$highest_class = false;
foreach ( $found_shipping_classes as $shipping_class => $products ) {
// Also handles BW compatibility when slugs were used instead of ids
$shipping_class_term = get_term_by('slug', $shipping_class, 'product_shipping_class');
$shipping_class_term_id = '';
if ($shipping_class_term != null) {
$shipping_class_term_id = $shipping_class_term->term_id;
}
$class_cost_string = $shipping_class_term && $shipping_class_term_id
? $shipping_method->get_option('class_cost_' . $shipping_class_term_id, $shipping_method->get_option('class_cost_' . $shipping_class, $shipping_class_term_id))
: $shipping_method->get_option('no_class_cost', '');
if ($class_cost_string === '') {
continue;
}
$has_costs = true;
$class_cost = $this->wc_flat_rate_evaluate_cost(
$class_cost_string,
array(
'qty' => array_sum(wp_list_pluck($products, 'quantity')),
'cost' => array_sum(wp_list_pluck($products, 'line_total'))
),
$shipping_method
);
if ($class_cost > $highest_class_cost && ! empty($shipping_class_term_id)) {
$highest_class_cost = $class_cost;
$highest_class = $shipping_class_term_id;
}
}
return $highest_class;
}
public function find_order_shipping_classes($order) {
$found_shipping_classes = array();
$order_items = $order->get_items();
foreach ( $order_items as $item_id => $item ) {
$product = $order->get_product_from_item($item);
if ($product && $product->needs_shipping()) {
$found_class = $product->get_shipping_class();
if ( ! isset($found_shipping_classes[$found_class])) {
$found_shipping_classes[$found_class] = array();
}
// normally this should pass the $product object, but only in the checkout this contains
// quantity & line_total (which is all we need), so we pass data from the $item instead
$item_product = new stdClass;
$item_product->quantity = $item['qty'];
$item_product->line_total = $item['line_total'];
$found_shipping_classes[$found_class][$item_id] = $item_product;
}
}
return $found_shipping_classes;
}
/**
* Adapted from WC_Shipping_Flat_Rate - Protected method
* Evaluate a cost from a sum/string.
*
* @param string $sum
* @param array $args
*
* @return string
*/
public function wc_flat_rate_evaluate_cost($sum, $args, $flat_rate_method) {
if (version_compare(WOOCOMMERCE_VERSION, '2.6', '>=')) {
include_once(WC()->plugin_path() . '/includes/libraries/class-wc-eval-math.php');
} else {
include_once(WC()->plugin_path() . '/includes/shipping/flat-rate/includes/class-wc-eval-math.php');
}
// Allow 3rd parties to process shipping cost arguments
$args = apply_filters('woocommerce_evaluate_shipping_cost_args', $args, $sum, $flat_rate_method);
$locale = localeconv();
$decimals = array(
wc_get_price_decimal_separator(),
$locale['decimal_point'],
$locale['mon_decimal_point'],
','
);
$this->fee_cost = $args['cost'];
// Expand shortcodes
add_shortcode('fee', array($this, 'wc_flat_rate_fee'));
$sum = do_shortcode(
str_replace(
array('[qty]', '[cost]'),
array($args['qty'], $args['cost']),
$sum
)
);
remove_shortcode('fee', array($this, 'wc_flat_rate_fee'));
// Remove whitespace from string
$sum = preg_replace('/\s+/', '', $sum);
// Remove locale from string
$sum = str_replace($decimals, '.', $sum);
// Trim invalid start/end characters
$sum = rtrim(ltrim($sum, "\t\n\r\0\x0B+*/"), "\t\n\r\0\x0B+-*/");
// Do the math
return $sum ? WC_Eval_Math::evaluate($sum) : 0;
}
/**
* Adapted from WC_Shipping_Flat_Rate - Protected method
* Work out fee (shortcode).
*
* @param array $atts
*
* @return string
*/
public function wc_flat_rate_fee($atts) {
$atts = shortcode_atts(
array(
'percent' => '',
'min_fee' => '',
'max_fee' => '',
),
$atts
);
$calculated_fee = 0;
if ($atts['percent']) {
$calculated_fee = $this->fee_cost * (floatval($atts['percent']) / 100);
}
if ($atts['min_fee'] && $calculated_fee < $atts['min_fee']) {
$calculated_fee = $atts['min_fee'];
}
if ($atts['max_fee'] && $calculated_fee > $atts['max_fee']) {
$calculated_fee = $atts['max_fee'];
}
return $calculated_fee;
}
public function filter_postnl_destination_orders($order_ids) {
foreach ( $order_ids as $key => $order_id ) {
$order = WCX::get_order($order_id);
$shipping_country = WCX_Order::get_prop($order, 'shipping_country');
// skip non-postnl destination orders
if ( ! $this->is_postnl_destination($shipping_country)) {
unset($order_ids[$key]);
}
}
return $order_ids;
}
public function is_postnl_destination($country_code) {
return ($country_code == 'NL' || $this->is_eu_country($country_code)
|| $this->is_world_shipment_country(
$country_code
));
}
public function is_eu_country($country_code) {
$euro_countries = array('AT','BE','BG','CZ','DK','EE','FI','FR','DE','GR','HU','IE','IT','LV','LT','LU','PL','PT','RO','SK','SI','ES','SE','MC','AL','AD','BA','IC','FO','GB','GI','GL','GG','JE','HR','LI','MK','MD','ME','UA','SM','RS','VA','BY');
return in_array($country_code, $euro_countries);
}
public function is_world_shipment_country($country_code) {
$world_shipment_countries = array('AF','AQ','DZ','VI','AO','AG','AR','AM','AW','AU','AZ','BS','BH','BD','BB','BZ','BJ','BM','BT','BO','BW','BR','VG','BN','BF','BI','KH','CA','KY','CF','CL','CN','CO','KM','CG','CD','CR','CU','DJ','DM','DO','EC','EG','SV','GQ','ER','ET','FK','FJ','PH','GF','PF','GA','GM','GE','GH','GD','GP','GT','GN','GW','GY','HT','HN','HK','IN','ID','IS','IQ','IR','IL','CI','JM','JP','YE','JO','CV','CM','KZ','KE','KG','KI','KW','LA','LS','LB','LR','LY','MO','MG','MW','MV','MY','ML','MA','MQ','MR','MU','MX','MN','MS','MZ','MM','NA','NR','NP','NI','NC','NZ','NE','NG','KP','UZ','OM','TL','PK','PA','PG','PY','PE','PN','PR','QA','RE','RU','RW','KN','LC','VC','PM','WS','ST','SA','SN','SC','SL','SG','SO','LK','SD','SR','SZ','SY','TJ','TW','TZ','TH','TG','TO','TT','TD','TN','TM','TC','TV','UG','UY','VU','VE','AE','US','VN','ZM','ZW','ZA','KR','AN','BQ','CW','SX','XK','IM','MT','CY','CH','TR','NO');
return in_array($country_code, $world_shipment_countries);
}
public function get_invoice_number($order) {
return (string) apply_filters('wc_postnl_invoice_number', $order->get_order_number());
}
public function log($message) {
if (isset(WooCommerce_PostNL()->general_settings['error_logging'])) {
// Starting with WooCommerce 3.0, logging can be grouped by context and severity.
if (class_exists('WC_Logger') && version_compare(WOOCOMMERCE_VERSION, '3.0', '>=')) {
$logger = wc_get_logger();
$logger->debug( $message, array( 'source' => 'wc-postnl' ) );
return;
}
if (class_exists('WC_Logger')) {
$wc_logger = function_exists('wc_get_logger') ? wc_get_logger() : new WC_Logger();
$wc_logger->add('wc-postnl', $message);
return;
}
// Old WC versions didn't have a logger
// log file in upload folder - wp-content/uploads
$upload_dir = wp_upload_dir();
$upload_base = trailingslashit($upload_dir['basedir']);
$log_file = $upload_base . 'postnl_log.txt';
$current_date_time = date("Y-m-d H:i:s");
$message = $current_date_time . ' ' . $message . "\n";
file_put_contents($log_file, $message, FILE_APPEND);
return;
}
}
private function get_shipment_barcode_from_postnl_api($shipment_id) {
$api = $this->init_api();
$response = $api->get_shipments($shipment_id);
if ( ! isset($response['body']['data']['shipments'][0]['barcode'])) {
throw new \ErrorException('No PostNL barcode found for shipment id; ' . $shipment_id);
}
return $response['body']['data']['shipments'][0]['barcode'];
}
/**
* @param $selected_shipment_ids
* @param $shipment_id
* @param $order
*/
private function add_postnl_note_to_shipment($selected_shipment_ids, $shipment_id, $order) {
if ( ! in_array($shipment_id, $selected_shipment_ids)) {
return;
}
$barcode = $this->get_shipment_barcode_from_postnl_api($shipment_id);
$order->add_order_note($this->prefix_message . sprintf($barcode));
}
/**
* @param $shipping_method_id
* @param $package_type_shipping_methods
* @param $shipping_class
*
* @return bool
*/
private function isActiveMethod($shipping_method_id, $package_type_shipping_methods, $shipping_method_id_class, $shipping_class) {
//support WooCommerce flat rate
// check if we have a match with the predefined methods
if (in_array($shipping_method_id, $package_type_shipping_methods)) {
return true;
}
if (in_array($shipping_method_id_class, $package_type_shipping_methods)) {
return true;
}
// fallback to bare method (without class) (if bare method also defined in settings)
if ( ! empty($shipping_method_id_class) && in_array($shipping_method_id_class, $package_type_shipping_methods)) {
return true;
}
// support WooCommerce Table Rate Shipping by WooCommerce
if ( ! empty($shipping_class) && in_array($shipping_class, $package_type_shipping_methods)) {
return true;
}
// support WooCommerce Table Rate Shipping by Bolder Elements
$newShippingClass = str_replace(':', '_', $shipping_class);
if ( ! empty($shipping_class) && in_array($newShippingClass, $package_type_shipping_methods)) {
return true;
}
return false;
}
public static function get_tier_ranges($round = false) {
// same as in backoffice, average is value of option
$tier_ranges = array(
1 => array(
'min' => 0,
'max' => 21,
'average' => 15
),
2 => array(
'min' => 21,
'max' => 51,
'average' => 35
),
3 => array(
'min' => 51,
'max' => 101,
'average' => 75
),
4 => array(
'min' => 101,
'max' => 351,
'average' => 225
),
5 => array(
'min' => 351,
'max' => 2001,
'average' => 1175
)
);
// round values for display according to postnl standard
if ($round) {
foreach ($tier_ranges as &$tier_range) {
$tier_range['min'] = $tier_range['min'] > 0 ? $tier_range['min'] - 1 : $tier_range['min'];
$tier_range['max'] = $tier_range['max'] - 1;
}
}
return $tier_ranges;
}
public static function find_tier_range($weight) {
$current_range = false;
foreach (WooCommerce_PostNL_Export::get_tier_ranges() as $tier_range => $value) {
if ($weight >= $value['min'] && $weight < $value['max']) {
$current_range = $tier_range;
}
}
return $current_range;
}
}
endif; // class_exists
return new WooCommerce_PostNL_Export();