#17

Product support

Visit this product's website for support.

Categories

  • E-Commerce
  • Marketing

We have 100 coupons for those who want to test our paid plugins. Curious? Just let us know at [email protected]!

Live Demo

You can visit our Live Demo site. Sign in to backend using: login - manager, password - manager. You can deploy the demo site locally. To do so, you need to clone the repository, follow the steps from the "Installation guide", install the plugins. As a result, you will receive a copy of the demo site with a full database. Having a ready-made demo site example, you can easily learn how to operate the plugins.

Large Catalog Performance Live Demo

If you would like to know how our plugins perform with large catalogs of products, you can visit our Large Catalog Live Demo that has 21 000 products, 68 000 offers and 210 000 variations of property values.

Below are the performance characteristics for server setup: Dual Core CPU with 4GB of RAM.

For a catalog containing 210 products

Catalog page load time: 100-150 ms

Product list filtering time: 80-100 ms

For a catalog containing 21 000 products

Catalog page load time: 900-1100 ms

Product list filtering time: 500-600 ms

Support

Please join us on #shopaholic channel in October CMS slack chat in order to have quick support on all our products. You will also get all newest updates and insights about our existing and upcoming products!

If you have any specific requests, suggestions or ideas please do not hesitate to send us a message, it will help us make our products even better.

If you don't have access to octobercms.slack.com, please register here

Required Plugins

Recommended Plugins

General information

The Orders plugin adds functionality to Shopaholic, allowing you to manage incoming orders.

With this plugin you are able to:

  • Oversee the orders in the back-end, overlook and change their state or delete them upon completion
  • Create, and modify delivery methods. Delivery methods can be displayed as text info or interactive interface components (buttons, radio buttons)
  • Display various payment methods and allow users to choose their desired method (without integration with online payment systems)
  • Send e-mails after creating an order. E-mails can be sent to users and managers using different mail templates. You can add data to mail templates using events.

Users are able to:

  • Choose products and put them in their cart
  • Change the product quantity and delete them from the cart
  • Proceed to checkout and choose delivery methods and payment types through the interface that you provide

Promo Logic & Mechanisms

These Promo Logic and Mechanisms can be used with our Coupons for Shopaholic and Campaigns for Shopahoic paid extensions to easily setup promo mechanisms on your online shop.

Promo Logic

We have included 22 Promo mechanisms for you to use manually or with the help of our extensions:

Discount without conditions

  • Discount on the position price without conditions - Use this if you need a discount on the price of the position to be applied without checking any conditions. Works great for applying coupons.
  • Discount on the position price with minimal price without conditions - Use this if you need a discount on the price of the position with minimal price to be applied without checking any conditions. Works great for applying coupons.
  • Discount on the total price of positions without conditions - Use this if you need a discount on the total price of positions list to be applied without checking any conditions. Works great for applying coupons.
  • Discount on the shipping price without conditions - Use this if you need a discount on the shipping price to be applied without checking any conditions. Works great for applying coupons.
  • Discount on the total price of order without conditions - Use this if you need a discount on the total price of order to be applied without checking any conditions. Works great for applying coupons.

Discount if the total price of the position is greater than "XX"

  • Discount on the shipping price if the total price of the position is greater than "XX" - Use this if you need a discount on the shipping price to be applied if the total price of the position is greater than the set value. Example: The shipping price discount is 5%, if the total price of the position is greater than 50$.
  • Discount on the total price of an order if the total price of the position is greater than "XX" - Use this if you need a discount on the total price of an order to be applied if the total price of the position is greater than the set value. Example: The total price discount is 5%, if the total price of the position is greater than 50$.

