You are here

uc_taxes.test in Ubercart 7.3

Tax tests.

File

uc_taxes/tests/uc_taxes.test
View source
<?php

/**
 * @file
 * Tax tests.
 */

/**
 * Tests the tax functionality.
 */
class UbercartTaxesTestCase extends UbercartTestHelper {
  public static function getInfo() {
    return array(
      'name' => 'Taxes',
      'description' => 'Ensures that taxes are calculated, stored and displayed correctly.',
      'group' => 'Ubercart',
    );
  }

  /**
   * Overrides DrupalWebTestCase::setUp().
   */
  protected function setUp($modules = array(), $permissions = array()) {
    $modules = array(
      'uc_product_kit',
      'uc_attribute',
      'uc_cart',
      'uc_payment',
      'uc_payment_pack',
      'uc_taxes',
    );
    $permissions = array(
      'bypass node access',
      'administer content types',
      'administer rules',
      'configure taxes',
    );
    parent::setUp($modules, $permissions);
  }
  public function testInclusiveTaxes() {
    $this
      ->drupalLogin($this->adminUser);

    // Create a 20% inclusive tax rate.
    $rate = (object) array(
      'name' => $this
        ->randomName(8),
      'rate' => 0.2,
      'taxed_product_types' => array(
        'product',
      ),
      'taxed_line_items' => array(),
      'weight' => 0,
      'shippable' => 0,
      'display_include' => 1,
      'inclusion_text' => $this
        ->randomName(6),
    );
    uc_taxes_rate_save($rate);

    // Ensure Rules picks up the new condition.
    entity_flush_caches();

    // Create a $10 product.
    $product = $this
      ->createProduct(array(
      'sell_price' => 10,
    ));

    // Create an attribute.
    $attribute = (object) array(
      'name' => $this
        ->randomName(8),
      'label' => $this
        ->randomName(8),
      'description' => $this
        ->randomName(8),
      'required' => TRUE,
      'display' => 1,
      'ordering' => 0,
    );
    uc_attribute_save($attribute);

    // Create an option with a price adjustment of $5.
    $option = (object) array(
      'aid' => $attribute->aid,
      'name' => $this
        ->randomName(8),
      'cost' => 0,
      'price' => 5,
      'weight' => 0,
      'ordering' => 0,
    );
    uc_attribute_option_save($option);

    // Attach the attribute to the product.
    $attribute = uc_attribute_load($attribute->aid);
    uc_attribute_subject_save($attribute, 'product', $product->nid, TRUE);

    // Create a product kit containing the product.
    $kit = $this
      ->drupalCreateNode(array(
      'type' => 'product_kit',
      'products' => array(
        $product->nid,
      ),
      'ordering' => 0,
      'mutable' => UC_PRODUCT_KIT_UNMUTABLE_WITH_LIST,
      'default_qty' => 1,
    ));

    // Set the kit total to $9 to automatically apply a discount.
    $kit = node_load($kit->nid);
    $kit->kit_total = 9;
    node_save($kit);
    $kit = node_load($kit->nid);
    $this
      ->assertEqual($kit->products[$product->nid]->discount, -1, 'Product kit component has correct discount applied.');

    // Ensure the price is displayed tax-inclusively on the add-to-cart form.
    $this
      ->drupalGet('node/' . $kit->nid);
    $this
      ->assertText('$10.80' . $rate->inclusion_text, 'Tax inclusive price on node-view form is accurate.');

    // $10.80 = $9.00 + 20%
    $this
      ->assertRaw($option->name . ', +$6.00</option>', 'Tax inclusive option price on node view form is accurate.');

    // $6.00 = $5.00 + 20%
    // Add the product kit to the cart, selecting the option.
    $attribute_key = 'products[' . $product->nid . '][attributes][' . $attribute->aid . ']';
    $this
      ->drupalPost('node/' . $kit->nid, array(
      $attribute_key => $option->oid,
    ), t('Add to cart'));

    // Check that the subtotal is $16.80 ($10 base + $5 option - $1 discount, with 20% tax)
    $this
      ->drupalGet('cart');
    $this
      ->assertText('Subtotal: $16.80', 'Order subtotal is correct on cart page.');

    // Make sure that the subtotal is also correct on the checkout page.
    $this
      ->drupalPost('cart', array(), 'Checkout');
    $this
      ->assertText('Subtotal: $16.80', 'Order subtotal is correct on checkout page.');

    // Manually proceed to checkout review.
    $zone_id = db_query_range('SELECT zone_id FROM {uc_zones} WHERE zone_country_id = :country ORDER BY rand()', 0, 1, array(
      'country' => variable_get('uc_store_country', 840),
    ))
      ->fetchField();
    $edit = array(
      'panes[delivery][delivery_first_name]' => $this
        ->randomName(10),
      'panes[delivery][delivery_last_name]' => $this
        ->randomName(10),
      'panes[delivery][delivery_street1]' => $this
        ->randomName(10),
      'panes[delivery][delivery_city]' => $this
        ->randomName(10),
      'panes[delivery][delivery_zone]' => $zone_id,
      'panes[delivery][delivery_postal_code]' => mt_rand(10000, 99999),
      'panes[billing][billing_first_name]' => $this
        ->randomName(10),
      'panes[billing][billing_last_name]' => $this
        ->randomName(10),
      'panes[billing][billing_street1]' => $this
        ->randomName(10),
      'panes[billing][billing_city]' => $this
        ->randomName(10),
      'panes[billing][billing_zone]' => $zone_id,
      'panes[billing][billing_postal_code]' => mt_rand(10000, 99999),
    );
    $this
      ->drupalPost('cart/checkout', $edit, t('Review order'));
    $this
      ->assertRaw(t('Your order is almost complete.'));

    // Make sure the price is still listed tax-inclusively.
    // !TODO This could be handled more specifically with a regex.
    $this
      ->assertText('$16.80' . $rate->inclusion_text, 'Tax inclusive price appears in cart pane on checkout review page');

    // Ensure the tax-inclusive price is listed on the order admin page.
    $order_id = db_query("SELECT order_id FROM {uc_orders} WHERE delivery_first_name = :name", array(
      ':name' => $edit['panes[delivery][delivery_first_name]'],
    ))
      ->fetchField();
    $this
      ->assertTrue($order_id, 'Order was created successfully');
    $this
      ->drupalGet('admin/store/orders/' . $order_id);
    $this
      ->assertText('$16.80' . $rate->inclusion_text, 'Tax inclusive price appears on the order view page.');

    // And on the invoice.
    $this
      ->drupalGet('admin/store/orders/' . $order_id . '/invoice');
    $this
      ->assertText('$16.80' . $rate->inclusion_text, 'Tax inclusive price appears on the invoice.');

    // And on the printable invoice.
    $this
      ->drupalGet('admin/store/orders/' . $order_id . '/invoice');
    $this
      ->assertText('$16.80' . $rate->inclusion_text, 'Tax inclusive price appears on the printable invoice.');
  }
  protected function loadTaxLine($order_id) {
    $order = uc_order_load($order_id, TRUE);
    foreach ($order->line_items as $line) {
      if ($line['type'] == 'tax') {
        return $line;
      }
    }
    return FALSE;
  }
  protected function assertTaxLineCorrect($line, $rate, $when) {
    $this
      ->assertTrue($line, t('The tax line item was saved to the order ' . $when));
    $this
      ->assertTrue(number_format($rate * $this->product->sell_price, 2) == number_format($line['amount'], 2), t('Stored tax line item has the correct amount ' . $when));
    $this
      ->assertFieldByName('line_items[' . $line['line_item_id'] . '][li_id]', $line['line_item_id'], t('Found the tax line item ID ' . $when));
    $this
      ->assertText($line['title'], t('Found the tax title ' . $when));
    $this
      ->assertText(uc_currency_format($line['amount']), t('Tax display has the correct amount ' . $when));
  }
  public function testStoredTaxDisplay() {
    $this
      ->drupalLogin($this->adminUser);

    // Enable a payment method for the payment preview checkout pane.
    $edit = array(
      'uc_payment_method_check_checkout' => 1,
    );
    $this
      ->drupalPost('admin/store/settings/payment', $edit, t('Save configuration'));

    // Create a 20% inclusive tax rate.
    $rate = (object) array(
      'name' => $this
        ->randomName(8),
      'rate' => 0.2,
      'taxed_product_types' => array(
        'product',
      ),
      'taxed_line_items' => array(),
      'weight' => 0,
      'shippable' => 0,
      'display_include' => 1,
      'inclusion_text' => '',
    );
    uc_taxes_rate_save($rate);
    $this
      ->drupalGet('admin/store/settings/taxes');
    $this
      ->assertText($rate->name, t('Tax was saved successfully.'));
    $this
      ->drupalGet("admin/store/settings/taxes/manage/uc_taxes_{$rate->id}");
    $this
      ->assertText(t('Conditions'), t('Rules configuration linked to tax.'));
    $this
      ->drupalPost('node/' . $this->product->nid, array(), t('Add to cart'));

    // Manually step through checkout. $this->checkout() doesn't know about taxes.
    $this
      ->drupalPost('cart', array(), 'Checkout');
    $this
      ->assertText(t('Enter your billing address and information here.'), t('Viewed cart page: Billing pane has been displayed.'));
    $this
      ->assertRaw($rate->name, t('Tax line item displayed.'));
    $this
      ->assertRaw(uc_currency_format($rate->rate * $this->product->sell_price), t('Correct tax amount displayed.'));

    // Build the panes.
    $zone_id = db_query_range('SELECT zone_id FROM {uc_zones} WHERE zone_country_id = :country ORDER BY rand()', 0, 1, array(
      'country' => variable_get('uc_store_country', 840),
    ))
      ->fetchField();
    $edit = array(
      'panes[delivery][delivery_first_name]' => $this
        ->randomName(10),
      'panes[delivery][delivery_last_name]' => $this
        ->randomName(10),
      'panes[delivery][delivery_street1]' => $this
        ->randomName(10),
      'panes[delivery][delivery_city]' => $this
        ->randomName(10),
      'panes[delivery][delivery_zone]' => $zone_id,
      'panes[delivery][delivery_postal_code]' => mt_rand(10000, 99999),
      'panes[billing][billing_first_name]' => $this
        ->randomName(10),
      'panes[billing][billing_last_name]' => $this
        ->randomName(10),
      'panes[billing][billing_street1]' => $this
        ->randomName(10),
      'panes[billing][billing_city]' => $this
        ->randomName(10),
      'panes[billing][billing_zone]' => $zone_id,
      'panes[billing][billing_postal_code]' => mt_rand(10000, 99999),
    );

    // Submit the checkout page.
    $this
      ->drupalPost('cart/checkout', $edit, t('Review order'));
    $this
      ->assertRaw(t('Your order is almost complete.'));
    $this
      ->assertRaw($rate->name, t('Tax line item displayed.'));
    $this
      ->assertRaw(uc_currency_format($rate->rate * $this->product->sell_price), t('Correct tax amount displayed.'));

    // Complete the review page.
    $this
      ->drupalPost(NULL, array(), t('Submit order'));
    $order_id = db_query("SELECT order_id FROM {uc_orders} WHERE delivery_first_name = :name", array(
      ':name' => $edit['panes[delivery][delivery_first_name]'],
    ))
      ->fetchField();
    if ($order_id) {
      $this
        ->pass(t('Order %order_id has been created', array(
        '%order_id' => $order_id,
      )));
      $this
        ->drupalGet('admin/store/orders/' . $order_id . '/edit');
      $this
        ->assertTaxLineCorrect($this
        ->loadTaxLine($order_id), $rate->rate, 'on initial order load');
      $this
        ->drupalPost('admin/store/orders/' . $order_id . '/edit', array(), t('Submit changes'));
      $this
        ->assertText(t('Order changes saved.'));
      $this
        ->assertTaxLineCorrect($this
        ->loadTaxLine($order_id), $rate->rate, 'after saving order');

      // Change tax rate and ensure order doesn't change.
      $oldrate = $rate->rate;
      $rate->rate = 0.1;
      $rate = uc_taxes_rate_save($rate);

      // Save order because tax changes are only updated on save.
      $this
        ->drupalPost('admin/store/orders/' . $order_id . '/edit', array(), t('Submit changes'));
      $this
        ->assertText(t('Order changes saved.'));
      $this
        ->assertTaxLineCorrect($this
        ->loadTaxLine($order_id), $oldrate, 'after rate change');

      // Change taxable products and ensure order doesn't change.
      $class = $this
        ->createProductClass();
      $rate->taxed_product_types = array(
        $class->name,
      );
      uc_taxes_rate_save($rate);
      entity_flush_caches();
      $this
        ->drupalPost('admin/store/orders/' . $order_id . '/edit', array(), t('Submit changes'));
      $this
        ->assertText(t('Order changes saved.'));
      $this
        ->assertTaxLineCorrect($this
        ->loadTaxLine($order_id), $oldrate, 'after applicable product change');

      // Change order Status back to in_checkout and ensure tax-rate changes now update the order.
      uc_order_update_status($order_id, 'in_checkout');
      $this
        ->drupalPost('admin/store/orders/' . $order_id . '/edit', array(), t('Submit changes'));
      $this
        ->assertText(t('Order changes saved.'));
      $this
        ->assertFalse($this
        ->loadTaxLine($order_id), t('The tax line was removed from the order when order status changed back to in_checkout.'));

      // Restore taxable product and ensure new tax is added.
      $rate->taxed_product_types = array(
        'product',
      );
      uc_taxes_rate_save($rate);
      $this
        ->drupalPost('admin/store/orders/' . $order_id . '/edit', array(), t('Submit changes'));
      $this
        ->assertText(t('Order changes saved.'));
      $this
        ->assertTaxLineCorrect($this
        ->loadTaxLine($order_id), $rate->rate, 'when order status changed back to in_checkout');
    }
    else {
      $this
        ->fail(t('No order was created.'));
    }
  }
  public function testTaxProductClassUpdate() {
    $this
      ->drupalLogin($this->adminUser);

    // Create a new product class.
    $type = strtolower($this
      ->randomName(12));
    $edit = array(
      'pcid' => $type,
      'name' => $type,
      'description' => $this
        ->randomName(32),
    );
    $this
      ->drupalPost('admin/store/products/classes', $edit, t('Save'));
    node_types_rebuild();

    // Create a tax rate.
    $tax = $this
      ->randomName(8);
    $rate = (object) array(
      'id' => 0,
      // TODO: should not have to set this
      'name' => $tax,
      'rate' => rand(1, 20) / 10,
      'taxed_product_types' => array(
        $type,
      ),
      'taxed_line_items' => array(),
      'weight' => 0,
      'shippable' => 0,
    );
    uc_taxes_rate_save($rate);

    // Check that the tax rate shows up at checkout.
    $product = $this
      ->createProduct(array(
      'type' => $type,
    ));
    $this
      ->drupalPost('node/' . $product->nid, array(), t('Add to cart'));
    $this
      ->drupalGet('cart/checkout');
    $this
      ->assertText($tax, 'Tax line item displayed.');

    // Change the machine name of the product class.
    $new_type = strtolower($this
      ->randomName(12));
    $edit = array(
      'name' => $new_type,
      'type' => $new_type,
    );
    $this
      ->drupalPost('admin/structure/types/manage/' . $type, $edit, t('Save content type'));

    // Check that the tax rate still shows up at checkout.
    $this
      ->drupalPost('cart', array(), t('Remove'));
    $this
      ->drupalPost('node/' . $product->nid, array(), t('Add to cart'));
    $this
      ->drupalGet('cart/checkout');
    $this
      ->assertText($tax, 'Tax line item displayed after changing product class node type.');
  }

}

Classes

Namesort descending Description
UbercartTaxesTestCase Tests the tax functionality.