123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331 |
- <?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().
- */
- function setUp() {
- $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);
- }
- 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.');
- }
- 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;
- }
- 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));
- }
- 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.'));
- }
- }
- 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.');
- }
- }
|