Discount if the total quantity of one offer in the order is greater than "XX"

  • Discount on the position price if the total quantity of one offer in the order is greater than "XX" - Use this if you need a discount on the price of the position to be applied if the total quantity of one offer in the order is greater than the set value. Example: The position price discount is 5%, if the total quantity of the offer "T-shirt size 52" is greater than 3.
  • Discount on the position with minimal price if the total quantity of one offer in the order is greater than "XX" - Use this if you need a discount on the price of the position with minimal price to be applied if the total quantity of one offer in the order is greater than the set value. Example: The discount on the position with minimal price is 5%, if the total quantity of the offer "T-shirt size 52" is greater than 3.
  • Discount on the total price of positions if the total quantity of one offer in the order is greater than "XX" - Use this if you need a discount on the total price of positions to be applied if the total quantity of one offer in the order is greater than the set value. Example: The discount on the total price of positions is 5%, if the total quantity of the offer "T-shirt size 52" is greater than 3.
  • Discount on the shipping price if the total quantity of one offer in the order is greater than "XX" - Use this if you need a discount on the shipping price to be applied if the total quantity of one offer in the order is greater than the set value. Example: Shipping price discount is 5%, if the total quantity of the offer "T-shirt size 52" is greater than 3.
  • Discount on the total price of an order if the total quantity of one offer in the order is greater than "XX" - Use this if you need a discount on the total price of an order to be applied if the total quantity of one offer in the order is greater than the set value. Example: Total price discount is 5%, if the total quantity of the offer "T-shirt size 52" is >= 3.

Discount if the total quantity of offers in the order is greater than "XX"

  • Discount on the price of the position if the total quantity of offers in the order is greater than "XX" - Use this if you need a discount on the price of the position to be applied if the total quantity of offers in the order is greater than the set value. Example: Position price discount is 5%, if the total quantity of offers "T-shirt size 52" (quantity = 2) + "T-shirt size 56" (quantity = 2) = 4 is greater than 3.
  • Discount on the position with minimal price if the total quantity of offers in the order is greater than "XX" - Use this if you need a discount on the the position with minimal price to be applied if the total quantity of offers in the order is greater than the set value. Example: The discount for position with minimal price is 5%, if the total quantity of offers "T-shirt size 52" (quantity = 2) + "T-shirt size 56" (quantity = 2) = 4 is greater than 3.
  • Discount on the total price of positions if the total quantity of offers in the order is greater than "XX" - Use this if you need a discount on the total price of positions to be applied if the total quantity of offers in the order is greater than the set value. Example: Total price of positions discount is 5%, if the total quantity of offers "T-shirt size 52" (quantity = 2) + "T-shirt size 56" (quantity = 2) = 4 is greater than 3.
  • Discount on the shipping price if the total quantity of offers in the order is greater than "XX" - Use this if you need a discount on the shipping price to be applied if the total quantity of offers in the order is greater than the set value. Example: Shipping price discount is 5%, if the total quantity of offers "T-shirt size 52" (quantity = 2) + "T-shirt size 56" (quantity = 2) = 4 is greater than 3.
  • Discount on the total price of an order if the total quantity of offers in the order is greater than "XX" - Use this if you need a discount on the total price of an order to be applied if the total quantity of offers in the order is greater than the set value. Example: Total price discount is 5%, if the total quantity of offers "T-shirt size 52" (quantity = 2) + "T-shirt size 56" (quantity = 2) = 4 is greater than 3.

Discount if the position count in the order is greater than "XX"

  • Discount on the position price if the position count in the order is greater than "XX" - Use this if you need a discount on the price of the position to be applied if the position count in the order is greater than the set value. Example: Position discount is 5%, if the position count is greater than 3.
  • Discount on the position with minimal price if the position count in the order is greater than "XX" - Use this if you need a discount on the position with min price to be applied if the position count in the order is greater than the set value. Example: Minimal price position discount is 5%, if the position count is greater than 3.
  • Discount on the total price of positions if the position count in the order is greater than "XX" - Use this if you need a discount on the total price of positions to be applied if the position count in the order is greater than the set value. Example: Total price discount is 5%, if the position count is greater than 3.
  • Discount on the shipping price if the position count in the order is greater than "XX" - Use this if you need a discount on the shipping price to be applied if the position count in the order is greater than the set value. Example: Shipping price discount is 5%, if the position count is greater than 3.
  • Discount on the total price of an order if the position count in the order is greater than "XX" - Use this if you need a discount on the total price of an order to be applied if the position count in the order is greater than the set value. Example: Total price discount is 5%, if the position count is greater than 3.

