Advanced Shipping Setting is an extension for the e-commerce solution Magento.
The syntax using PHP 5.6 allows a great flexibility in setting delivery charges.
Technical Informations
The usage of the PHP syntax (with an Abstract Syntax Tree) has been preferred to the usage of a JSON syntax (with regular expressions and the eval function) as in previous versions of the extension. This is the result of considerations on security and performance.
The PHP code defined in the configuration is not evaluated with the eval function for security reasons. The library PHP-Parser is used to obtain an Abstract Syntax Tree (AST). The AST is browsed and only a limited set of functions and variables is allowed.
As the AST is not version-dependent, you can use the PHP 5.6 syntax even if your server uses a lower version of PHP.
Advanced Shipping Setting allows you to manage one carrier.
To manage more carriers, you can get a license for Unlimited Carriers add-on by Owebia.
$item->product->getAttributeText('attribute_code')
for product attributes of type select
A call to addMethod
function adds a shipping method.
object addMethod ( string $method_id , array $method_properties )
List of method properties:
title
price
description
(optional)enabled
(optional): conditions for displaying the shipping methodExample
// First shipping method addMethod('method1', [ 'title' => "Standard Shipping", 'price' => 10, ]); // Second shipping method addMethod('method2', [ 'title' => "Express Shipping", 'price' => 20, ]);
Warning: to avoid conflicts, use only the characters a-z
, A-Z
, 0-9
, -
and _
for the method id.
You should also avoid identifiers that already correspond to variable names (quote
, request
…).
You can use variables, functions and operators to define a dynamic value (all operators are not supported).
Example
addMethod('method1', [ // Dynamic title using the variable $request->dest_country_id 'title' => "Delivery to " . $request->dest_country_id, // Dynamic price using the variable $quote->subtotal 'price' => 0.2 * $quote->subtotal, ]); addMethod('method2', [ 'title' => "Free Shipping", // Dynamic enabled using the function substr() and the variable $quote->coupon_code 'enabled' => substr($quote->coupon_code, 0, 4) == 'free', 'price' => 0, ]);
There are global variables and local variables that you can access with array functions and callbacks.
If you activate the debug option, you can see all data available for each object that you use.
Remember that you don't have access to all methods of the original objects because they are not accessed directly.
These variables are global variables and can be accessed everywhere (use the global
keyword when you are inside a function).
\Magento\Quote\Model\Quote\Address\RateRequest
) given by Magento:
$request->all_items
: array of items in cart$request->country_id
*$request->region_id
$request->city
$request->postcode
$request->dest_country_id
*$request->dest_region_id
$request->dest_region_code
$request->dest_street
$request->dest_city
$request->dest_postcode
$request->package_value
: value of the package$request->package_value_with_discount
: value of the package with discount$request->package_weight
: weight of the package$request->package_qty
: number of products in the package$request->free_shipping
: free shipping calculated by Magento rules$request->*
: property of the request object\Magento\Quote\Model\Quote
):
$quote->subtotal
: subtotal (excluding tax)$quote->subtotal_with_discount
: subtotal (excluding tax) with discount$quote->grand_total
: total (including tax) with discount$quote->base_subtotal
: subtotal (excluding tax) in base currency$quote->base_subtotal_with_discount
: subtotal (excluding tax) with discount in base currency$quote->base_grand_total
: total (including tax) with discount in base currency$quote->coupon_code
: the coupon code used in cart$quote->*
: property of the quote (ex: $quote->subtotal
)\Magento\Customer\Model\Group
):
$customer_group->id
: alias of $customer_group->customer_group_id
$customer_group->code
: alias of $customer_group->customer_group_code
$customer_group->name
: alias of $customer_group->customer_group_code
$customer_group->*
: property of the customer group (ex: $customer_group->tax_class_id
)\Magento\Customer\Model\Customer
):
$customer->id
: alias of $customer->entity_id
$customer->*
: attribute of the customer (ex: email, lastname, firstname, group_id…)\Magento\Variable\Model\Variable
):
$variable->*
: custom variable defined in Magento (ex: $variable->my_var
)\Magento\Store\Model\Store
):
$store->id
$store->code
$store->name
$store->address
$store->phone
* Magento apparently uses the ISO 3166-1 alpha-2 codes.
Note that the country code for United Kingdom is GB and not UK.
You can use $request->all_items
with array functions.
Example
addMethod('__auto__', [ 'title' => "If at least one product has the attribute 'name' equal to 'Cat'", 'enabled' => count( array_filter($request->all_items, function ($item) { return $item->product->name == 'Cat'; }) ) > 0, 'price' => 10 ]);
\Magento\Quote\Model\Quote\Item
):
$item->qty
: quantity of the item$item->weight
: weight of the item$item->base_original_price
: price excluding tax without discount$item->price_incl_tax
: price including tax without discount$item->options->*
: option (the available options depend on the product)\Magento\Catalog\Model\Product
):
$item->product->*
sku
name
weight
price
(as defined in Magento backoffice)special_price
: (as defined in Magento backoffice)tax_class_id
: the taxclass idgetAttributeText('tax_class_id')
: the tax class namegetAttributeText('attribute_code')
\Magento\Catalog\Model\Category
)
$item->product->category->*
: attribute of the first categoryid
name
is_active
$item->product->category_ids
: array of id of the categories\Magento\Eav\Model\Entity\Attribute\Set
):
$item->product->attribute_set
: the attribute set$item->product->attribute_set->*
: attribute of the attribute setid
attribute_set_name
\Magento\CatalogInventory\Model\Stock\Item
):
$item->product->stock_item->*
: attribute of the product stockis_in_stock
qty
Look at the PHP documentation if you want to know how to use these functions.
Functions allowed:
addMethod('__auto__', [ 'title' => "Free shipping", 'price' => 0, ]);
addMethod('__auto__', [ 'title' => "France, Germany, Switzerland, Spain, Italy", 'enabled' => in_array($request->dest_country_id, ['FR', 'DE', 'CH', 'ES', 'IT']), 'price' => 10, ]); addMethod('__auto__', [ 'title' => "Postcode starting with 25", 'enabled' => $request->dest_country_id == 'FR' && substr($request->dest_postcode, 0, 2) == '25', 'price' => 10, ]); addMethod('__auto__', [ 'title' => "Regular expressions allowing postal codes beginning with 'PO' (case insensitive)", 'enabled' => $request->dest_country_id == 'GB' && preg_match('/^PO.*$/i', $request->dest_postcode), 'price' => 10, ]);
France excluding DOM/TOM
// Regular Expression refusing delivery to France with postal codes // beginning with 97 and 98 (with or without interspersed zeros and spaces) addMethod('__auto__', [ 'title' => "France excluding DOM/TOM", 'enabled' => $request->dest_country_id == 'FR' && !preg_match('/^[0\\s]*9\\s*[78]/', $request->dest_postcode), 'price' => 10, ]);
You can use the name or ID of the customer groups.
addMethod('__auto__', [ 'title' => "Retailer group", 'enabled' => $customer_group->code == "Retailer", 'price' => 10, ]); addMethod('__auto__', [ 'title' => "NOT LOGGED IN and General groups", 'enabled' => in_array($customer_group->code, ['NOT LOGGED IN', 'General']), 'price' => 10, ]); addMethod('__auto__', [ 'title' => "NOT LOGGED IN and General groups by their ID", 'enabled' => in_array($customer_group->id, [0, 1]), 'price' => 10, ]);
Formulas can be used to calculate the price of the delivery.
addMethod('__auto__', [ 'title' => "Shipping", 'price' => 0.1 * $quote->subtotal + 10.00, ]);
Using the configuration of another element
$standard = addMethod('standard', [ 'title' => "Standard Shipping", 'enabled' => $quote->subtotal < 1000.00, 'price' => 10, ]); addMethod('express', [ 'title' => "Express Shipping", 'enabled' => $standard->enabled && $request->package_weight < 10, 'price' => 12, ]);
Defining a table
// If the package weight is lower or equal to 0.5, the price will be 5.30 // If the package weight is lower or equal to 1.0, the price will be 6.50 // In others cases, the price will be 7.50 addMethod('__auto__', [ 'title' => "Shipping", 'price' => array_reduce([ [0.7, 5.30], [1.0, 6.50], ['*', 7.50] ], function ($carry, $item) { global $request; if (isset($carry)) return $carry; if (isset($item[0]) && ($request->package_weight <= $item[0] || $item[0] == '*')) { $carry = $item[1]; } return $carry; }), ]); // You can exclude the upper limit value by adding an argument false addMethod('__auto__', [ 'title' => "Shipping", 'price' => array_reduce([ [0.7, 5.30], [1.0, 6.50], ['*', 7.50] ], function ($carry, $item) { global $request; if (isset($carry)) return $carry; if (isset($item[0]) && ($request->package_weight < $item[0] || $item[0] == '*')) { $carry = $item[1]; } return $carry; }), ]);
Using the function _switch()
(associative table)
// If the coupon code is equal to "coupon1", the price will be 5.30 // If the coupon code is equal to "coupon2", the price will be 6.50 // In others cases, the price will be 7.50 addMethod('__auto__', [ 'title' => "Shipping", 'price' => [ 'coupon1' => 5.30, 'coupon2' => 6.50 ][$quote->coupon_code] ?? 7.50, ]);
addMethod('__auto__', [ 'title' => "If at least one product has the attribute 'name' equal to 'Cat'", 'enabled' => count( array_filter($request->all_items, function ($item) { return $item->product->name == 'Cat'; }) ) > 0, 'price' => 10 ]); addMethod('__auto__', [ 'title' => "If all items have the option 'Size' greater or equal to 1", 'enabled' => count( array_filter($request->all_items, function ($item) { return isset($item->options['Size']) && $item->options['Size']['value'] >= 1; }) ) == $request->package_qty, 'price' => 10 ]); addMethod('__auto__', [ 'title' => "More than 3 sku differents", 'enabled' => count( array_unique( array_map(function ($item) { return $item->product->sku; }, $request->all_items) ) ) > 3, 'price' => 10 ]); addMethod('__auto__', [ 'title' => "Sum of all options 'Size' is greater than 30", 'enabled' => array_sum( array_map( function ($item) { return $item->options['Size']['value'] ?? 0; }, $request->all_items ) ) > 30, 'price' => 10 ]); addMethod('__auto__', [ 'title' => "Minimum price excluding tax without discount is greater to 10", 'enabled' => min( array_map( function ($item) { return $item->base_original_price; }, $request->all_items ) ) > 10, 'price' => 10 ]); addMethod('__auto__', [ 'title' => "Maximum value of the option 'Size' is lower than 50", 'enabled' => max( array_map( function ($item) { return $item->options['Size']['value'] ?? 0; }, $request->all_items ) ) < 50, 'price' => 10 ]); // shipping is a custom product attribute addMethod('__auto__', [ 'title' => "Calculate shipping fees by product", 'price' => array_sum( array_map( function ($item) { return $item->product->shipping * $item->qty; }, $request->all_items ) ), ]); addMethod('__auto__', [ 'title' => "5 x weight of products that are in categories 2 or 3", 'price' => array_sum( array_map( function ($item) { return count(array_intersect($item->product->category_ids, [2, 3]))>= 1 ? $item->product->weight * $item->qty : 0; }, $request->all_items ) ) * 5.0, ]); addMethod('__auto__', [ 'title' => "5 x weight of products that are in both categories 2 and 3", 'price' => array_sum( array_map( function ($item) { return count(array_intersect($item->product->category_ids, [2, 3])) == 2 ? $item->product->weight * $item->qty : 0; }, $request->all_items ) ) * 5.0, ]);
Warning: you must notice that in Magento, a product can be in multiple categories.
So be particularly careful how you use this property.
addMethod('__auto__', [ 'title' => "Sum of weight attributes of products in category 12", 'price' => array_sum( array_map( function ($item) { return in_array(12, $item->product->category_ids) ? $item->product->weight : 0; }, $request->all_items ) ), ]); addMethod('__auto__', [ 'title' => "Sum of weight attributes of products in categories whose id is 11 and 12", 'price' => array_sum( array_map( function ($item) { return count(array_intersect($item->product->category_ids, [11, 12])) >= 1 ? $item->product->weight : 0; }, $request->all_items ) ), ]); addMethod('__auto__', [ 'title' => "Sum of weights of products having for first category id 12", 'price' => array_sum( array_map( function ($item) { return $item->product->category_id == 12 ? $item->product->weight : 0; }, $request->all_items ) ), ]);
© 2016 Owebia