id = 'dots_ausm';
$this->method_title = __( 'Advanced USPS Shipping Method', 'advanced-usps-shipping-method' );
$this->method_description = __( 'The USPS extension obtains rates dynamically from the USPS API during cart/checkout.', 'advanced-usps-shipping-method' );
$this->services = include ADVANCED_USPS_SHIPPING_METHOD_DIR . '/includes/data-ausm-services.php';
$this->api_services = include ADVANCED_USPS_SHIPPING_METHOD_DIR . '/includes/data-ausm-api-services.php';
$this->init();
}
public function init(){
$this->ausm_admin_object = new Advanced_Usps_Shipping_Method_Admin( ADVANCED_USPS_SHIPPING_METHOD_SLUG, ADVANCED_USPS_SHIPPING_METHOD_VERSION );
$this->ausm_config = !empty(get_option('ausm_config')) ? get_option('ausm_config') : array();
$this->enabled = isset( $this->ausm_config['ausm_status'] ) && 'on' === $this->ausm_config['ausm_status'] ? 'yes' : 'no';
$this->request_mode = isset( $this->ausm_config['ausm_request_mode'] ) && !empty( $this->ausm_config['ausm_request_mode'] ) ? $this->ausm_config['ausm_request_mode'] : 'legacy';
$this->api_mode = isset( $this->ausm_config['ausm_api_mode'] ) && !empty( $this->ausm_config['ausm_api_mode'] ) ? $this->ausm_config['ausm_api_mode'] : 'sandbox';
$this->client_id = isset( $this->ausm_config['ausm_client_id'] ) && !empty( $this->ausm_config['ausm_client_id'] ) ? $this->ausm_config['ausm_client_id'] : '';
$this->client_secret = isset( $this->ausm_config['ausm_client_secret'] ) && !empty( $this->ausm_config['ausm_client_secret'] ) ? $this->ausm_config['ausm_client_secret'] : '';
$this->debug = isset( $this->ausm_config['ausm_debug_mode'] ) && 'on' === $this->ausm_config['ausm_debug_mode'] ? true : false;
$this->origin = isset( $this->ausm_config['ausm_origin'] ) && !empty( $this->ausm_config['ausm_origin'] ) ? $this->ausm_config['ausm_origin'] : (new WC_Countries())->get_base_postcode();
$this->user_id = isset( $this->ausm_config['ausm_user_id'] ) && !empty( $this->ausm_config['ausm_user_id'] ) ? $this->ausm_config['ausm_user_id'] : $this->default_user_id;
$this->custom_services = isset( $this->ausm_config['ausm_services'] ) && !empty( $this->ausm_config['ausm_services'] ) ? $this->ausm_config['ausm_services'] : array();
$this->api_custom_services = isset( $this->ausm_config['ausm_api_services'] ) && !empty( $this->ausm_config['ausm_api_services'] ) ? $this->ausm_config['ausm_api_services'] : array();
$this->title = isset( $this->ausm_config['ausm_default_title'] ) && !empty( $this->ausm_config['ausm_default_title'] ) ? $this->ausm_config['ausm_default_title'] : '';
$this->default_rate = isset( $this->ausm_config['ausm_default_rate'] ) && !empty( $this->ausm_config['ausm_default_rate'] ) ? $this->ausm_config['ausm_default_rate'] : '';
$this->cheapest_rate = isset( $this->ausm_config['ausm_cheapest_rate'] ) && ( 'on' === $this->ausm_config['ausm_cheapest_rate'] ) ? true : false;
$this->packing_method = 'per_item';
$this->rates_preference = isset( $this->ausm_config['ausm_rates_preference'] ) && !empty( $this->ausm_config['ausm_rates_preference'] ) ? $this->ausm_config['ausm_rates_preference'] : 'commercial';
$this->disable_commercial_rates = false;
}
/**
* Calculate_shipping function.
*
* @accesss public
* @param mixed $package
* @return void
*/
public function calculate_shipping( $package = array() ) {
if( $this->request_mode === 'api-base' ) {
$found_rates = $this->ausm_api_base_calculate_shipping( $package );
} else {
$found_rates = $this->ausm_legacy_calculate_shipping( $package );
}
// Add rates
if ( $found_rates ) {
if ( $this->cheapest_rate ) {
$cheapest_rate = '';
foreach ( $found_rates as $key => $rate ) {
if ( ! $cheapest_rate || $cheapest_rate['cost'] > $rate['cost'] ) {
$cheapest_rate = $rate;
}
}
// phpcs:ignore
// $cheapest_rate['label'] = $this->method_title;
$this->add_rate( $cheapest_rate );
} else {
uasort( $found_rates, array( $this, 'sort_rates' ) );
foreach ( $found_rates as $key => $rate ) {
$this->add_rate( $rate );
}
}
}
}
/**
* Prepare request for legacy SOAP call.
*
* @accesss public
* @param mixed $package
* @return Array found rates
*/
public function ausm_legacy_calculate_shipping( $package = array() ) {
global $woocommerce;
$domestic = in_array( $package['destination']['country'], $this->domestic, true ) ? true : false;
$this->debug( __( 'Advanced USPS debug mode is on - to hide these messages, turn debug mode off in the settings.', 'advanced-usps-shipping-method' ) );
$package_requests = $this->get_package_requests($package);
$api = $domestic ? 'RateV4' : 'IntlRateV2';
libxml_use_internal_errors( true );
if( $package_requests ) {
$request = '<' . $api . 'Request USERID="' . $this->user_id . '">' . "\n";
$request .= '2' . "\n";
foreach ( $package_requests as $key => $package_request ) {
$request .= $package_request['request_data'];
}
$request .= '' . $api . 'Request>' . "\n";
$request = 'API=' . $api . '&XML=' . str_replace( array( "\n", "\r" ), '', $request );
// phpcs:disable
// $transient = 'ausm_quote_' . md5( $request );
// $cached_response = get_transient( $transient );
$this->debug( 'Advanced USPS REQUEST:
' . print_r( htmlspecialchars( $request ), true ) . '
' );
// phpcs:enable
$response = wp_remote_post(
$this->endpoint,
array(
'timeout' => 3,
'sslverify' => 0,
'body' => $request,
)
);
if ( is_wp_error( $response ) ) {
$error_string = $response->get_error_message();
$this->debug( 'Advanced USPS REQUEST FAILED' . $error_string );
if ( $this->default_rate && ! empty( $this->custom_services ) ) {
$default_title = !empty($this->title) ? $this->title : $this->method_title;
$this->add_rate(
array(
'id' => $this->id . '_default_rate',
'label' => $default_title,
'cost' => $this->default_rate,
'sort' => 0,
)
);
}
$response = false;
} else {
$response = $response['body'];
// phpcs:ignore
$this->debug( 'Advanced USPS RESPONSE: ' . print_r( htmlspecialchars( $response ), true ) . '
' );
// phpcs:ignore
// set_transient( $transient, $response, DAY_IN_SECONDS * 30 );
}
if ( $response ) {
$usps_packages = simplexml_load_string( $response );
if ( ! ( $usps_packages ) ) {
$this->debug( 'Advanced Failed loading XML', 'error' );
}
if ( ! is_object( $usps_packages ) && ! is_a( $usps_packages, 'SimpleXMLElement' ) ) {
$this->debug( 'Advanced Invalid XML response format', 'error' );
}
if ( ! empty( $usps_packages ) ) {
foreach ( $usps_packages as $usps_package ) {
if ( ! $usps_package || ! is_object( $usps_package ) ) {
continue;
}
// Get package data
$data_parts = explode( ':', $usps_package->attributes()->ID );
if ( count( $data_parts ) < 6 ) {
$valid_response = false; // when the request has invalid ID or no valid address was found.
continue;
}
list( $package_item_id, $cart_item_qty, $package_length, $package_width, $package_height, $package_weight ) = $data_parts;
$quotes = $usps_package->children();
if ( $this->debug ) {
$found_quotes = array();
foreach ( $quotes as $quote ) {
// phpcs:disable
if ( $domestic ) {
$code = strval( $quote->attributes()->CLASSID );
$name = strip_tags( htmlspecialchars_decode( (string) $quote->{'MailService'} ) );
} else {
$code = strval( $quote->attributes()->ID );
$name = strip_tags( htmlspecialchars_decode( (string) $quote->{'SvcDescription'} ) );
}
// phpcs:enable
if ( $name && $code ) {
$found_quotes[ $code ] = $name;
} elseif ( $name ) {
$found_quotes[ $code . '-' . sanitize_title( $name ) ] = $name;
}
}
if ( $found_quotes ) {
ksort( $found_quotes );
$found_quotes_html = '';
foreach ( $found_quotes as $code => $name ) {
if ( ! strstr( $name, 'Flat Rate' ) ) {
$found_quotes_html .= '' . $code . ' - ' . $name . '';
}
}
$this->debug( 'Advanced The following quotes were returned by USPS: ' . $found_quotes_html . '
If any of these do not display, they may not be enabled in USPS settings.', 'success' );
}
}
// Loop our known services
foreach ( $this->services as $service => $values ) {
if ( $domestic && strpos( $service, 'D_' ) !== 0 ) {
continue;
}
if ( ! $domestic && strpos( $service, 'I_' ) !== 0 ) {
continue;
}
$default_title = ( !empty($this->title) ) ? ' (' . $this->title . ')' : '';
$rate_code = (string) $service;
$rate_id = $this->id . ':' . $rate_code;
$rate_name = (string) $values['name'] . $default_title;
$rate_cost = null;
$svc_commitment = null;
foreach ( $quotes as $quote ) {
if ( $domestic ) {
$code = strval( $quote->attributes()->CLASSID );
} else {
$code = strval( $quote->attributes()->ID );
}
if ( '' !== $code && in_array( $code, array_keys( $values['services'] ) ) ) { // phpcs:ignore
if ( $domestic ) {
if ( $this->disable_commercial_rates ) {
if ( ( (float) $quote->{'Rate'} ) > 0.0 ) {
$cost = (float) $quote->{'Rate'} * $cart_item_qty;
} else {
continue;
}
} else {
if ( ! empty( $quote->{'CommercialRate'} ) ) {
$cost = (float) $quote->{'CommercialRate'} * $cart_item_qty;
} else {
$cost = (float) $quote->{'Rate'} * $cart_item_qty;
}
}
} else {
if ( ! empty( $quote->{'CommercialPostage'} ) ) {
$cost = (float) $quote->{'CommercialPostage'} * $cart_item_qty;
} else {
$cost = (float) $quote->{'Postage'} * $cart_item_qty;
}
}
// Cost percentage adjustment
if ( ! empty( $this->custom_services[ $rate_code ][ $code ]['percentage'] ) ) {
$cost = round( $cost + ( $cost * ( floatval( $this->custom_services[ $rate_code ][ $code ]['percentage'] ) / 100 ) ), wc_get_price_decimals() );
}
// Cost price adjustment
if ( ! empty( $this->custom_services[ $rate_code ][ $code ]['price'] ) ) {
$cost = round( $cost + floatval( $this->custom_services[ $rate_code ][ $code ]['price'] ), wc_get_price_decimals() );
}
// Enabled check
if ( ! isset( $this->custom_services[ $rate_code ][ $code ] ) || empty( $this->custom_services[ $rate_code ][ $code ]['enabled'] ) ) {
continue;
}
if ( is_null( $rate_cost ) ) {
$rate_cost = $cost;
$svc_commitment = $quote->SvcCommitments;
} elseif ( $cost < $rate_cost ) {
$rate_cost = $cost;
$svc_commitment = $quote->SvcCommitments;
}
}
}
if ( $rate_cost ) {
if ( ! empty( $svc_commitment ) && strstr( $svc_commitment, 'days' ) ) {
$rate_name .= ' (' . current( explode( 'days', $svc_commitment ) ) . ' days)';
}
$this->prepare_rate( $rate_code, $rate_id, $rate_name, $rate_cost );
}
}
}
} else {
// No rates
$this->debug( 'Invalid request; no rates returned', 'error' );
}
}
}
// Ensure rates were found for all packages
if ( $this->found_rates ) {
foreach ( $this->found_rates as $key => $value ) {
if ( $value['packages'] < count( $package_requests ) ) {
$this->debug( "Unsetting {$key} - too few packages.", 'error' );
unset( $this->found_rates[ $key ] );
}
}
}
return $this->found_rates;
}
/**
* Prepare API package requests function.
*
* @accesss public
* @param mixed $package
* @return Array found rates
*/
public function ausm_api_base_calculate_shipping( $package = array() ) {
$domestic = in_array( $package['destination']['country'], $this->domestic, true ) ? true : false;
$this->debug( __( 'Advanced USPS debug mode is on - to hide these messages, turn debug mode off in the settings.', 'advanced-usps-shipping-method' ) );
$package_requests = $this->prepare_auth_package_requests( $package );
$stored_access_tokens = get_transient( 'ausm_api_auth_tokens' );
$token_hash = hash( 'sha256', $this->client_secret.$this->client_id );
$access_token = '';
if ( $stored_access_tokens
&& !empty($stored_access_tokens)
&& isset($stored_access_tokens[$token_hash])
&& isset($stored_access_tokens[$token_hash][$this->api_mode])
&& isset($stored_access_tokens[$token_hash][$this->api_mode]['access_token'])
&& !empty($stored_access_tokens[$token_hash][$this->api_mode]['access_token'])
) {
$access_token = $stored_access_tokens[$token_hash][$this->api_mode]['access_token'];
} else {
$access_token = $this->ausm_admin_object->ausm_fetch_usps_access_token( $this->client_id, $this->client_secret, $this->api_mode );
if( is_wp_error( $access_token ) ) {
$this->debug( 'Advanced USPS API REQUEST FAILED' . $access_token->get_error_message(), 'error' );
return false;
}
$stored_access_tokens = array();
$stored_access_tokens[$token_hash][$this->api_mode] = array(
'access_token' => $access_token,
'created_at' => time(),
);
set_transient( 'ausm_api_auth_tokens', $stored_access_tokens, 8 * HOUR_IN_SECONDS );
}
if ( 'production' === $this->api_mode ) {
$rates_endpoint_api = $domestic ? 'https://apis.usps.com/prices/v3/total-rates/search' : 'https://apis.usps.com/international-prices/v3/base-rates-list/search';
} else {
$rates_endpoint_api = $domestic ? 'https://apis-tem.usps.com/prices/v3/total-rates/search' : 'https://apis-tem.usps.com/international-prices/v3/base-rates-list/search';
}
$usps_package_total_weight = 0;
if ( $package_requests ) {
$usps_api_packages = array();
foreach ( $package_requests as $key => $package_request ) {
$usps_package_total_weight += $package_request['request_data']['weight'];
try {
$send_usps_request_encode = wp_json_encode( $package_request['request_data'] );
$response = wp_remote_post(
$rates_endpoint_api,
array(
'method' => 'POST',
'timeout' => 60, // phpcs:ignore
'blocking' => true,
'body' => $send_usps_request_encode,
'headers' => array(
'Authorization' => 'Bearer ' . $access_token,
'Content-Type' => 'application/json',
),
)
);
if ( is_wp_error( $response ) ) {
$error_string = $response->get_error_message();
$this->debug( 'Advanced USPS API REQUEST FAILED' . $error_string, 'error' );
if ( $this->default_rate && ! empty( $this->api_services ) ) {
$default_title = !empty($this->title) ? $this->title : $this->method_title;
$this->add_rate(
array(
'id' => $this->id . '_default_rate',
'label' => $default_title,
'cost' => $this->default_rate,
'sort' => 0,
)
);
}
$response = false;
throw new Exception( 'USPS response Failed' );
}
$response_body = json_decode( $response['body'] );
if ( isset( $response_body->fault ) ) {
throw new Exception( $response_body->fault->faultstring );
}
if ( isset( $response_body->error ) ) {
throw new Exception( $response_body->error->message );
}
$usps_api_packages[] = array(
'rates_response' => $response_body,
'product_info' => $package_request['package_info'],
);
} catch ( Exception $e ) {
$this->debug( 'Advanced USPS API REQUEST FAILED' . $e->getMessage(), 'error' );
if ( $this->default_rate && ! empty( $this->api_services ) ) {
$default_title = !empty($this->title) ? $this->title : $this->method_title;
$this->add_rate(
array(
'id' => $this->id . '_default_rate',
'label' => $default_title,
'cost' => $this->default_rate,
'sort' => 0,
)
);
}
}
}
$delivery_response = null;
if ( $domestic && isset( $this->estimated_delivery_date ) && 'yes' === $this->estimated_delivery_date ) {
$delivery_response = $this->prepare_auth_estimated_delivery_date_request( $package, $usps_package_total_weight );
$this->debug( 'USPS - Estimated Delivery Response: ' . print_r( $delivery_response, true ), 'notice' ); // phpcs:ignore
}
if ( ! empty( $usps_api_packages ) ) {
foreach ( $usps_api_packages as $usps_package ) {
$quotes = $usps_package['rates_response']->rateOptions;
foreach ( $this->api_services as $service => $values ) {
if ( $domestic && strpos( $service, 'D_' ) !== 0 ) {
continue;
}
if ( ! $domestic && strpos( $service, 'I_' ) !== 0 ) {
continue;
}
$rate_code = (string) $service;
$rate_id = $this->id . ':' . $rate_code;
$rate_name = (string) $values['name'] . ' (' . $this->title . ')';
$rate_cost = null;
$svc_commitment = null;
$rate_delivery = null;
$cart_item_qty = $usps_package['product_info']['items']['qty'];
foreach ( $quotes as $quote ) {
$code_zone = $quote->rates[0]->SKU;
$code = substr( $code_zone, 0, 9 );
if ( 'DUXR0XXXX' === $code || 'DPXR0XXXX' === $code || 'DEXR0XXXX' === $code ) {
$description = $quote->rates[0]->description;
if ( strpos( $description, 'Nonrectangular' ) > 0 ) {
$code .= '_1';
} else {
$code .= '_2';
}
}
if ( 'DUXP0XXXU' === $code ) {
$code = 'DUXP0XXXX';
}
if ( '' !== $code && in_array( $code, array_keys( $values['services'] ), true ) ) {
$cost = (float) $quote->rates[0]->price * $cart_item_qty;
$mailClass = $quote->rates[0]->mailClass;
$delivery_mailclasses = array( 'BOUND_PRINTED_MATTER', 'FIRST-CLASS_PACKAGE_SERVICE', 'LIBRARY_MAIL', 'MEDIA_MAIL', 'PARCEL_SELECT', 'PARCEL_SELECT_LIGHTWEIGHT', 'PRIORITY_MAIL', 'PRIORITY_MAIL_EXPRESS', 'USPS_GROUND_ADVANTAGE' );
if ( ! empty( $delivery_response ) ) {
if ( in_array( $mailClass, $delivery_mailclasses, true ) ) {
foreach ( $delivery_response as $delivery_data ) {
if ( $mailClass === $delivery_data->mailClass ) {
$rate_delivery = $delivery_data->delivery->scheduledDeliveryDateTime;
}
}
}
}
if ( isset( $this->api_custom_services[ $rate_code ][ $code ] ) && empty( $this->api_custom_services[ $rate_code ][ $code ]['enabled'] ) ) {
continue;
}
// Cost percentage adjustment
if ( ! empty( $this->api_custom_services[ $rate_code ][ $code ]['percentage'] ) ) {
$cost = round( $cost + ( $cost * ( floatval( $this->api_custom_services[ $rate_code ][ $code ]['percentage'] ) / 100 ) ), wc_get_price_decimals() );
}
// Cost price adjustment
if ( ! empty( $this->api_custom_services[ $rate_code ][ $code ]['price'] ) ) {
$cost = round( $cost + floatval( $this->api_custom_services[ $rate_code ][ $code ]['price'] ), wc_get_price_decimals() );
}
// phpcs:disable
// if ( $domestic ) {
// if ( 'DMXX0XXXU' == $code || 'DMXX0XXX5' == $code || 'DMXX0XXXB' == $code ) {
// if ( count( $this->mediamail_restriction ) > 0 ) {
// $invalid = false;
// foreach ( $package['contents'] as $package_item ) {
// if ( ! in_array( $package_item['data']->get_shipping_class_id(), $this->mediamail_restriction ) ) {
// // Checking if product is virutal. If it is,
// // then don't skip media mail.
// if ( ! $package_item['data']->is_virtual() ) {
// $invalid = true;
// }
// }
// }
// if ( $invalid ) {
// $this->debug( 'Skipping media mail', 'error' );
// continue 2;
// }
// }
// }
// }
// phpcs:enable
if ( is_null( $rate_cost ) ) {
$rate_cost = $cost;
} elseif ( $cost < $rate_cost ) {
$rate_cost = $cost;
}
}
}
if ( $rate_cost ) {
$this->prepare_rate_auth_api( $rate_code, $rate_id, $rate_name, $rate_cost, $rate_delivery );
}
}
}
} else {
$this->debug( 'Invalid request; no rates returned', 'error' );
}
if ( $this->found_rates ) {
foreach ( $this->found_rates as $key => $value ) {
if ( $value['packages'] < count( $package_requests ) ) {
$this->debug( sprintf( 'Unsetting {' . $key . '} - too few packages.' ), 'error' );
unset( $this->found_rates[ $key ] );
}
// phpcs:disable
// if ( $this->unpacked_item_costs && ! empty( $this->found_rates[ $key ] ) ) {
// $this->debug( sprintf( 'Adding unpacked item costs to rate %s', $key ), 'error' );
// $this->found_rates[ $key ]['cost'] += $this->unpacked_item_costs;
// }
// phpcs:enable
}
}
}
return $this->found_rates;
}
/**
* Prepare_rate function.
*
* @accesss private
* @param mixed $rate_code
* @param mixed $rate_id
* @param mixed $rate_name
* @param mixed $rate_cost
* @return void
*/
private function prepare_rate( $rate_code, $rate_id, $rate_name, $rate_cost ) {
// Name adjustment
if ( ! empty( $this->custom_services[ $rate_code ]['name'] ) ) {
$rate_name = $this->custom_services[ $rate_code ]['name'];
}
// Merging
if ( isset( $this->found_rates[ $rate_id ] ) ) {
$rate_cost = $rate_cost + $this->found_rates[ $rate_id ]['cost'];
$packages = 1 + $this->found_rates[ $rate_id ]['packages'];
} else {
$packages = 1;
}
// Sort
if ( isset( $this->custom_services[ $rate_code ]['order'] ) ) {
$sort = $this->custom_services[ $rate_code ]['order'];
} else {
$sort = 999;
}
$this->found_rates[ $rate_id ] = array(
'id' => $rate_id,
'label' => $rate_name,
'cost' => $rate_cost,
'sort' => $sort,
'packages' => $packages,
);
}
/**
* Sort_rates function.
*
* @accesss public
* @param mixed $a
* @param mixed $b
* @return void
*/
public function sort_rates( $a, $b ) {
if ( $a['sort'] === $b['sort'] ) {
return 0;
}
return ( $a['sort'] < $b['sort'] ) ? -1 : 1;
}
public function debug( $message, $type = 'notice' ) {
if ( $this->debug && ! is_admin() ) {
if ( version_compare( WOOCOMMERCE_VERSION, '2.1', '>=' ) ) {
wc_add_notice( $message, $type );
} else {
global $woocommerce;
$woocommerce->add_message( $message );
}
}
}
public function get_package_requests( $package ) {
// Choose selected packing
switch ( $this->packing_method ) {
case 'box_packing': //premium
$requests = $this->box_shipping__premium_only( $package ); // @phpstan-ignore-line
break;
case 'weight_based': //premium
$requests = $this->weight_based_shipping__premium_only( $package ); // @phpstan-ignore-line
break;
case 'per_item':
default:
$requests = $this->per_item_shipping( $package );
break;
}
return $requests;
}
/**
* Per_item_shipping function.
*
* @accesss private
* @param mixed $package
* @return array
*/
private function per_item_shipping( $package ) {
global $woocommerce;
$requests = array();
$domestic = in_array( $package['destination']['country'], $this->domestic, true ) ? true : false;
// Get weight of order
foreach ( $package['contents'] as $item_id => $values ) {
if ( ! $values['data']->needs_shipping() ) {
$this->debug( sprintf( wp_kses_post( '(#%s - %s) is virtual. Skipping...', 'advanced-usps-shipping-method' ), $values['data']->get_id(), $values['data']->get_title() ) );
continue;
}
$item_weight = !empty($values['data']->get_weight()) && $values['data']->get_weight() > 0 ? $values['data']->get_weight() : '';
if ( ! $item_weight ) {
$this->debug( sprintf( wp_kses_post( '(#%s - %s) is missing weight. We are assuming 1lb.', 'advanced-usps-shipping-method' ), $values['data']->get_id(), $values['data']->get_title() ) );
$weight = 1;
} else {
$weight = wc_get_weight( $item_weight, 'lbs' );
}
//Default we will use regular size
$size = 'REGULAR';
$item_length = $values['data']->get_length() ? $values['data']->get_length() : 0;
$item_width = $values['data']->get_width() ? $values['data']->get_width() : 0;
$item_height = $values['data']->get_height() ? $values['data']->get_height() : 0;
if( $item_length <= 0 ) {
$this->debug( sprintf( wp_kses_post( '(#%s - %s) is missing length. We are assuming 0.', 'advanced-usps-shipping-method' ), $values['data']->get_id(), $values['data']->get_title() ) );
}
if( $item_width <= 0 ) {
$this->debug( sprintf( wp_kses_post( '(#%s - %s) is missing width. We are assuming 0.', 'advanced-usps-shipping-method' ), $values['data']->get_id(), $values['data']->get_title() ) );
}
if( $item_height <= 0 ) {
$this->debug( sprintf( wp_kses_post( '(#%s - %s) is missing height. We are assuming 0.', 'advanced-usps-shipping-method' ), $values['data']->get_id(), $values['data']->get_title() ) );
}
if( $item_length > 0 || $item_width > 0 || $item_height > 0 ){
$dimensions = array( wc_get_dimension( $item_length, 'in' ), wc_get_dimension( $item_width, 'in' ), wc_get_dimension( $item_height, 'in' ) ); //we have converted these data from cm to inches
if ( max( $dimensions ) > 12 ) {
$size = 'LARGE';
}
} else {
$dimensions = array( 0, 0, 0 );
}
if ( $domestic ) {
$request = '' . "\n";
$request .= ' ' . ( $this->ausm_config['ausm_service_type'] ? $this->ausm_config['ausm_service_type'] : 'ONLINE' ) . '' . "\n";
$request .= ' ' . str_replace( ' ', '', strtoupper( $this->origin ) ) . '' . "\n";
$request .= ' ' . strtoupper( substr( $package['destination']['postcode'], 0, 5 ) ) . '' . "\n";
$request .= ' ' . floor( $weight ) . '' . "\n";
$request .= ' ' . number_format( wc_get_weight( $weight - floor( $weight ), 'oz', 'lbs'), 2 ) . '' . "\n";
if ( 'LARGE' === $size ) {
$request .= ' RECTANGULAR' . "\n";
} else {
$request .= ' ' . "\n";
}
$request .= ' ' . $size . '' . "\n";
$request .= ' ' . $dimensions[1] . '' . "\n";
$request .= ' ' . $dimensions[0] . '' . "\n";
$request .= ' ' . $dimensions[2] . '' . "\n";
$request .= ' ' . "\n";
$request .= ' true ' . "\n";
$request .= ' ' . gmdate( 'd-M-Y', ( current_time( 'timestamp' ) + ( 60 * 60 * 24 ) ) ) . '' . "\n";
$request .= '' . "\n";
} else {
$request = '' . "\n";
$request .= ' ' . floor( $weight ) . '' . "\n";
$request .= ' ' . number_format( wc_get_weight( $weight - floor( $weight ), 'oz', 'lbs'), 2 ) . '' . "\n";
$request .= ' true ' . "\n";
$request .= ' Package' . "\n";
$request .= ' ' . $values['data']->get_price() . '' . "\n";
$request .= ' ' . strtoupper( WC()->countries->countries[ $package['destination']['country'] ] ) . '' . "\n";
$request .= ' RECTANGULAR' . "\n";
$request .= ' ' . $size . '' . "\n";
$request .= ' ' . $dimensions[1] . '' . "\n";
$request .= ' ' . $dimensions[0] . '' . "\n";
$request .= ' ' . $dimensions[2] . '' . "\n";
$request .= ' ' . "\n";
$request .= ' ' . str_replace( ' ', '', strtoupper( $this->origin ) ) . '' . "\n";
$request .= ' ' . ( 'ONLINE' === $this->ausm_config['ausm_service_type'] ? 'Y' : 'N' ) . '' . "\n";
$request .= '' . "\n";
}
$item_data = $values['data'] ? $values['data'] : array();
$packed_items = array();
if ( $item_data ) {// Front-end price call doesn't need this data
$item_id = $item_data->get_id();
$packed_items[ $item_id ] = array(
'product_name' => $item_data->get_title(),
'qty' => 1,
);
if ( 'simple' !== $item_data->get_type() ) {
$packed_items[ $item_id ]['variation_text'] = $this->ausm_get_variation_data_from_variation_id( $item_data->get_id() );
}
}
$package_info = array(
'items' => $packed_items,
'dimension' => array(
'length' => $dimensions[0],
'width' => $dimensions[1],
'height' => $dimensions[2],
'weight' => $weight,
),
'units' => array(
'dimension' => 'in',
'weight' => 'lbs',
),
);
$requests[] = array(
'request_data' => $request,
'package_info' => $package_info,
);
}
return $requests;
}
/**
* Generate a package ID for the request
*
* Contains qty and dimension info so we can look at it again later when it comes back from USPS if needed
*
* @return string
*/
public function generate_package_id( $id, $qty, $length, $width, $height, $weight ) {
return implode( ':', array( $id, $qty, $length, $width, $height, $weight ) );
}
/**
* Return product variation details from variation ID
*
* Contains qty and dimension info so we can look at it again later when it comes back from USPS if needed
*
* @return string
*/
public function ausm_get_variation_data_from_variation_id( $item_id ) {
$_product = new WC_Product_Variation( $item_id );
$variation_data = $_product->get_variation_attributes();
$variation_detail = wc_get_formatted_variation( $variation_data, true ); // this will give all variation detail in one line
// $variation_detail = woocommerce_get_formatted_variation( $variation_data, false); // this will give all variation detail one by one
return $variation_detail; // $variation_detail will return string containing variation detail which can be used to print on website
// return $variation_data; // $variation_data will return only the data which can be used to store variation data
}
/**
* Prepare package requests function.
*
* @accesss public
* @param mixed $package
* @return Array request body
*/
public function prepare_auth_package_requests( $package ) {
$requests = array();
$domestic = in_array( $package['destination']['country'], $this->domestic, true ) ? true : false;
foreach ( $package['contents'] as $item_id => $values ) {
$packed_items = array();
$item_product_object = wc_get_product( $values['data'] );
if ( ! $item_product_object->needs_shipping() ) {
continue;
}
$weight = ! $item_product_object->get_weight() ? 1 : wc_get_weight( $item_product_object->get_weight(), 'lbs' );
$lenght = $item_product_object->get_length() ? wc_get_dimension( $item_product_object->get_length(), 'in' ) : 0;
$height = $item_product_object->get_height() ? wc_get_dimension( $item_product_object->get_height(), 'in' ) : 0;
$width = $item_product_object->get_width() ? wc_get_dimension( $item_product_object->get_width(), 'in' ) : 0;
$request_body = array();
if ( $domestic ) {
$request_body = array(
'originZIPCode' => str_replace( ' ', '', strtoupper( $this->origin ) ),
'destinationZIPCode' => strtoupper( substr( $package['destination']['postcode'], 0, 5 ) ),
'weight' => $weight,
'length' => floor( $lenght ),
'width' => floor( $width ),
'height' => floor( $height ),
'priceType' => ( 'commercial' === $this->rates_preference ? 'COMMERCIAL' : 'RETAIL' ),
'mailingDate' => $this->get_estimated_shipping_date(),
);
} else {
$request_body = array(
'originZIPCode' => str_replace( ' ', '', strtoupper( $this->origin ) ),
'foreignPostalCode' => strtoupper( substr( $package['destination']['postcode'], 0, 5 ) ),
'destinationCountryCode' => strtoupper( $package['destination']['country'] ),
'mailingDate' => $this->get_estimated_shipping_date(),
'weight' => $weight,
'length' => floor( $lenght ),
'width' => floor( $width ),
'height' => floor( $height ),
);
}
$item_data = wc_get_product( $values['product_id'] );
$packed_items = array(
'product_name' => $item_data->get_title(),
'product_id' => $values['product_id'],
'qty' => $values['quantity'],
);
$package_info = array(
'items' => $packed_items,
'dimension' => array(
'length' => $lenght,
'width' => $width,
'height' => $height,
'weight' => $weight,
),
'units' => array(
'dimension' => 'in',
'weight' => 'lbs',
),
);
$requests[] = array(
'request_data' => $request_body,
'package_info' => $package_info,
);
}
return $requests;
}
/**
* Get estimated shipping date function.
*
* @accesss public
* @return string
*/
public function get_estimated_shipping_date() {
//Estimated day and cut off time.
$timezone = new DateTimeZone( -5 ); // USPS is Working in central time (GMT-05:00)
$request_shipdate = wp_date( 'Y-m-d', null, $timezone );
return $request_shipdate;
}
public function prepare_auth_estimated_delivery_date_request( $package, $weight ) {
$stored_access_tokens = get_transient( 'ausm_api_auth_tokens' );
$token_hash = hash( 'sha256', $this->client_secret.$this->client_id );
$access_token = '';
if ( $stored_access_tokens
&& ! empty($stored_access_tokens)
&& isset($stored_access_tokens[$token_hash])
&& isset($stored_access_tokens[$token_hash][$this->api_mode])
&& isset($stored_access_tokens[$token_hash][$this->api_mode]['access_token'])
&& !empty($stored_access_tokens[$token_hash][$this->api_mode]['access_token'])
) {
$access_token = $stored_access_tokens[$token_hash][$this->api_mode]['access_token'];
} else {
$access_token = $this->ausm_admin_object->ausm_fetch_usps_access_token( $this->client_id, $this->client_secret, $this->api_mode );
if( is_wp_error( $access_token ) ) {
$this->debug( 'Advanced USPS API REQUEST FAILED' . $access_token->get_error_message(), 'error' );
return false;
}
$stored_access_tokens = array();
$stored_access_tokens[$token_hash][$this->api_mode] = array(
'access_token' => $access_token,
'created_at' => time(),
);
set_transient( 'ausm_api_auth_tokens', $stored_access_tokens, 8 * HOUR_IN_SECONDS );
}
$mailing_date = $this->get_estimated_shipping_date();
$delivery_request_body = array(
'originZIPCode' => str_replace( ' ', '', strtoupper( $this->origin ) ),
'destinationZIPCode' => strtoupper( substr( $package['destination']['postcode'], 0, 5 ) ),
'acceptanceDate' => $mailing_date,
'mailClass' => 'ALL',
'destinationType' => 'STREET',
'destinationEntryFacilityType' => 'NONE',
'weight' => $weight,
);
$delivery_usps_request_encode = http_build_query( $delivery_request_body );
if ( 'production' === $this->api_mode ) {
$delivery_endpoint_api = 'https://apis.usps.com/service-standards/v3/standards?' . $delivery_usps_request_encode ;
} else {
$delivery_endpoint_api = 'https://apis-tem.usps.com/service-standards/v3/estimates?' . $delivery_usps_request_encode;
}
$response = wp_remote_post(
$delivery_endpoint_api,
array(
'method' => 'GET',
'timeout' => 60, // phpcs:ignore
'blocking' => true,
'headers' => array(
'Authorization' => 'Bearer ' . $access_token,
'Content-Type' => 'application/json',
),
)
);
if ( is_wp_error( $response ) ) {
return null;
}
return json_decode( $response['body'] );
}
/**
* Prepare rate for API function.
*
* @accesss protected
* @param mixed $rate_code
* @param mixed $rate_id
* @param mixed $rate_name
* @param mixed $rate_cost
* @param mixed $delivery_date
* @return void
*/
protected function prepare_rate_auth_api( $rate_code, $rate_id, $rate_name, $rate_cost, $delivery_date ) {
// Name adjustment
if ( ! empty( $this->api_services[ $rate_code ]['name'] ) ) {
$rate_name = $this->api_services[ $rate_code ]['name'];
}
// Merging
if ( isset( $this->found_rates[ $rate_id ] ) ) {
$rate_cost = $rate_cost + $this->found_rates[ $rate_id ]['cost'];
$packages = 1 + $this->found_rates[ $rate_id ]['packages'];
} else {
$packages = 1;
}
// Sort
if ( isset( $this->api_services[ $rate_code ]['order'] ) ) {
$sort = $this->api_services[ $rate_code ]['order'];
} else {
$sort = 999;
}
$this->found_rates[ $rate_id ] = array(
'id' => $rate_id,
'label' => $rate_name,
'cost' => $rate_cost,
'sort' => $sort,
'meta_data' => array(
'usps_est_delivery_time' => $delivery_date,
),
'packages' => $packages,
);
}
}