Additional Promo Mechanism Parameters

  • Logic Priority of promotional activities - promo activities with higher priority are applied first;
  • Finalize promo activity - block other promo activities with less priority.

Authorization\Authentication features with Rainlab.User or Buddies plugin

Our Buddies plugin adds authorization functionality to Orders, allowing users to log in while placing orders. Orders Plugin now has integration with Rainlab.User, so you can also use it on projects that still run with this plugin. However, we highly recommend to make the transition and use our Buddies plugin!

Get involved and contribute to the project

If you’d like to help us improve the project, you can do so in the following ways:

You can also visit LOVATA’s GitHub page.

License

© 2018, LOVATA Software Development Company under GNU GPL v3.

Developed by Andrey Kharanenka.

These plugin(s) are required for the plugin:

The following themes use this plugin:

Order list

The full plugin documentation is available here.

Cart component

The component allows to work with user cart.

Method list

onAdd()

Method adds offers to cart. Example:

//Prepare object with offers
var data = {
    'cart': [
        {'offer_id': 2, 'quantity': 4, 'property': {'double_cheese': true}},
        {'offer_id': 5, 'quantity': 1, 'property': {'double_cheese': false}},
        {'offer_id': 10, 'quantity': 1, 'property': {'double_cheese': true}}
    ]
};

//Send ajax request and update cart items
$.request('Cart::onAdd', {
    'data': data,
    'update': {'cart-items': '.cart-item-wrapper'}
});
onUpdate()

Method updates quantity of offers in cart. Example:

//Prepare object with offers
var data = {
    'cart': [
        {'offer_id': 2, 'quantity': 4},
        {'offer_id': 5, 'quantity': 1},
        {'offer_id': 10, 'quantity': 1}
    ]
};

//Send ajax request and update cart items
$.request('Cart::onUpdate', {
    'data': data,
    'update': {'cart-items': '.cart-item-wrapper'}
});
onRemove()

Method removes offers from cart. Example:

//Prepare array with offers ID
var data = {
    'cart': [2,10]
};

//Send ajax request and update cart items
$.request('Cart::onRemove', {
    'data': data,
    'update': {'cart-items': '.cart-item-wrapper'}
});
onClear()

Method removes all offers from cart. Example:

//Send ajax request and update cart items
$.request('Cart::onClear', {
    'data': data,
    'update': {'cart-items': '.cart-item-wrapper'}
});
get($obShippingType = null)

Method returns CartElementCollection class object. You can pass active sipping type object to the method to get the total cost of the order with shipping price. Example:

{% set obCartElementList = Cart.get() %}
{% if obCartElementList.isNotEmpty() %}
    {% for obCartElement in obCartElementList %}
        {% set obOffer = obCartElement.offer %}
        <div>Name: {{ obOffer.product.name }}</div>
        <div>Quantity: <input type="number" value="{{ obCartElement.quantity }}"></div>
        <div>Price: {{ obOffer.price }} {{ obOffer.currency }}</div>
        <div>Total price: {{ obCartElement.price }} {{ obCartElement.currency }}</div>
    {% endfor %}

    <div>Total price: {{ obCartElementList.getTotalPrice() }} {{ obCartElementList.getCurrency() }}</div>
{% else %}
 <div>Cart is empty</div>
{% endif %}
onSetShippingType()

Method allows you to send ajax request with ID of active shipping type and get updated cart data

//Send ajax request and update cart data
$.request('Cart::onSetShippingType', {
    'data': {'shipping_type_id': iActiveShippingTypeID},
    success: function(response) {
        updateCart(response);
    }
});
getTotalPrice()

Method returns formatted total price string ("1 450,95")

    $obList = CartPositionCollection::make([1,2,10,15]);
    echo $obList->getTotalPrice();
getTotalPriceValue()

Method returns float total price value (1450.95)

    $obList = CartPositionCollection::make([1,2,10,15]);
    echo $obList->getTotalPriceValue();
getOldTotalPrice()

