<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

/*
 * Exp:Store module for ExpressionEngine 2.x by Crescendo (support@crescendo.net.nz)
 * Copyright (c) 2010-2012 Crescendo Multimedia Ltd
 * All rights reserved.
 */

class Store_shipping_ups extends Store_shipping_driver
{
	const PROCESS_URL = 'https://onlinetools.ups.com/ups.app/xml/Rate';
	const PROCESS_URL_TEST = 'https://wwwcie.ups.com/ups.app/xml/Rate';

	const CM_PER_INCH = 2.54;
	const LB_PER_KG = 0.45359237;

	public static $imperial_countries = array('us');

	public $default_settings = array(
		'access_key' => '',
		'user_id' => '',
		'password' => array('type' => 'password'),
		'pickup_type' => array('type' => 'select', 'default' => '01', 'options' => array(
			'01' => 'Daily Pickup',
			'03' => 'Customer Counter',
			'06' => 'One Time Pickup',
			'07' => 'On Call Air',
			'19' => 'Letter Center',
			'20' => 'Air Service Center')),
		'service' => array('type' => 'select', 'options' => array(
			''   => 'Any Available',
			'03' => 'Domestic Ground',
			'12' => 'Domestic 3 Day Select',
			'01' => 'Domestic Next Day Air',
			'14' => 'Domestic Next Day Air Early AM',
			'13' => 'Domestic Next Day Air Saver',
			'02' => 'Domestic Second Day Air',
			'59' => 'Domestic Second Day Air AM',
			'11' => 'International Standard',
			'65' => 'International Saver',
			'07' => 'International Worldwide Express',
			'54' => 'International Worldwide Express Plus',
			'08' => 'International Worldwide Expedited')),
		'packaging' => array('type' => 'select', 'default' => '02', 'options' => array(
			'02' => 'Package',
			'01' => 'UPS Letter',
			'03' => 'Tube',
			'04' => 'Pak',
			'25' => '10KG Box',
			'24' => '25KG Box',
			'30' => 'Pallet',
			'21' => 'Express Box',
			'2a' => 'Small Express Box',
			'2b' => 'Medium Express Box',
			'2c' => 'Large Express Box',
			'00' => 'Unknown')),
		'source_city' => '',
		'source_zip' => '',
		'source_country' => array('type' => 'select', 'options' => array('' => '')),
		'insure_order' => false,
		'test_mode' => true,
	);

	private $EE;

	public function __construct()
	{
		$this->EE =& get_instance();
		$this->default_settings['source_country']['options'] += $this->EE->store_shipping_model->countries;
	}

