6

In a Travel Booking website, how can I configure checkout so that customers pay only a n% deposit of the order total at checkout (off-site payment ATOS solution) ?

If the order is created :

  • less than 30 days before departure, customer pay 100% of order total at checkout.
  • between 30 and 90 days before, they pay 30% at checkout.
  • more than 90 days before, they pay 10% at checkout.

Full settlement must be paid before travel departure (reminder emails)...

There are few contrib modules about deposit or partial payment :

  • I had a look at Commerce deposit sandbox but it seems to be a per product solution, while I need a global cart approach.
  • I began to hack Commerce Partial Payment for my own need. The module alters checkout_form_alter and provides a textfield where the customer can input a deposit value just before payment, so I pre-calculated deposit amount as per my rules above, filled the field with it, and hide it.

    /**
     * Implements hook_form_BASE_FORM_ID_alter().
     *
     * Alters whichever commerce checkout page includes the commerce_payment
     * checkout pane and adds the amount element to the payment details.
     */
    function commerce_partial_payment_form_commerce_checkout_form_alter(&$form, &$form_state, $form_id) {
    
      $panes = commerce_checkout_panes(array('pane_id' => 'commerce_payment'));
      $checkout_page = $panes['commerce_payment']['page'];
      if ($form_id != "commerce_checkout_form_$checkout_page" || !commerce_partial_payment_access($form_state['order'])) {
        return;
      }
    
      //setting up my own deposit value
      $deposit = vts_commerce_deposit();
    
      // If a values has already been set then use it as the value for the amount.
      // Otherwise, default it to the balance of the order.
      $default = NULL;
    
      if ($deposit > 0) {
         $default = $deposit ;
      }
      elseif (isset($form_state['values']['commerce_payment']['payment_details']['amount'])) {
        $default = $form_state['values']['commerce_payment']['payment_details']['amount'];
      }
      else {
        $balance = commerce_payment_order_balance($form_state['order']);
        $default = commerce_currency_amount_to_decimal($balance['amount'], $balance['currency_code']);
      }
    
      // Add the amount to the payment details form.
      $form['commerce_payment']['payment_details']['amount'] = array(
        '#type' => 'hidden',
        //'#title' => t('Amount'),
        '#weight' => -10,
        '#required' => TRUE,
        '#default_value' => $default,
      );
    }
    