Method returns formatted total price string without discounts ("1 650,95")

    $obList = CartPositionCollection::make([1,2,10,15]);
    echo $obList->getOldTotalPrice();
getOldTotalPriceValue()

Method returns float total price value without discounts (1650.95)

    $obList = CartPositionCollection::make([1,2,10,15]);
    echo $obList->getOldTotalPriceValue();
getDiscountTotalPrice()

Method returns formatted discount price string ("200,00")

    $obList = CartPositionCollection::make([1,2,10,15]);
    echo $obList->getDiscountTotalPrice();
getDiscountTotalPriceValue()

Method returns float discount price value (200)

    $obList = CartPositionCollection::make([1,2,10,15]);
    echo $obList->getDiscountTotalPriceValue();
getTotalPriceData()

Method returns PriceContainer class object.

    $obList = CartPositionCollection::make([1,2,10,15]);
    echo $obList->getTotalPriceData();

MakeOrder component

The component allows to create orders.

Component properties:

  • Mode (Submit form/Ajax form)
  • Send flash message (only for Ajax mode)
  • Enable redirect
  • Choose page for redirect (the URL of the page will be passed to the order ID and order number)

Usage: The component is used to process the order form. To send an ajax request, you must use the MakeOrder::onCreate method. You need to send the 'order' object with the order data and the 'user' object with the user data. Acceptable order fields: payment_method_id, shipping_type_id, shipping_price, property (array). User data will be stored in the 'property' field of the order. If the setting is enabled, a new user will be created or the order will be attached to the authorized user.

Example 1 (Submit form).

[MakeOrder]
mode = "submit"
redirect_on = 1
redirect_page = "order_success"

[PaymentMethodList]

[ShippingTypeList]
==

{% set arError = MakeOrder.getErrorMessage %}
{% set arForm = MakeOrder.getOldFormData %}

<form href="{{ 'order'|page }}">
    <label for="field-email">Email</label>
    <input type="email" id="field-email" placeholder="Email" name="user[email]" value="{{ arForm.user.email }}">
    {% if arError.message is not empty and arError.field == 'email' %}
        <p>{{ arError.message }}</p>
    {% endif %}

    <label for="field-company-name">Company name</label>
    <input type="text" id="field-company-name" placeholder="My company" name="user[property][company_name]" value="{{ arForm.user.property.company_name }}">

    {% set obPaymentMethodList = PaymentMethodList.make().sort().active() %}
    {% if obPaymentMethodList.isNotEmpty() %}
        <div class="payment-method-list-wrapper">
            {% for obPaymentMethod in obPaymentMethodList %}
                <input type="radio" name="order[payment_method_id]" id="payment-{{ obPaymentMethod.id }}" value="{{ obPaymentMethod.id }}">
                <label for="payment-{{ obPaymentMethod.id }}">{{ obPaymentMethod.name }}</label>
            {% endfor %}
        </div>
    {% endif %}

    {% set obShippingTypeList = ShippingTypeList.make().sort().active() %}
    {% if obShippingTypeList.isNotEmpty() %}
        <div class="payment-method-list-wrapper">
            {% for obShippingType in obShippingTypeList %}
                <input type="radio" name="order[shipping_type_id]" id="payment-{{ obShippingType.id }}" value="{{ obShippingType.id }}">
                <label for="payment-{{ obShippingType.id }}">{{ obShippingType.name }}</label>
            {% endfor %}
        </div>
    {% endif %}

    <input type="hidden" name="order[shipping_price]" value="5.50">
    <button type="submit">Submit</button>
</form>
{% if arError.message is not empty %}
    <p>{{ arError.message }}</p>
{% endif %}

Example 1 (Ajax request).

var data = {
    'order': {
        'payment_method_id': 1,
        'shipping_type_id': 2,
        'shipping_price': 10.5,
        'property': {
            'address': '...',
            'city': 'Minsk'
        }
    },
    'user': {
        'email': '[email protected]',
        'name': 'Andrey'
    }
};

$.request('MakeOrder::onCreate', {
    'data': data
});

