Merx

Stock Management

Let’s assume your granny knitted 10 pairs of knitted socks. So you can’t sell 11 pairs. Learn how to manage your inventory.

You can find the source code of a full working example on Github:
Source Code

Add stock field to product page

content/knitted-socks/product.txt

Title: Knitted socks
----
Price: 14.99
----
Tax: 19
----
Stock: 10

Check if stock is sufficient

Use hooks to throw exception if the stock is not sufficient.

Check the availability of the products with the initializePayment:before and completePayment:before hooks. For each item in the cart check if the available stock is smaller than the quantity of the cart item. If that’s the case an exception is thrown.

In this example we use Kirby’s helpful Exception class to throw a nice error message.

site/config/config.php

<?php
use Kirby\Exception\Exception;

function checkStock($cart) {
  foreach($cart as $cartItem) {
    $cartItemPage = page($cartItem['id']);
    $availableStock = $cartItemPage->stock()->toInt();
    if ($availableStock < (int)$cartItem['quantity']) {
      throw new Exception([
        'httpCode' => 400,
        'fallback' => '“{productTitle}” is out of stock',
        'data' => [
          'productTitle' => $cartItemPage->title(),
        ],
      ]);
    }
  }
}

return [
  'hooks' => [
    'ww.merx.initializePayment:before' => function ($data, $cart) {
      checkStock($cart);
    },
    'ww.merx.completePayment:before' => function ($virtualOrderPage) {
      checkStock($virtualOrderPage->cart());
    },
  ],
];

It’s up to you were you print the exception / error message. For example you can use a checkout controller like this.

site/controllers/checkout.php

<?php
if (kirby()->request()->method() === 'POST') {
  try {
    $data = $_POST;
    $redirect = merx()->initializePayment($data);
    go($redirect);
  } catch (Exception $ex) {
    echo $ex->getMessage(); // e.g. “Knitted socks” is out of stock.
  }
}

Merx comes with a default success template which prints the exceptions of the completePayment method. You can/should use your own success template to handle completePayment exceptions.

site/plugins/merx/templates/success.php

<?php
try {
  $orderPage = merx()->completePayment($_GET);
  go($orderPage->url());
} catch (Exception $ex) {
  echo $ex->getMessage();
}

Update stock

Use the completePayment:after hook to update the stocks.

site/config/config.php

return [
  'hooks' => [
    …
    'ww.merx.completePayment:after' => function ($orderPage) {
      foreach($orderPage->cart() as $cartItem) {
        $cartItemPage = page($cartItem['id']);
        $newStock = $cartItemPage->stock()->toInt() - (int)$cartItem['quantity'];
        $cartItemPage->update([
          'stock' => (int)$newStock,
        ]);
      }
    },
  ],
];