But I got stuck there because that value, passed to $form['commerce_payment']['payment_details']['amount'], is not the one sent to the remote payment server (so that AFAIK, this module can't work)...

I also tried to set any other parts of checkout_form_alter ( $form and $form_state) where the order amount was repeated with $deposit, this NEVER changes the value set for payment at next step...

Question(s)

Using the above solution, at what point of checkout / which form can I alter the amount to be paid, replacing order total by deposit value ?

Indeed, I couldn't find how to separate the order total from the amount to pay... with correct data along the process : order total / paid deposit / balance order to pay later.

If there is a more D7 commerce way to implement this deposit issue, with rules or whatever, I'll be glad to learn it.

  • Did you get anywhere with this? Looking for a similar solution – Collins Dec 16 '14 at 15:39
  • Try if drupal.org/project/commerce_installments can help you – arpitr Sep 25 '15 at 15:14
  • 1
    @arpitr, IMO this is far away for why I'm looking for ? as per readme.txt, the feature provides two custom product types, masterinstallment has an installment field and is used for a first-payment of an installment plan. installmentpayment is the product used for an installment You have then to create products of 1st type, with fixed due date, which will create products of 2nd type when paid... I checked the code for ideas or reusability, but unfortunately, it seems to be a turn around very far from my issue ? Please tell me if I misunderstood – Kojo Sep 25 '15 at 19:34
  • 1
    Save the total amount to be paid and the amount paid in a custom table along with the order id. And assign the discounted amount value to the total amount value which will be sent to the Payment. – Kiran Tej Sep 28 '15 at 11:51
  • @KiranTej tks for your suggestion. One of the things I'm stuck with is precisely how to assign the discounted amount value to the total amount value which will be sent to the Payment Or said in other words where in the code can I alter the amount sent to payment ? Doesn't seem to be in checkout_form_alter – Kojo Sep 28 '15 at 12:49
4

I got it working the following way.

In order to get Commerce Deposit work with the deposit calculation you like to instead of a customer deposit input, patch it as following :

function commerce_partial_payment_form_commerce_checkout_form_alter(&$form, &$form_state, $form_id) {
  //... line 93
  $acompte = MODULENAME_deposit_calculation($form_state['order']) /100;
    if (!is_null($acompte) && $acompte > 0) {
      $default = $acompte;
    }
  //... line 109 Add the amount to the payment details form,in a hidden field.
  $form['commerce_payment']['payment_details']['amount'] = array(
    '#type' => 'hidden',
  //...
}

function commerce_partial_payment_checkout_validate($form, &$form_state, $checkout_pane, $order) {
  //... line 261
  $amount['amount'] = MODULENAME_deposit_calculation($order)  /100;
  //...
}

function commerce_partial_payment_checkout_submit($form, &$form_state, $checkout_pane, $order) {
  //...line 317
  if ($pane_values['payment_methods']) {
    $amount = MODULENAME_deposit_calculation($order) /100;
    $order->data['atos']['request']['amount'] = $amount;
    if (!empty( $amount)){
      $amount['amount'] = $amount;
  //...
}

As the sandbox doesn't properly send the deposit amount to off site payment, we need to hook the payment method :

In a METHOD_PAYMENT.api.php file

function hook_METHOD_PAYMENT_request_alter(&$settings) {
  //no example
}

Now send to off site payment the deposit amount instead of order total :

function commerce_partial_payment_PAYMENT_METHOD_request_alter(&$settings) {
  $order = commerce_order_load($settings['order_id']);
  $deposit = MODULENAME_deposit_calculation($order);
  $settings['amount'] = $deposit;
}

Last, add a price component deposit below Total to inform the customer what he's going to pay.

function commerce_partial_payment_commerce_price_formatted_components_alter(&$components, $price, $entity) {
  //Add a deposit line to price components
  $deposit= MODULENAME_deposit_calculation($entity);

  $components['deposit'] = array(
      'title' => t('Deposit'),
      'price' => array(
        'amount' => $deposit,
        'currency_code' => $components['commerce_price_formatted_amount']['price']['currency_code'],
        'data' => '',
      ),      
    'weight' => '200',
  );
}
0

I think that alter the form at checkout is not the place that interests your payment method ; only the total amount in the actual order is taken in account, imo.

So what you have to do is alter it at checkout form submit, either with custom module or rules.

The data taken in account is $order->commerce_order_total['und'][0]['amount']

  • Merci ! Could you develop a bit and give a coding ex please ? Do you mean I have to add a callback fn to checkout form submit ? AFAIK if I alter $order->commerce_order_total['und'][0]['amount'] before forwarding to payment, it will appear modified in review total display, and also in cart if the client goes back to change sthing. The desire feature is that I alter the amount for payment but still display the total, not the deposit value, in order total (I display the deposit value in a price component line below total...) Hope it's clear enough. Tks again for your contribution – Kojo Sep 30 '15 at 11:32
  • "Partial payment" is closed and "won't fix". (see drupal.org/node/1096504) . I guess the easiest solution for you would be to duplicate original total price in a separate field like Kiran said, and use that data in your backoffice instead of the order total price... Be careful though ; Commerce might use the added totals of each commerce line instead of order total to calculate the price to be paid. – Gregory Kapustin Sep 30 '15 at 13:14
  • I 've read the issue you link to some time ago : it is not about the sandbox I'm using, but a Commerce core issue, tagged as won't fix because, as per Rszrama 3 years ago no easy ideas come to mind for how we could make this abstract enough to solve in core . Surely there are several ways to fix that, included Kiran's one, if he's able to precise where to assign the discounted amount value to the total amount value which will be sent to the Payment . At the moment this is a blocking point. Thank you . – Kojo Sep 30 '15 at 13:37
  • I make a few tests on my own to see if it's the order total or the sum of the commerce lines and i come back to you. – Gregory Kapustin Sep 30 '15 at 14:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.