The MakeOrder.getOldFormData method returns the filled form fields, if the form was sent and an error occurred. The MakeOrder.getErrorMessage method returns an error message if the form was sent and an error occurred.

[
    'message' => 'Error message',
    'field'   => 'email',           //Field name, if there was a validation error
]

Event "shopaholic.order.created"

You can add your logic after creating an order.

Event::listen('shopaholic.order.created', function($obOrder) {
    ...
});

Event "shopaholic.order.created.user.template.data"

You can add additional fields in the email template (for users). By default, the 'lovata.ordersshopaholic::mail.create_order_user' template is used. To integrate with the Translate plugin, you need to create templates for languages with suffix = language code. For example:

  • 'lovata.ordersshopaholic::mail.create_order_user' - for default language
  • 'lovata.ordersshopaholic::mail.create_order_user_ru' - for language with code 'ru'
Event::listen('shopaholic.order.created.user.template.data', function($obOrder) {
    ...

    //Return array with addition fields
    return $arResult;
});

Event "shopaholic.order.created.manager.template.data"

You can add additional fields in the email template (for managers). By default, the 'lovata.ordersshopaholic::mail.create_order_manager' template is used. To integrate with the Translate plugin, you need to create templates for languages with suffix = language code. For example:

  • 'lovata.ordersshopaholic::mail.create_order_manager' - for default language
  • 'lovata.ordersshopaholic::mail.create_order_manager_ru' - for language with code 'ru'
Event::listen('shopaholic.order.created.manager.template.data', function($obOrder) {
    ...

    //Return array with addition fields
    return $arResult;
});

PaymentMethodList component

The component allows to work with PaymentMethodCollection class objects.

Method list

make($arElementIDList = null)

Example: render list of payment methods

Get collection of payment methods, apply sorting + filter by flag "active"

{% set obPaymentMethodList = PaymentMethodList.make().sort().active() %}
{% if obPaymentMethodList.isNotEmpty() %}
    <div class="payment-method-list-wrapper">
        {% for obPaymentMethod in obPaymentMethodList %}
            <div data-id="{{ obPaymentMethod.id }}">
                <div>{{ obPaymentMethod.name }}</div>
                <div>{{ obPaymentMethod.preview_text }}</div>
            </div>
        {% endfor %}
    </div>
{% endif %}

ShippingTypeList component

The component allows to work with ShippingTypeCollection class objects.

Method list

make($arElementIDList = null)

Example: render list of shipping types

Get collection of shipping types, apply sorting + filter by flag "active"

{% set obShippingTypeList = ShippingTypeList.make().sort().active() %}
{% if obShippingTypeList.isNotEmpty() %}
    <div class="payment-method-list-wrapper">
        {% for obShippingType in obShippingTypeList %}
            <div data-id="{{ obShippingType.id }}">
                <div>{{ obShippingType.name }}</div>
                <div>{{ obShippingType.preview_text }}</div>
            </div>
        {% endfor %}
    </div>
{% endif %}

UserAddress component

The component allows to create/update/remove user addresses.

Method list

onAdd()

Method creates new user address. Example:

$('form').request('UserAddress::onAdd');
onUpdate()

Method updates user address. Example:

//Prepare object with address data
var data = {
    'id': 10,
    'address1': 'test'
};

//Send ajax request
$.request('UserAddress::onUpdate', {
    'data': data
});
onUpdateList()

Method syncs user address list. Example:

//Prepare object with address data
var data = [
      {'id': 10, 'address1': 'test1'},
      {'id': 12, 'address1': 'test2'}
];

//Send ajax request
$.request('UserAddress::onUpdateList', {
    'data': data
});
onRemove()

Method removes user address. Example:

var data = {
    'id': 10
};

$.request('UserAddress::onRemove', {
    'data': data
});
var data = {
    'id': [2, 10]
};

$.request('UserAddress::onRemove', {
    'data': data
});
onClear()

Method removes all user addresses. Example:

