backdrop-contrib / ubercart

A flexible but easy-to-use e-commerce system for Backdrop.
https://backdropcms.org/project/ubercart
GNU General Public License v2.0
4 stars 10 forks source link

Better distinguish between business and consumer customers #447

Open yorkshire-pudding opened 1 year ago

yorkshire-pudding commented 1 year ago

In the UK and EU there can be different tax (VAT) treatments based on whether the customer is a business or an individual consumer. It may also be desirable to offer different payment methods for businesses to consumers.

There is a simple text Company field but it is not exposed to the rule conditions in any way. My guess is it needs new uc_order_condition_* functions. Am I right in thinking this would need to be in the module? I looked at the API for uc_order but didn't see any way to add this in. I know that the uc_order.rules.inc implements rules hooks but could a custom module or another contrib add to the order rules?

The ideal might be a switch with company name being required if a business.

It would also be good to have the option to capture customer VAT number as whether someone is VAT registered or not can affect the tax rules. There is a drupal module, Ubercart VAT Number but I think this is overkill as it will also need Web service client

bugfolder commented 1 year ago

Ubercart supports diverse ways of customized handling of sales tax, which (presumably) VAT is, so this sounds like a job for a contrib module. You don't need to use Rules; just implement hook_uc_calculate_tax($order) and set the line item type to 'tax'.

One way of handling different tax treatment on a per-customer basis is to create different Backdrop roles, then check those roles in your hook_uc_calculate_tax($order) function (because the user account is in the order record, you can do that). For example, on our site, we have a "tax exempt" role for certain customers, and the (custom) tax module checks that role.

yorkshire-pudding commented 1 year ago

Thanks for that @bugfolder - that is useful and probably the way to go at least partly; we wouldn't necessarily be able to do this based on roles as we wouldn't know this at first order and the account isn't created until checkout. Can I override the billing fields in the order to do what I want with regard to company vs individual, enforce company name if company, and also some fields about VAT status and VAT number? Is this sort of thing possible by extending UcOrder? Are there any ubercart contrib modules you would recommend to look at in order to get a feel for how this is done?

Thank you.

argiepiano commented 1 year ago

Ideally this would be done with roles... but

While I haven't looked into this closely (and I don't have much experience with UC tax), I believe the way to go here is to add a custom pane with a checkbox to indicate whether the customer is a business, and show this only if the user is anonymous. That checkbox could have an ajax callback that rebuilds the checkout form and recalculates the tax (implementing hook_uc_calculate_tax() - your ajax callback should set a flag in the $order object to tell this implementation that this is a business).

In addition you could add a field to the $order bundle to indicate this is a business, and set the value of that field during the ajax callback. That way this checkbox value would be saved with the order.

argiepiano commented 1 year ago

Re-reading the original post, here are some answers, @yorkshire-pudding. So, as you know, you can create conditions for a tax rate to be applied through the UC taxes UI (via rules). You are right that there is currently no way to check the order's company (to see if it's empty, for example). But any module can add rules conditions to any group. In this case the easiest way to check if (for example) Company is empty is

  1. Implement hook_rules_condition_info() as follows
function MY_MODULE_rules_condition_info() {
  $conditions['MY_MODULE_condition_company_empty'] = array(
    'label' => t("Check if an order's company is empty"),
    'group' => t('Order'),
    'parameter' => array(
      'order' => array(
        'type' => 'uc_order',
        'label' => t('Order'),
      ),
      'empty' => array(
        'type' => 'boolean',
        'label' => t('Is empty'),
        'restriction' => 'input',
      ),
    ),
  );
  return $conditions;
}

And the callback:

function MY_MODULE_condition_company_empty($order, $empty) {
  $is_empty = empty($order->billing_company);
  if ($empty) {
    return $is_empty;
  }
  else {
    return !$is_empty;
  }
}

I've tested this with different tax rates, and it works (you have to move to the "Review order" stage to see the correct tax rate being applied, since the pricing in the Checkout pane the first time you visit will show the rate for an empty Company field).

Ideally, you would have a checkbox in the checkout pane to indicate that this is a business. This could be done with a hook_form_alter() hook that shows/hides the field company if the checkbox is checked, and a custom validate function to be sure a company name is provided if the business checkbox is checked. The value of the checkbox could be stored as a field attached to the order (within a custom submit).

yorkshire-pudding commented 1 year ago

Thank you @argiepiano for the detailed explanation and example. That gives me a lot to go on. I have another site to get out the door today, but hopefully will have another look at ubercart and try to implement this later this week.

bugfolder commented 11 months ago

@yorkshire-pudding, did you achieve success with the suggested approach?

yorkshire-pudding commented 11 months ago

@bugfolder - this was while I was investigating ubercart as a client was considering a store for some courses. They've not progressed this idea and I haven't had time to experiment yet

argiepiano commented 11 months ago

Should we close this, then?