You are here

function uc_cybersource_calculate_tax in Ubercart 5

Same name and namespace in other branches
  1. 6.2 payment/uc_cybersource/uc_cybersource.module \uc_cybersource_calculate_tax()

Calculates taxes for an order using CyberSource's tax service.

Parameters

$order: An order object with address and product information.

Return value

An array of associative arrays representing tax information with the keys 'id', 'name', and 'amount'.

1 call to uc_cybersource_calculate_tax()
uc_cybersource_tax_test in payment/uc_cybersource/uc_cybersource.module

File

payment/uc_cybersource/uc_cybersource.module, line 716
A module used for CyberSource's Silent Order POST method of payment.

Code

function uc_cybersource_calculate_tax($order) {

  // Kick out if the tax service is not enabled.
  if (!variable_set('uc_cybersource_soap_tax_calculate', FALSE)) {
    return array();
  }

  // Check for compatibility.
  if (!class_exists('SoapClient') || !class_exists('DOMDocument')) {
    drupal_set_message(t('CyberSource needs PHP to have the SOAP and DOM extensions enabled.  Please talk to your system administrator to get this configured.'));
    return array();
  }
  if (!is_object($order)) {
    return array();
  }

  // Include the SOAP helper file.
  require_once drupal_get_path('module', 'uc_cybersource') . '/uc_cybersource.soap.inc';
  global $user;

  // Set the URL for the CyberSource SOAP Toolkit API WSDL.
  if (variable_get('uc_cybersource_server', 'test') == 'test') {
    $url = 'https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor/CyberSourceTransaction_1.38.wsdl';
  }
  else {
    $url = 'https://ics2ws.ic3.com/commerce/1.x/transactionProcessor/CyberSourceTransaction_1.38.wsdl';
  }

  // Variable currency... not used atm.
  $currency = variable_get('uc_cybersource_currency', 'usd');
  $billing_country = uc_get_country_data(array(
    'country_id' => $order->billing_country,
  ));
  $delivery_country = uc_get_country_data(array(
    'country_id' => $order->delivery_country,
  ));
  try {
    $soapClient = new CyberSourceSoapClient($url, array());
    $login = _uc_cybersource_soap_login_data();

    // Create the request with some meta data.
    $request = new stdClass();
    $request->merchantID = $login['merchant_id'];
    $request->merchantReferenceCode = $order->order_id;
    $request->clientLibrary = 'PHP';
    $request->clientLibraryVersion = phpversion();
    $request->clientEnvironment = php_uname();

    // Add the billing information.
    $billTo = new stdClass();
    $billTo->firstName = $order->billing_first_name;
    $billTo->lastName = $order->billing_last_name;
    $billTo->street1 = $order->billing_street1;
    if ($order->billing_street2) {
      $billTo->street2 = $order->billing_street2;
    }
    $billTo->city = $order->billing_city;
    $billTo->state = uc_get_zone_code($order->billing_zone);
    $billTo->postalCode = $order->billing_postal_code;
    $billTo->country = $billing_country[0]['country_iso_code_2'];
    if ($order->billing_phone) {
      $billTo->phoneNumber = $order->billing_phone;
    }
    $billTo->email = $order->primary_email;
    $billTo->customerID = $order->uid;
    $request->billTo = $billTo;

    // Add the shipping information.
    $shipTo = new stdClass();
    $shipTo->firstName = $order->delivery_first_name;
    $shipTo->lastName = $order->delivery_last_name;
    $shipTo->street1 = $order->delivery_street1;
    if ($order->billing_street2) {
      $shipTo->street2 = $order->delivery_street2;
    }
    $shipTo->city = $order->delivery_city;
    $shipTo->state = uc_get_zone_code($order->delivery_zone);
    $shipTo->postalCode = $order->delivery_postal_code;
    $shipTo->country = $delivery_country[0]['country_iso_code_2'];
    $shipTo->email = $order->primary_email;
    $request->shipTo = $shipTo;

    // Add the company's ship from information.
    $shipFrom = new stdClass();
    $shipFrom->firstName = variable_get('cs_ship_from_first_name', '');
    $shipFrom->lastName = variable_get('cs_ship_from_last_name', '');
    $shipFrom->street1 = variable_get('cs_ship_from_street1', '');
    $shipFrom->city = variable_get('cs_ship_from_city', '');
    $shipFrom->state = variable_get('cs_ship_from_zone', '');
    $shipFrom->postalCode = variable_get('cs_ship_from_postal_code', '');
    $shipFrom->country = variable_get('cs_ship_from_country', '');
    $shipFrom->email = variable_get('cs_ship_from_email', '');
    $request->shipFrom = $shipFrom;

    // TaxService
    // US product codes:
    // 70.280: Software Training Services
    // 81112201.121: Business Use Services and Upgrades via Elect Dnld
    // TODO: product code, international product code
    // TODO: invoiceHeader->invoiceDate: to get correct refund amounts
    // TODO: VAT
    $taxService = new stdClass();
    $taxService->nexus = 'MA CA';
    $taxService->orderOriginCity = $taxService->orderAcceptanceCity = $shipFrom->city;
    $taxService->orderOriginCountry = $taxService->orderAcceptanceCountry = $shipFrom->country;
    $taxService->orderOriginState = $taxService->orderAcceptanceState = $shipFrom->state;
    $taxService->orderOriginPostalCode = $taxService->orderAcceptancePostalCode = $shipFrom->postalCode;
    $taxService->sellerRegistration = 'XXX TODO';
    $taxService->run = 'true';
    $request->taxService = $taxService;

    // Add the order total information.
    $purchaseTotals = new stdClass();
    $purchaseTotals->currency = $currency;

    // Add the products to the request.
    $request->item = array();
    $counter = 0;

    // Add the products to the item array.
    foreach ($order->products as $product) {
      $obj = $request->item[] = new stdClass();
      $obj->productName = $product->title;
      $obj->unitPrice = $product->price;
      $obj->quantity = $product->qty;
      $obj->productSKU = $product->model;
      $obj->productCode = 'default';
      $obj->id = $counter;
      $counter++;
    }

    // drupal_set_message('<pre>Request: '. print_r($request, TRUE) .'</pre>');
    // Send the request to CyberSource and get the reply.
    $reply = $soapClient
      ->runTransaction($request);

    // drupal_set_message('<pre>Reply: '. print_r($reply, TRUE) .'</pre>');
  } catch (SoapFault $exception) {

    // Log and display errors if Ubercart is unable to connect via SOAP.
    watchdog('uc_cybersource', t('Unable to connect to CyberSource via SOAP.'), WATCHDOG_ERROR);
    drupal_set_message(t('We apologize for the delay, but we are unable to process your credit card at this time. Please <a href="!url">contact sales</a> to complete your order.', array(
      '!url' => url('contact'),
    )), 'error');
  }

  // Process a reply from CyberSource.
  if (isset($reply)) {
    $result = array();
    if ($reply->reasonCode == '100') {

      // Add a city tax if applicable.
      if (floatval($reply->taxReply->totalCityTaxAmount) > 0) {
        $result[] = array(
          'id' => 'city',
          'name' => t('@city city tax', array(
            '@city' => floatval($reply->taxReply->city),
          )),
          'amount' => floatval($reply->taxReply->totalCityTaxAmount),
        );
      }

      // Add a county tax if applicable.
      if (floatval($reply->taxReply->totalCountyTaxAmount) > 0) {
        $result[] = array(
          'id' => 'county',
          'name' => t('County tax'),
          'amount' => floatval($reply->taxReply->totalCountryTaxAmount),
        );
      }

      // Add a district tax if applicable.
      if (floatval($reply->taxReply->totalDistrictTaxAmount) > 0) {
        $result[] = array(
          'id' => 'district',
          'name' => t('District tax'),
          'amount' => floatval($reply->taxReply->totalDistrictTaxAmount),
        );
      }

      // Add a state tax if applicable.
      if (floatval($reply->taxReply->totalStateTaxAmount) > 0) {
        $result[] = array(
          'id' => 'state',
          'name' => t('@state state tax', array(
            '@state' => $reply->taxReply->state,
          )),
          'amount' => floatval($reply->taxReply->totalStateTaxAmount),
        );
      }

      // Verify that the component taxes equal the total.
      $total = 0;
      foreach ($result as $tax) {
        $total += $tax['amount'];
      }

      // If it doesn't, log an error message and simply return the total.
      if ($total != floatval($reply->taxReply->totalTaxAmount)) {
        watchdog('uc_cybersource', t('Tax calculation produced uneven results.  Expected a total of @total, received the following: @dump', array(
          '@total' => uc_currency_format($reply->taxReply->totalTaxAmount),
          '@dump' => '<pre>' . print_r($result, TRUE) . '</pre>',
        )), WATCHDOG_ERROR);
        $result = array(
          array(
            'id' => 'total',
            'name' => t('Tax'),
            'amount' => floatval($reply->taxReply->totalTaxAmount),
          ),
        );
      }
    }
    else {
      watchdog('uc_cybersource', t('Attempted to calculate taxes failed for order @order_id - reason @code', array(
        '@order_id' => $order->order_id,
        '@code' => $reply->reasonCode,
      )), WATCHDOG_ERROR);
    }
  }
  else {
    watchdog('uc_cybersource', t('Attempted to calculate taxes failed for order @order_id. No response returned from CyberSource.', array(
      '@order_id' => $order->order_id,
    )), WATCHDOG_ERROR);
    $result = array();
  }
  return $result;
}