diff --git a/payment/uc_payment/tests/uc_payment.test b/payment/uc_payment/tests/uc_payment.test index 65e538a..ec30fb2 100644 --- a/payment/uc_payment/tests/uc_payment.test +++ b/payment/uc_payment/tests/uc_payment.test @@ -58,4 +58,38 @@ class UbercartPaymentPaneTestCase extends UbercartTestHelper { $this->drupalGet('cart/checkout'); $this->assertNoText('Order total:'); } + + /** + * Tests free orders. + */ + public function testFreeOrders() { + $free_product = $this->createProduct(array('sell_price' => 0)); + variable_set('uc_payment_method_check_checkout', TRUE); + + // Check that paid products cannot be purchased for free. + $this->drupalGet('cart/checkout'); + $this->assertText('Check or money order'); + $this->assertNoText('No payment required'); + $this->assertNoText('Subtotal: $0.00'); + + // Check that a mixture of free and paid products cannot be purchased for free. + $this->drupalPost('node/' . $free_product->nid, array(), t('Add to cart')); + $this->drupalGet('cart/checkout'); + $this->assertText('Check or money order'); + $this->assertNoText('No payment required'); + $this->assertNoText('Subtotal: $0.00'); + + // Check that free products can be purchased successfully with no payment. + $this->drupalPost('cart', array(), t('Remove')); + $this->drupalPost('cart', array(), t('Remove')); + $this->drupalPost('node/' . $free_product->nid, array(), t('Add to cart')); + $this->drupalGet('cart/checkout'); + $this->assertNoText('Check or money order'); + $this->assertText('No payment required'); + $this->assertText('Subtotal: $0.00'); + + // Check that this is the only available payment method. + $this->assertNoText('Select a payment method from the following options.'); + $this->assertFieldByXPath("//input[@name='panes[payment][payment_method]' and @disabled='disabled']"); + } } diff --git a/payment/uc_payment/uc_payment.api.php b/payment/uc_payment/uc_payment.api.php index b8a9ed0..cbf1be1 100644 --- a/payment/uc_payment/uc_payment.api.php +++ b/payment/uc_payment/uc_payment.api.php @@ -223,5 +223,21 @@ function hook_uc_payment_method_alter(&$methods) { } /** + * Alter payment methods available at checkout. + * + * @param $methods + * Array of payment methods passed by reference. Keys are payment method IDs, + * strings are payment method titles. + * @param $order + * The order that is being checked out. + */ +function hook_uc_payment_method_checkout_alter(&$methods, $order) { + // Remove the Check payment method for orders under $100. + if ($order->order_total < 100) { + unset($methods['check']); + } +} + +/** * @} End of "addtogroup hooks". */ diff --git a/payment/uc_payment/uc_payment.module b/payment/uc_payment/uc_payment.module index 9217e5d..b5d0363 100644 --- a/payment/uc_payment/uc_payment.module +++ b/payment/uc_payment/uc_payment.module @@ -236,6 +236,67 @@ function uc_payment_uc_order_state() { } /** + * Implements hook_uc_payment_method(). + */ +function uc_payment_uc_payment_method() { + $methods['free_order'] = array( + 'name' => t('Free order'), + 'title' => t('No payment required'), + 'desc' => t('Allow customers with !zero order totals to checkout without paying.', array('!zero' => uc_currency_format(0))), + 'callback' => 'uc_payment_method_free_order', + 'checkout' => TRUE, + 'no_gateway' => TRUE, + 'weight' => 0, + ); + + return $methods; +} + +/** + * Implements hook_uc_payment_method_checkout_alter(). + */ +function uc_payment_uc_payment_method_checkout_alter(&$methods, $order) { + if (isset($methods['free_order'])) { + if ($order->order_total < 0.01) { + // Unset all other payment methods if this is a free order. + foreach (array_keys($methods) as $key) { + if ($key != 'free_order') { + unset($methods[$key]); + } + } + } + else { + // Disallow this payment method if the order is not free. + unset($methods['free_order']); + } + } +} + +/** + * Payment method callback for free orders. + * + * @see uc_payment_uc_payment_method() + */ +function uc_payment_method_free_order($op, &$order) { + switch ($op) { + case 'cart-details': + return array( + '#markup' => t('Continue with checkout to complete your order.'), + ); + + case 'order-submit': + if ($order->order_total >= 0.01) { + return array(array( + 'pass' => FALSE, + 'message' => t('We cannot process your order without payment.'), + )); + } + + uc_payment_enter($order->order_id, 'free_order', 0, 0, NULL, t('Checkout completed for a free order.')); + } +} + +/** * Returns a formatted list of line items for an order total preview. * * @param $return diff --git a/payment/uc_payment/uc_payment_checkout_pane.inc b/payment/uc_payment/uc_payment_checkout_pane.inc index 35a280d..1b11f9a 100644 --- a/payment/uc_payment/uc_payment_checkout_pane.inc +++ b/payment/uc_payment/uc_payment_checkout_pane.inc @@ -41,6 +41,8 @@ function uc_checkout_pane_payment($op, &$order, $form = NULL, &$form_state = NUL } } + drupal_alter('uc_payment_method_checkout', $options, $order); + $description = ''; if (!$options) { $description = t('Checkout cannot be completed without any payment methods enabled. Please contact an administrator to resolve the issue.');