	public function calculate_shipping($order)
	{
		// don't bother unless we at least have a country, and city or ZIP
		if (empty($order['shipping_country'])) return 0;
		if (empty($order['shipping_postcode']) AND empty($order['shipping_address3'])) return 0;

		// prep UPS query
		$order_weight = $order['order_shipping_weight'];
		$weight_units = $this->EE->store_config->item('weight_units') == 'kg' ? 'KGS' : 'LBS';

		$order_length = $order['order_shipping_length'];
		$order_width = $order['order_shipping_width'];
		$order_height = $order['order_shipping_height'];
		$dimension_units = strtoupper($this->EE->store_config->item('dimension_units'));

		// normalize units
		if ($dimension_units == 'M')
		{
			$dimension_units = 'CM';
			$order_length = $order_length * 100;
			$order_width = $order_width * 100;
			$order_height = $order_height * 100;
		}
		elseif ($dimension_units == 'FT')
		{
			$dimension_units = 'IN';
			$order_length = $order_length * 12;
			$order_width = $order_width * 12;
			$order_height = $order_height * 12;
		}

		// US source address must use imperial units
		if (in_array($this->settings['source_country'], self::$imperial_countries))
		{
			if ($weight_units = 'KGS')
			{
				$weight_units = 'LBS';
				$order_weight = $order_weight * Store_shipping::LB_PER_KG;
			}
		}
		else
		{
			if ($weight_units = 'LBS')
			{
				$weight_units = 'KGS';
				$order_weight = $order_weight / Store_shipping::LB_PER_KG;
			}
		}

		// weight / dimension units must match
		if ($weight_units == 'LBS' AND $dimension_units == 'CM')
		{
			$dimension_units = 'IN';
			$order_length = $order_length / Store_shipping::CM_PER_INCH;
			$order_width = $order_width / Store_shipping::CM_PER_INCH;
			$order_height = $order_height / Store_shipping::CM_PER_INCH;
		}
		elseif ($weight_units == 'KGS' AND $dimension_units == 'IN')
		{
			$dimension_units = 'CM';
			$order_length = $order_length * Store_shipping::CM_PER_INCH;
			$order_width = $order_width * Store_shipping::CM_PER_INCH;
			$order_height = $order_height * Store_shipping::CM_PER_INCH;
		}

		// more UPS weirdness
		if ($this->settings['source_country'] == 'uk') $this->settings['source_country'] = 'gb';

		$order_weight = max($order_weight, 0.1);

		$insure_order = $this->settings['insure_order'] ? '<PackageServiceOptions><InsuredValue>
				<CurrencyCode>'.$this->EE->store_config->item('currency_code').'</CurrencyCode>
				<MonetaryValue>'.$order['order_total_val'].'</MonetaryValue>
			</InsuredValue></PackageServiceOptions>' : '';

		$request_option = $this->settings['service'] == '' ? 'Shop' : 'Rate';

		// generate request
		$request = '<?xml version="1.0" ?>
			<AccessRequest xml:lang="en-US">
				<AccessLicenseNumber>'.$this->settings['access_key'].'</AccessLicenseNumber>
				<UserId>'.$this->settings['user_id'].'</UserId>
				<Password>'.$this->settings['password'].'</Password>
			</AccessRequest>
			<RatingServiceSelectionRequest>
				<Request>
					<TransactionReference>
						<CustomerContext>Rating and Service</CustomerContext>
						<XpciVersion>1.0</XpciVersion>
					</TransactionReference>
					<RequestAction>Rate</RequestAction>
					<RequestOption>'.$request_option.'</RequestOption>
				</Request>
				<PickupType><Code>'.$this->settings['pickup_type'].'</Code></PickupType>
				<Shipment>
					<Shipper>
						<Address>
							<City>'.$this->settings['source_city'].'</City>
							<PostalCode>'.$this->settings['source_zip'].'</PostalCode>
							<CountryCode>'.strtoupper($this->settings['source_country']).'</CountryCode>
						</Address>
					</Shipper>
					<ShipTo>
						<PhoneNumber>'.$order['shipping_phone'].'</PhoneNumber>
						<Address>
							<AddressLine1>'.$order['shipping_address1'].'</AddressLine1>
							<AddressLine2>'.$order['shipping_address2'].'</AddressLine2>
							<City>'.$order['shipping_address3'].'</City>
							<StateProvinceCode>'.$order['shipping_region'].'</StateProvinceCode>
							<PostalCode>'.$order['shipping_postcode'].'</PostalCode>
							<CountryCode>'.strtoupper($order['shipping_country']).'</CountryCode>
						</Address>
					</ShipTo>
					<Service><Code>'.$this->settings['service'].'</Code></Service>
					<Package>
						<PackagingType>
							<Code>'.$this->settings['packaging'].'</Code>
						</PackagingType>
						<Dimensions>
							<UnitOfMeasurement><Code>'.$dimension_units.'</Code></UnitOfMeasurement>
							<Length>'.sprintf("%.1f", $order_length).'</Length>
							<Height>'.sprintf("%.1f", $order_height).'</Height>
							<Width>'.sprintf("%.1f", $order_width).'</Width>
						</Dimensions>
						<PackageWeight>
							<UnitOfMeasurement><Code>'.$weight_units.'</Code></UnitOfMeasurement>
							<Weight>'.sprintf("%.1f", $order_weight).'</Weight>
						</PackageWeight>
						'.$insure_order.'
					</Package>
				</Shipment>
			</RatingServiceSelectionRequest>';

		$this->EE->load->library('curl');

		$url = ($this->settings['test_mode']) ? self::PROCESS_URL_TEST : self::PROCESS_URL;
		$response = $this->EE->curl->simple_post($url, $request, array('ssl_verifypeer' => FALSE));

		if (empty($response))
		{
			return array('error:shipping_method' => lang('ups_communication_error'));
		}

		$xml = simplexml_load_string($response);
		if ((int)$xml->Response->ResponseStatusCode === 1)
		{
			return (float)$xml->RatedShipment->TotalCharges->MonetaryValue;
		}
		else
		{
			return array('error:shipping_method' => (string)$xml->Response->Error->ErrorDescription);
		}
	}
}

/* End of file ./plugins/shipping/default/default_shipping_plugin.php */