$.request('UserAddress::onClear');
  • Found the plugin useful on 6 Jul, 2018

    Can someone please shed some light on how to add items to the cart please??

    The documentation says: $.request('Cart::onAdd', { 'data': data, 'update': {'cart-items': '.cart-item-wrapper'} });

    how to call this exactly?

    Thanks Matthew

  • author

    Replied on 6 Jul, 2018

    Hi Matthew!

    You can see example of using Cart component in code of demo theme.

    You can install local copy of demo site and study code of demo theme.

    Thank you for using Shopaholic! We're happy you enjoyed it!

1.11.2

Fixed the logic of getting custom field values of the saved user address when creating an order.

Oct 17, 2018

1.11.1

Added annotations for integration with Coupons for Shopaholic, Discounts for Shopaholic, Campaigns for Shopaholic plugins.

Oct 16, 2018

1.11.0

Added PromoMechanism model. Added of opportunity to change price of order positions, shipping price, order total price, using promo mechanisms. Added user addresses. Added tasks with relation with orders, users.

Oct 15, 2018

1.10.2

Fixed labels in ShippingType controller breadcrumbs.

Sep 03, 2018

1.10.1

Remove links on lang file of Buddies plugin.

Aug 17, 2018

1.10.0

Add Validation trait to Order model.

Aug 09, 2018

1.9.1

Adds secret_key field to OrderItem object

Aug 08, 2018

1.9.0

Added type returned by methods in AbstractStore * classes

Aug 07, 2018

1.8.0

Add payment_token field to Order model

Aug 06, 2018

1.7.0

Improved integration with payment systems. Adds of shipping price filling from shipping type object, if shipping_price field value from request is empty.

Aug 01, 2018

1.6.4

Fix position type default value

Jul 12, 2018

1.6.3

Fix work with *Store classes in *Handler classes

Jul 11, 2018

1.6.2

Fix error in OfferOrderPositionProcessor class.

Jun 25, 2018

1.6.1

Fix error in OrderPage::get() method

Jun 21, 2018

1.6.0

Add classes: OrderCollection, OrderPositionCollection, StatusCollection, OrderItem, OrderPositionItem, StatusItem. Add StatusList component. Adding the ability to create custom properties for order positions. Adding the ability to attach users with orders. Adding the ability to create/update order positions in backend. Add filter order list (backend) by payment method, shipping type, created_at/update_at fields. Add "hasMany" relation in User model with Order model. Add "user_list" property in User model. Add "order" in UserItem class. Refactoring CartProcessor, OrderProcessor classes. Rename classes: CartElementCollection => CartPositionCollection, CartElementItem => CartPositionItem. Requires Toolbox plugin version 1.10.0 and later.

Jun 21, 2018

1.5.0

Update logic for new version of CResult class. Requires Toolbox plugin version 1.9.1 and later.

Apr 17, 2018

1.4.0

Add integration with RainLab.User plugin. Added sending emails to the user and managers after the order was created. Add events "shopaholic.order.created", "shopaholic.order.created.user.template.data", "shopaholic.order.created.manager.template.data". Requires Toolbox plugin version 1.7.0 and later.

Mar 11, 2018

1.3.1

Added check for isNested flag when expanding forms

Feb 23, 2018

1.3.0

Add "price" field in ShippingType model

Feb 11, 2018

1.2.1

Remove php short tags from orders/_price_block.htm

Jan 29, 2018

1.2.0

Add additional properties for Order model. Add settings for validation the email field as required.

Jan 27, 2018

1.1.0

The "rewrite" and "increase" flags are removed from the method of updating the quantity of items in the cart

Jan 27, 2018

1.0.5

$casts property is replaced with $jsonable property in the Order model

Jan 11, 2018

1.0.4

!!! Adding additional cache cleaning for the sorted list of payment methods and shipping types, after the creation of a new element. Requires Toolbox plugin version 1.3.0 and later.

Jan 08, 2018

1.0.3

Change method for generation secret_key field in Order model

Dec 24, 2017

1.0.2

Remove php short tags from orders/_price_block.htm

Dec 15, 2017

1.0.1

Fix permission tab label in config

Dec 08, 2017

1.0.0

Initialize plugin.

Dec 06, 2017