May 4, 2017

How To Provide Wholesale Pricing In Craft Commerce

Mitchell Kimbrough
Mitchell Kimbrough
Founder & CEO

Your client sells physical goods on the web. At the last minute you realize that they want to offer special wholesale pricing only to those customers who qualify. That sounds gnarly. But good thing they chose to use Craft Commerce as their platform. Here's how to build wholesale pricing into Craft Commerce.

This is a great client we're talking about; super cool, very chill, always relaxed and amenable to sensible revisions and changes. They got a surprised look on their face when you said, "What wholesale pricing?"

Turns out you wrote it into the contract. In their store you would make it so that certain of their customers would get special pricing for being wholesalers of their products. It's late in the project and you're headed into QA. You sure wish you would have written this down somewhere other than in their pesky contract so you wouldn't forget; somewhere like on your forehead.

You talk it over with your team and you consider using the Variants feature in Craft Commerce. You could make a variant of a product that could hold the wholesale information. But if you did this it would clutter the system and create annoyances at the template level. You could create a custom field on your products, store the wholesale price in that field and show that only to people of a certain group. But the shopping cart flow would have all the wrong math if you did that.

You feel stuck. The client is totally nice. They're rooting for you. So here's what you do.

Craft Commerce comes native with a Discounts feature. You can use this feature to build out your wholesale pricing.

In Craft Commerce you can create n number of discounts.

Discounts

When you create a discount you can attach it, using conditions, to member groups as well as products and product types. This way, only members of the designated Wholesale group can get the discount and only the products or the product types indicated are affected.

Conditions

It's perfect. It's exactly what you needed! You wrote that contract without even really checking. You just knew that since you were in Craft Commerce, Brandon, Brad and Andris probably already knew you were coming and were ready for you.

There's a small problem, though. Even though the system is built so that eligible discounts are calculated and deducted from cart items in the context of the cart, the main sales pages don't really have access to wholesale discount pricing info. In other words, even though there may be a wholesale discount for a product, when you are looking at the product detail page on the site, you can't see the wholesale price. It's not readily available in the template.

In comes a simple plugin. You just need to do some database queries to work your way backwards up the tree from a product up to its eligible discounts. You can simply use the variable feature in Craft CMS to do this if you want to keep things easy.

Scaffold your plugin maybe by starting from the Business Logic Plugin Template. Get a method into your variables file like this:

    public function getWholesalePrice($criteria = array())
    {
    }

Check to see if the currently logged in user belongs to the Wholesale group. Bail out if they don't.

    //	Get user
    $user = craft()->userSession->getUser();

    //	Not in wholesale group?
    if (! $user->isInGroup('wholesale')) return FALSE;

Grab the product id and product type id from the criteria passed across in the template. More on that in a sec...

    $productId = $criteria['productId'];
    $productTypeId = $criteria['productTypeId'];	// For this blog post we won't bother with this variable.
    $wholesaleGroupId = 2;	// Honestly no one else will use your plugin. You may as well save a DB query and hard code the wholesale member group.

Now query the database to see if there are any discounts for this product allowable for the Wholesale group.

    $result = Commerce_DiscountRecord::model()
	    ->with(array(
		    'groups' => array(
			    'condition' => 'userGroupId=' . $wholesaleGroupId
		    ),
		    'products' => array(
			    'condition' => 'productId=' . $criteria['productId']
		    )
	    ))
	    ->findByAttributes([
		    'enabled'	=> TRUE,
	    ]);

You could be a lot more professional about this and capture the other stuff like start and end dates of discounts and such, but hey, it's just a quick blog post before bed.

Populate the model so that you can tinker with it.

    if ($result)
    {
	    $result	= Commerce_DiscountModel::populateModel($result);
    }

Make a computer do math, not a human.

    //	If per item discount
    if ($result->perItemDiscount < 0) {
	    return $criteria['price'] + $result->perItemDiscount;
    }

Craft Commerce saves the per item discount you indicated in this format: -10.000. So you just need to add the two numbers together to get a right and proper discount.

And here's what the template looks like:

    Your Wholesale Price: {{ craft.yourPluginName.getWholesalePrice({
	    price: product.defaultPrice,
	    productId: product.id,
	    productTypeId: product.typeId
    })|commerceCurrency(cart.currency) }}

You can wrap that thing in conditionals if you don' want the wholesale jargon to show when there's no discount. You can also add a twig filter at the end there to format the currency.

When the customer adds this item to their cart, Craft Commerce is already smart enough to look for and apply the discount that you found above. That part is nicely automatic. Just make sure that in your cart templates you are using the right variables like {{ item.total }} and {{ cart.totalPrice }} and stuff. Otherwise you'll end up using variables that do not have the discounts calculated in.

Good night.

Mitchell Kimbrough
Mitchell Kimbrough Founder & CEO