Repository files navigation

Purchases Shipping

Build StatusScrutinizer Quality ScoreCode CoverageLatest Stable Version

Usage

Purchase_items that you want to ship must implement Shippable, like this:

class Model_Product extends Jam_Model implements Sellable, Shippable {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
$meta
->associations(array(
'shipping' => Jam::association('belongsto', array('inverse_of' => 'products')),
))
->fields(array(
'id' => Jam::field('primary'),
'name' => Jam::field('string'),
'currency' => Jam::field('string'),
'price' => Jam::field('price'),
))
->validator('type', 'price', 'quantity', array(
'present' => TRUE
));
}
// Implement Sellablepublicfunctionprice(Model_Purchase_Item$item)
{
return$this->price;
}
// Implement Sellablepublicfunctioncurrency()
{
return$this->currency;
}
// Implement Shippable// Must return a ``Model_Shipping`` object holding all the data for the shippingpublicfunctionshipping()
{
return$this->shipping;
}
// Implement Shippable// Must return a boolean whether or not the product ships can to that locationpublicfunctionships_to(Model_Location$location)
{
return$this->shipping ? $this->shipping->ships_to($location) : FALSE;
}
}
class Model_Purchase_Item_Product extends Kohana_Model_Purchase_Item_Product {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_purchase_item' => Jam::behavior('shippable_purchase_item'),
));
}
}
class Model_Shipping extends Kohana_Model_Shipping {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->associations(array(
'products' => Jam::association('hasmany', [
'inverse_of' => 'shipping',
]),
));
}
}

Also you need to add the shippable purchase to your purchase and brand purchase:

class Model_Brand_Purchase extends Kohana_Model_Brand_Purchase {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_brand_purchase' => Jam::behavior('shippable_brand_purchase'),
));
}
}
class Model_Purchase extends Kohana_Model_Purchase {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_purchase' => Jam::behavior('shippable_purchase'),
));
}
}

This behaviors will add the 'shipping' association to the brand_pruchase, also listen to update_items event and add a shipping purchase_item, and listen to the filter_items event, adding some more flags to filter by.

Once you have added the shipping data to your products:

$post = Jam::find('shipping_method', 'Post');
$europe = Jam::find('location', 'Europe');
$france = Jam::find('location', 'France');
$product->shipping = Jam::create('shipping', array(
'currency' => 'GBP',
'ships_from' => $france,
'groups' => array(
// Ships to all of Europe for 20 GBParray('method' => $post, 'location' => $europe, 'price' => 20),
// Specifically for France - only 10 GBParray('method' => $post, 'location' => $france, 'price' => 10),
)
));

You can start to select which shipping applies to each purchase item.

$brand_purchase = Jam::find('brand_purchase', 1);
// If you want to set the informaction explicitly on which purchase_item what shipping_group to use$brand_purchase->build('shipping', array(
'items' => array(
array(
'purchase_item' => $brand_purchase->items[0],
'shipping_group' => $brand_purchase->items[0]->reference->shipping()->groups[0],
),
)
));
// Or if you want ones selected automatically, based on a preffered shipping method and purchaser location$post = Jam::find('shipping_method', 'Post');
$france = Jam::find('location', 'France');
$brand_purchase_shipping = $brand_purchase->build('shipping', array(
'location' => $france,
));
$brand_purchase_shipping->build_items_from($brand_purchase->items, $post);

Having configured that, you can now call update_items() method on the purchase / brand_purchase, adding to the purchase_items a shipping item.

$brand_purchase->update_items();
echo$brand_purchase->items_count('shipping'); // should return 1

Shipping Groups and Price Calculations

Each shipping group has several properties that affect how much muney the shipping of this item will cost:

  • price - this is the base price for shipping of 1 item.
  • additional_item_price - for more than one item, the second, third, etc items require this price, instead of the base one.
  • discount_threshold - whenever the brand_purchase is more than this amount - free shipping

Here are some examples:

If an item costs 10, with additional_item_price of 6, then you will pay 10+6+6 for 3 of the same item.

Also items are grouped per shipping method, per "ships_from" location so 3 different item shipped by post will be grouped. Only the most expensive base price will be used, all others will use additional_item_price. So:

Item 1: price 10, additional_item_price 6, quantity: 3
Item 2: price 12, additional_item_price 8, quantity: 2
Total Price will be (12 + 8) + 6 * 3

When searching for a country, the most specific one will be used for calculation, so if you are shipping for France, and you have a shipping_group for Europe, and one for France, the second one will be used.

Advanced Item Splitting

If you want to allow people to use different methods for different products, here is how you might accomplish this:

First of all - finding all purchase_items that can / cannot ship to your country

$available = $brand_purchase->items(array('can_ship' => TRUE));
$not_shippable = $brand_purchase->items(array('can_ship' => FALSE));

If you want to be more precise, you can get available items, but grouped by available shipping methods, so that if you have purchase_items that can ship with both post and courier and other that can ship only with post, they will be in different groups:

$group_shipping_methods = $brand_purchase->group_shipping_methods()
foreach ($group_shipping_methodsas$group)
{
foreach ($group->group_shipping_items() as$items)
{
// Get all the purchase items, shippable to this location by this method.$items->purchase_items;
// Calculate the price of these items, provide a total price to remove ones that are discounted based on it.$items->total_price();
// Delivery$items->total_delivery_time();
}
}

Delivery Times

This shipping module comes with extensive support for calculating delivery times.

Model_Shipping_Group has "delivery_time" - min - max workdays to deliver the item. Model_Shipping has process_time - min - max workdays to 'build' the item. Both of these are Jam_Ranges, and combined represent the total_delivery_time for a specific location.

Model_Shipping has this interface:

$france = Jam::find('locaiton', 'France');
$shipping = $product->shipping();
// To get a Jam_Range object only for the delivery to that location$shipping->delivery_time_for($france);
// To get a Jam_Range for delivery + processing for a specific country$shipping->total_delivery_time_for($france);

The shippable purchase behavior also adds some methods to the Model_Brand_Purchase for handling delivery time calculations:

// Get the Jam_Range object for the delivery time for the brand_purchase$brand_purchase->total_delivery_time();
// Get the Jam_Range object if the dates that the purchase will arraive// This is calculate based on the time the payment was made. If its not yet payed purchase, the current time is used.$brand_purchase->delivery_time_dates();

Shipping Address

By default as shipping address is used the billing address of the purchase. If you want to change that address, you'll have to change the shipping_same_as_billing field and set the shipping_address association, which is the same Model_Address object. After that all the calculation will take the country of shiping_address instead of billing_address:

$purchase = Jam::find('purchase', 1);
$purchase->shipping_same_as_billing = FALSE;
$purchase->build('shipping_address', array(
'country' => Jam::find('country', 'United Kingdom'),
'line1' => 'Street 1',
// ...
));
## LicenseCopyright (c) 2012-2013, OpenBuildings Ltd. Developed by Ivan Kerin as part of [clippings.com](http://clippings.com)
Under BSD-3-Clause license, read LICENSE file.

About

Shipping for OpenBuildings/purchases

Resources

Contributing

Stars

0 stars

Watchers

10 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Purchases Shipping

Build StatusScrutinizer Quality ScoreCode CoverageLatest Stable Version

Usage

Purchase_items that you want to ship must implement Shippable, like this:

class Model_Product extends Jam_Model implements Sellable, Shippable {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
$meta
->associations(array(
'shipping' => Jam::association('belongsto', array('inverse_of' => 'products')),
))
->fields(array(
'id' => Jam::field('primary'),
'name' => Jam::field('string'),
'currency' => Jam::field('string'),
'price' => Jam::field('price'),
))
->validator('type', 'price', 'quantity', array(
'present' => TRUE
));
}
// Implement Sellablepublicfunctionprice(Model_Purchase_Item$item)
{
return$this->price;
}
// Implement Sellablepublicfunctioncurrency()
{
return$this->currency;
}
// Implement Shippable// Must return a ``Model_Shipping`` object holding all the data for the shippingpublicfunctionshipping()
{
return$this->shipping;
}
// Implement Shippable// Must return a boolean whether or not the product ships can to that locationpublicfunctionships_to(Model_Location$location)
{
return$this->shipping ? $this->shipping->ships_to($location) : FALSE;
}
}
class Model_Purchase_Item_Product extends Kohana_Model_Purchase_Item_Product {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_purchase_item' => Jam::behavior('shippable_purchase_item'),
));
}
}
class Model_Shipping extends Kohana_Model_Shipping {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->associations(array(
'products' => Jam::association('hasmany', [
'inverse_of' => 'shipping',
]),
));
}
}

Also you need to add the shippable purchase to your purchase and brand purchase:

class Model_Brand_Purchase extends Kohana_Model_Brand_Purchase {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_brand_purchase' => Jam::behavior('shippable_brand_purchase'),
));
}
}
class Model_Purchase extends Kohana_Model_Purchase {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_purchase' => Jam::behavior('shippable_purchase'),
));
}
}

This behaviors will add the 'shipping' association to the brand_pruchase, also listen to update_items event and add a shipping purchase_item, and listen to the filter_items event, adding some more flags to filter by.

Once you have added the shipping data to your products:

$post = Jam::find('shipping_method', 'Post');
$europe = Jam::find('location', 'Europe');
$france = Jam::find('location', 'France');
$product->shipping = Jam::create('shipping', array(
'currency' => 'GBP',
'ships_from' => $france,
'groups' => array(
// Ships to all of Europe for 20 GBParray('method' => $post, 'location' => $europe, 'price' => 20),
// Specifically for France - only 10 GBParray('method' => $post, 'location' => $france, 'price' => 10),
)
));

You can start to select which shipping applies to each purchase item.

$brand_purchase = Jam::find('brand_purchase', 1);
// If you want to set the informaction explicitly on which purchase_item what shipping_group to use$brand_purchase->build('shipping', array(
'items' => array(
array(
'purchase_item' => $brand_purchase->items[0],
'shipping_group' => $brand_purchase->items[0]->reference->shipping()->groups[0],
),
)
));
// Or if you want ones selected automatically, based on a preffered shipping method and purchaser location$post = Jam::find('shipping_method', 'Post');
$france = Jam::find('location', 'France');
$brand_purchase_shipping = $brand_purchase->build('shipping', array(
'location' => $france,
));
$brand_purchase_shipping->build_items_from($brand_purchase->items, $post);

Having configured that, you can now call update_items() method on the purchase / brand_purchase, adding to the purchase_items a shipping item.

$brand_purchase->update_items();
echo$brand_purchase->items_count('shipping'); // should return 1

Shipping Groups and Price Calculations

Each shipping group has several properties that affect how much muney the shipping of this item will cost:

  • price - this is the base price for shipping of 1 item.
  • additional_item_price - for more than one item, the second, third, etc items require this price, instead of the base one.
  • discount_threshold - whenever the brand_purchase is more than this amount - free shipping

Here are some examples:

If an item costs 10, with additional_item_price of 6, then you will pay 10+6+6 for 3 of the same item.

Also items are grouped per shipping method, per "ships_from" location so 3 different item shipped by post will be grouped. Only the most expensive base price will be used, all others will use additional_item_price. So:

Item 1: price 10, additional_item_price 6, quantity: 3
Item 2: price 12, additional_item_price 8, quantity: 2
Total Price will be (12 + 8) + 6 * 3

When searching for a country, the most specific one will be used for calculation, so if you are shipping for France, and you have a shipping_group for Europe, and one for France, the second one will be used.

Advanced Item Splitting

If you want to allow people to use different methods for different products, here is how you might accomplish this:

First of all - finding all purchase_items that can / cannot ship to your country

$available = $brand_purchase->items(array('can_ship' => TRUE));
$not_shippable = $brand_purchase->items(array('can_ship' => FALSE));

If you want to be more precise, you can get available items, but grouped by available shipping methods, so that if you have purchase_items that can ship with both post and courier and other that can ship only with post, they will be in different groups:

$group_shipping_methods = $brand_purchase->group_shipping_methods()
foreach ($group_shipping_methodsas$group)
{
foreach ($group->group_shipping_items() as$items)
{
// Get all the purchase items, shippable to this location by this method.$items->purchase_items;
// Calculate the price of these items, provide a total price to remove ones that are discounted based on it.$items->total_price();
// Delivery$items->total_delivery_time();
}
}

Delivery Times

This shipping module comes with extensive support for calculating delivery times.

Model_Shipping_Group has "delivery_time" - min - max workdays to deliver the item. Model_Shipping has process_time - min - max workdays to 'build' the item. Both of these are Jam_Ranges, and combined represent the total_delivery_time for a specific location.

Model_Shipping has this interface:

$france = Jam::find('locaiton', 'France');
$shipping = $product->shipping();
// To get a Jam_Range object only for the delivery to that location$shipping->delivery_time_for($france);
// To get a Jam_Range for delivery + processing for a specific country$shipping->total_delivery_time_for($france);

The shippable purchase behavior also adds some methods to the Model_Brand_Purchase for handling delivery time calculations:

// Get the Jam_Range object for the delivery time for the brand_purchase$brand_purchase->total_delivery_time();
// Get the Jam_Range object if the dates that the purchase will arraive// This is calculate based on the time the payment was made. If its not yet payed purchase, the current time is used.$brand_purchase->delivery_time_dates();

Shipping Address

By default as shipping address is used the billing address of the purchase. If you want to change that address, you'll have to change the shipping_same_as_billing field and set the shipping_address association, which is the same Model_Address object. After that all the calculation will take the country of shiping_address instead of billing_address:

$purchase = Jam::find('purchase', 1);
$purchase->shipping_same_as_billing = FALSE;
$purchase->build('shipping_address', array(
'country' => Jam::find('country', 'United Kingdom'),
'line1' => 'Street 1',
// ...
));
## LicenseCopyright (c) 2012-2013, OpenBuildings Ltd. Developed by Ivan Kerin as part of [clippings.com](http://clippings.com)
Under BSD-3-Clause license, read LICENSE file.

About

Shipping for OpenBuildings/purchases

Resources

Contributing

Stars

0 stars

Watchers

10 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Purchases Shipping

Build StatusScrutinizer Quality ScoreCode CoverageLatest Stable Version

Usage

Purchase_items that you want to ship must implement Shippable, like this:

class Model_Product extends Jam_Model implements Sellable, Shippable {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
$meta
->associations(array(
'shipping' => Jam::association('belongsto', array('inverse_of' => 'products')),
))
->fields(array(
'id' => Jam::field('primary'),
'name' => Jam::field('string'),
'currency' => Jam::field('string'),
'price' => Jam::field('price'),
))
->validator('type', 'price', 'quantity', array(
'present' => TRUE
));
}
// Implement Sellablepublicfunctionprice(Model_Purchase_Item$item)
{
return$this->price;
}
// Implement Sellablepublicfunctioncurrency()
{
return$this->currency;
}
// Implement Shippable// Must return a ``Model_Shipping`` object holding all the data for the shippingpublicfunctionshipping()
{
return$this->shipping;
}
// Implement Shippable// Must return a boolean whether or not the product ships can to that locationpublicfunctionships_to(Model_Location$location)
{
return$this->shipping ? $this->shipping->ships_to($location) : FALSE;
}
}
class Model_Purchase_Item_Product extends Kohana_Model_Purchase_Item_Product {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_purchase_item' => Jam::behavior('shippable_purchase_item'),
));
}
}
class Model_Shipping extends Kohana_Model_Shipping {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->associations(array(
'products' => Jam::association('hasmany', [
'inverse_of' => 'shipping',
]),
));
}
}

Also you need to add the shippable purchase to your purchase and brand purchase:

class Model_Brand_Purchase extends Kohana_Model_Brand_Purchase {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_brand_purchase' => Jam::behavior('shippable_brand_purchase'),
));
}
}
class Model_Purchase extends Kohana_Model_Purchase {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_purchase' => Jam::behavior('shippable_purchase'),
));
}
}

This behaviors will add the 'shipping' association to the brand_pruchase, also listen to update_items event and add a shipping purchase_item, and listen to the filter_items event, adding some more flags to filter by.

Once you have added the shipping data to your products:

$post = Jam::find('shipping_method', 'Post');
$europe = Jam::find('location', 'Europe');
$france = Jam::find('location', 'France');
$product->shipping = Jam::create('shipping', array(
'currency' => 'GBP',
'ships_from' => $france,
'groups' => array(
// Ships to all of Europe for 20 GBParray('method' => $post, 'location' => $europe, 'price' => 20),
// Specifically for France - only 10 GBParray('method' => $post, 'location' => $france, 'price' => 10),
)
));

You can start to select which shipping applies to each purchase item.

$brand_purchase = Jam::find('brand_purchase', 1);
// If you want to set the informaction explicitly on which purchase_item what shipping_group to use$brand_purchase->build('shipping', array(
'items' => array(
array(
'purchase_item' => $brand_purchase->items[0],
'shipping_group' => $brand_purchase->items[0]->reference->shipping()->groups[0],
),
)
));
// Or if you want ones selected automatically, based on a preffered shipping method and purchaser location$post = Jam::find('shipping_method', 'Post');
$france = Jam::find('location', 'France');
$brand_purchase_shipping = $brand_purchase->build('shipping', array(
'location' => $france,
));
$brand_purchase_shipping->build_items_from($brand_purchase->items, $post);

Having configured that, you can now call update_items() method on the purchase / brand_purchase, adding to the purchase_items a shipping item.

$brand_purchase->update_items();
echo$brand_purchase->items_count('shipping'); // should return 1

Shipping Groups and Price Calculations

Each shipping group has several properties that affect how much muney the shipping of this item will cost:

  • price - this is the base price for shipping of 1 item.
  • additional_item_price - for more than one item, the second, third, etc items require this price, instead of the base one.
  • discount_threshold - whenever the brand_purchase is more than this amount - free shipping

Here are some examples:

If an item costs 10, with additional_item_price of 6, then you will pay 10+6+6 for 3 of the same item.

Also items are grouped per shipping method, per "ships_from" location so 3 different item shipped by post will be grouped. Only the most expensive base price will be used, all others will use additional_item_price. So:

Item 1: price 10, additional_item_price 6, quantity: 3
Item 2: price 12, additional_item_price 8, quantity: 2
Total Price will be (12 + 8) + 6 * 3

When searching for a country, the most specific one will be used for calculation, so if you are shipping for France, and you have a shipping_group for Europe, and one for France, the second one will be used.

Advanced Item Splitting

If you want to allow people to use different methods for different products, here is how you might accomplish this:

First of all - finding all purchase_items that can / cannot ship to your country

$available = $brand_purchase->items(array('can_ship' => TRUE));
$not_shippable = $brand_purchase->items(array('can_ship' => FALSE));

If you want to be more precise, you can get available items, but grouped by available shipping methods, so that if you have purchase_items that can ship with both post and courier and other that can ship only with post, they will be in different groups:

$group_shipping_methods = $brand_purchase->group_shipping_methods()
foreach ($group_shipping_methodsas$group)
{
foreach ($group->group_shipping_items() as$items)
{
// Get all the purchase items, shippable to this location by this method.$items->purchase_items;
// Calculate the price of these items, provide a total price to remove ones that are discounted based on it.$items->total_price();
// Delivery$items->total_delivery_time();
}
}

Delivery Times

This shipping module comes with extensive support for calculating delivery times.

Model_Shipping_Group has "delivery_time" - min - max workdays to deliver the item. Model_Shipping has process_time - min - max workdays to 'build' the item. Both of these are Jam_Ranges, and combined represent the total_delivery_time for a specific location.

Model_Shipping has this interface:

$france = Jam::find('locaiton', 'France');
$shipping = $product->shipping();
// To get a Jam_Range object only for the delivery to that location$shipping->delivery_time_for($france);
// To get a Jam_Range for delivery + processing for a specific country$shipping->total_delivery_time_for($france);

The shippable purchase behavior also adds some methods to the Model_Brand_Purchase for handling delivery time calculations:

// Get the Jam_Range object for the delivery time for the brand_purchase$brand_purchase->total_delivery_time();
// Get the Jam_Range object if the dates that the purchase will arraive// This is calculate based on the time the payment was made. If its not yet payed purchase, the current time is used.$brand_purchase->delivery_time_dates();

Shipping Address

By default as shipping address is used the billing address of the purchase. If you want to change that address, you'll have to change the shipping_same_as_billing field and set the shipping_address association, which is the same Model_Address object. After that all the calculation will take the country of shiping_address instead of billing_address:

$purchase = Jam::find('purchase', 1);
$purchase->shipping_same_as_billing = FALSE;
$purchase->build('shipping_address', array(
'country' => Jam::find('country', 'United Kingdom'),
'line1' => 'Street 1',
// ...
));
## LicenseCopyright (c) 2012-2013, OpenBuildings Ltd. Developed by Ivan Kerin as part of [clippings.com](http://clippings.com)
Under BSD-3-Clause license, read LICENSE file.

About

Shipping for OpenBuildings/purchases

Resources

Contributing

Stars

0 stars

Watchers

10 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Purchases Shipping

Build StatusScrutinizer Quality ScoreCode CoverageLatest Stable Version

Usage

Purchase_items that you want to ship must implement Shippable, like this:

class Model_Product extends Jam_Model implements Sellable, Shippable {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
$meta
->associations(array(
'shipping' => Jam::association('belongsto', array('inverse_of' => 'products')),
))
->fields(array(
'id' => Jam::field('primary'),
'name' => Jam::field('string'),
'currency' => Jam::field('string'),
'price' => Jam::field('price'),
))
->validator('type', 'price', 'quantity', array(
'present' => TRUE
));
}
// Implement Sellablepublicfunctionprice(Model_Purchase_Item$item)
{
return$this->price;
}
// Implement Sellablepublicfunctioncurrency()
{
return$this->currency;
}
// Implement Shippable// Must return a ``Model_Shipping`` object holding all the data for the shippingpublicfunctionshipping()
{
return$this->shipping;
}
// Implement Shippable// Must return a boolean whether or not the product ships can to that locationpublicfunctionships_to(Model_Location$location)
{
return$this->shipping ? $this->shipping->ships_to($location) : FALSE;
}
}
class Model_Purchase_Item_Product extends Kohana_Model_Purchase_Item_Product {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_purchase_item' => Jam::behavior('shippable_purchase_item'),
));
}
}
class Model_Shipping extends Kohana_Model_Shipping {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->associations(array(
'products' => Jam::association('hasmany', [
'inverse_of' => 'shipping',
]),
));
}
}

Also you need to add the shippable purchase to your purchase and brand purchase:

class Model_Brand_Purchase extends Kohana_Model_Brand_Purchase {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_brand_purchase' => Jam::behavior('shippable_brand_purchase'),
));
}
}
class Model_Purchase extends Kohana_Model_Purchase {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_purchase' => Jam::behavior('shippable_purchase'),
));
}
}

This behaviors will add the 'shipping' association to the brand_pruchase, also listen to update_items event and add a shipping purchase_item, and listen to the filter_items event, adding some more flags to filter by.

Once you have added the shipping data to your products:

$post = Jam::find('shipping_method', 'Post');
$europe = Jam::find('location', 'Europe');
$france = Jam::find('location', 'France');
$product->shipping = Jam::create('shipping', array(
'currency' => 'GBP',
'ships_from' => $france,
'groups' => array(
// Ships to all of Europe for 20 GBParray('method' => $post, 'location' => $europe, 'price' => 20),
// Specifically for France - only 10 GBParray('method' => $post, 'location' => $france, 'price' => 10),
)
));

You can start to select which shipping applies to each purchase item.

$brand_purchase = Jam::find('brand_purchase', 1);
// If you want to set the informaction explicitly on which purchase_item what shipping_group to use$brand_purchase->build('shipping', array(
'items' => array(
array(
'purchase_item' => $brand_purchase->items[0],
'shipping_group' => $brand_purchase->items[0]->reference->shipping()->groups[0],
),
)
));
// Or if you want ones selected automatically, based on a preffered shipping method and purchaser location$post = Jam::find('shipping_method', 'Post');
$france = Jam::find('location', 'France');
$brand_purchase_shipping = $brand_purchase->build('shipping', array(
'location' => $france,
));
$brand_purchase_shipping->build_items_from($brand_purchase->items, $post);

Having configured that, you can now call update_items() method on the purchase / brand_purchase, adding to the purchase_items a shipping item.

$brand_purchase->update_items();
echo$brand_purchase->items_count('shipping'); // should return 1

Shipping Groups and Price Calculations

Each shipping group has several properties that affect how much muney the shipping of this item will cost:

  • price - this is the base price for shipping of 1 item.
  • additional_item_price - for more than one item, the second, third, etc items require this price, instead of the base one.
  • discount_threshold - whenever the brand_purchase is more than this amount - free shipping

Here are some examples:

If an item costs 10, with additional_item_price of 6, then you will pay 10+6+6 for 3 of the same item.

Also items are grouped per shipping method, per "ships_from" location so 3 different item shipped by post will be grouped. Only the most expensive base price will be used, all others will use additional_item_price. So:

Item 1: price 10, additional_item_price 6, quantity: 3
Item 2: price 12, additional_item_price 8, quantity: 2
Total Price will be (12 + 8) + 6 * 3

When searching for a country, the most specific one will be used for calculation, so if you are shipping for France, and you have a shipping_group for Europe, and one for France, the second one will be used.

Advanced Item Splitting

If you want to allow people to use different methods for different products, here is how you might accomplish this:

First of all - finding all purchase_items that can / cannot ship to your country

$available = $brand_purchase->items(array('can_ship' => TRUE));
$not_shippable = $brand_purchase->items(array('can_ship' => FALSE));

If you want to be more precise, you can get available items, but grouped by available shipping methods, so that if you have purchase_items that can ship with both post and courier and other that can ship only with post, they will be in different groups:

$group_shipping_methods = $brand_purchase->group_shipping_methods()
foreach ($group_shipping_methodsas$group)
{
foreach ($group->group_shipping_items() as$items)
{
// Get all the purchase items, shippable to this location by this method.$items->purchase_items;
// Calculate the price of these items, provide a total price to remove ones that are discounted based on it.$items->total_price();
// Delivery$items->total_delivery_time();
}
}

Delivery Times

This shipping module comes with extensive support for calculating delivery times.

Model_Shipping_Group has "delivery_time" - min - max workdays to deliver the item. Model_Shipping has process_time - min - max workdays to 'build' the item. Both of these are Jam_Ranges, and combined represent the total_delivery_time for a specific location.

Model_Shipping has this interface:

$france = Jam::find('locaiton', 'France');
$shipping = $product->shipping();
// To get a Jam_Range object only for the delivery to that location$shipping->delivery_time_for($france);
// To get a Jam_Range for delivery + processing for a specific country$shipping->total_delivery_time_for($france);

The shippable purchase behavior also adds some methods to the Model_Brand_Purchase for handling delivery time calculations:

// Get the Jam_Range object for the delivery time for the brand_purchase$brand_purchase->total_delivery_time();
// Get the Jam_Range object if the dates that the purchase will arraive// This is calculate based on the time the payment was made. If its not yet payed purchase, the current time is used.$brand_purchase->delivery_time_dates();

Shipping Address

By default as shipping address is used the billing address of the purchase. If you want to change that address, you'll have to change the shipping_same_as_billing field and set the shipping_address association, which is the same Model_Address object. After that all the calculation will take the country of shiping_address instead of billing_address:

$purchase = Jam::find('purchase', 1);
$purchase->shipping_same_as_billing = FALSE;
$purchase->build('shipping_address', array(
'country' => Jam::find('country', 'United Kingdom'),
'line1' => 'Street 1',
// ...
));
## LicenseCopyright (c) 2012-2013, OpenBuildings Ltd. Developed by Ivan Kerin as part of [clippings.com](http://clippings.com)
Under BSD-3-Clause license, read LICENSE file.

About

Shipping for OpenBuildings/purchases

Resources

Contributing

Stars

0 stars

Watchers

10 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Purchases Shipping

Build StatusScrutinizer Quality ScoreCode CoverageLatest Stable Version

Usage

Purchase_items that you want to ship must implement Shippable, like this:

class Model_Product extends Jam_Model implements Sellable, Shippable {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
$meta
->associations(array(
'shipping' => Jam::association('belongsto', array('inverse_of' => 'products')),
))
->fields(array(
'id' => Jam::field('primary'),
'name' => Jam::field('string'),
'currency' => Jam::field('string'),
'price' => Jam::field('price'),
))
->validator('type', 'price', 'quantity', array(
'present' => TRUE
));
}
// Implement Sellablepublicfunctionprice(Model_Purchase_Item$item)
{
return$this->price;
}
// Implement Sellablepublicfunctioncurrency()
{
return$this->currency;
}
// Implement Shippable// Must return a ``Model_Shipping`` object holding all the data for the shippingpublicfunctionshipping()
{
return$this->shipping;
}
// Implement Shippable// Must return a boolean whether or not the product ships can to that locationpublicfunctionships_to(Model_Location$location)
{
return$this->shipping ? $this->shipping->ships_to($location) : FALSE;
}
}
class Model_Purchase_Item_Product extends Kohana_Model_Purchase_Item_Product {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_purchase_item' => Jam::behavior('shippable_purchase_item'),
));
}
}
class Model_Shipping extends Kohana_Model_Shipping {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->associations(array(
'products' => Jam::association('hasmany', [
'inverse_of' => 'shipping',
]),
));
}
}

Also you need to add the shippable purchase to your purchase and brand purchase:

class Model_Brand_Purchase extends Kohana_Model_Brand_Purchase {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_brand_purchase' => Jam::behavior('shippable_brand_purchase'),
));
}
}
class Model_Purchase extends Kohana_Model_Purchase {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_purchase' => Jam::behavior('shippable_purchase'),
));
}
}

This behaviors will add the 'shipping' association to the brand_pruchase, also listen to update_items event and add a shipping purchase_item, and listen to the filter_items event, adding some more flags to filter by.

Once you have added the shipping data to your products:

$post = Jam::find('shipping_method', 'Post');
$europe = Jam::find('location', 'Europe');
$france = Jam::find('location', 'France');
$product->shipping = Jam::create('shipping', array(
'currency' => 'GBP',
'ships_from' => $france,
'groups' => array(
// Ships to all of Europe for 20 GBParray('method' => $post, 'location' => $europe, 'price' => 20),
// Specifically for France - only 10 GBParray('method' => $post, 'location' => $france, 'price' => 10),
)
));

You can start to select which shipping applies to each purchase item.

$brand_purchase = Jam::find('brand_purchase', 1);
// If you want to set the informaction explicitly on which purchase_item what shipping_group to use$brand_purchase->build('shipping', array(
'items' => array(
array(
'purchase_item' => $brand_purchase->items[0],
'shipping_group' => $brand_purchase->items[0]->reference->shipping()->groups[0],
),
)
));
// Or if you want ones selected automatically, based on a preffered shipping method and purchaser location$post = Jam::find('shipping_method', 'Post');
$france = Jam::find('location', 'France');
$brand_purchase_shipping = $brand_purchase->build('shipping', array(
'location' => $france,
));
$brand_purchase_shipping->build_items_from($brand_purchase->items, $post);

Having configured that, you can now call update_items() method on the purchase / brand_purchase, adding to the purchase_items a shipping item.

$brand_purchase->update_items();
echo$brand_purchase->items_count('shipping'); // should return 1

Shipping Groups and Price Calculations

Each shipping group has several properties that affect how much muney the shipping of this item will cost:

  • price - this is the base price for shipping of 1 item.
  • additional_item_price - for more than one item, the second, third, etc items require this price, instead of the base one.
  • discount_threshold - whenever the brand_purchase is more than this amount - free shipping

Here are some examples:

If an item costs 10, with additional_item_price of 6, then you will pay 10+6+6 for 3 of the same item.

Also items are grouped per shipping method, per "ships_from" location so 3 different item shipped by post will be grouped. Only the most expensive base price will be used, all others will use additional_item_price. So:

Item 1: price 10, additional_item_price 6, quantity: 3
Item 2: price 12, additional_item_price 8, quantity: 2
Total Price will be (12 + 8) + 6 * 3

When searching for a country, the most specific one will be used for calculation, so if you are shipping for France, and you have a shipping_group for Europe, and one for France, the second one will be used.

Advanced Item Splitting

If you want to allow people to use different methods for different products, here is how you might accomplish this:

First of all - finding all purchase_items that can / cannot ship to your country

$available = $brand_purchase->items(array('can_ship' => TRUE));
$not_shippable = $brand_purchase->items(array('can_ship' => FALSE));

If you want to be more precise, you can get available items, but grouped by available shipping methods, so that if you have purchase_items that can ship with both post and courier and other that can ship only with post, they will be in different groups:

$group_shipping_methods = $brand_purchase->group_shipping_methods()
foreach ($group_shipping_methodsas$group)
{
foreach ($group->group_shipping_items() as$items)
{
// Get all the purchase items, shippable to this location by this method.$items->purchase_items;
// Calculate the price of these items, provide a total price to remove ones that are discounted based on it.$items->total_price();
// Delivery$items->total_delivery_time();
}
}

Delivery Times

This shipping module comes with extensive support for calculating delivery times.

Model_Shipping_Group has "delivery_time" - min - max workdays to deliver the item. Model_Shipping has process_time - min - max workdays to 'build' the item. Both of these are Jam_Ranges, and combined represent the total_delivery_time for a specific location.

Model_Shipping has this interface:

$france = Jam::find('locaiton', 'France');
$shipping = $product->shipping();
// To get a Jam_Range object only for the delivery to that location$shipping->delivery_time_for($france);
// To get a Jam_Range for delivery + processing for a specific country$shipping->total_delivery_time_for($france);

The shippable purchase behavior also adds some methods to the Model_Brand_Purchase for handling delivery time calculations:

// Get the Jam_Range object for the delivery time for the brand_purchase$brand_purchase->total_delivery_time();
// Get the Jam_Range object if the dates that the purchase will arraive// This is calculate based on the time the payment was made. If its not yet payed purchase, the current time is used.$brand_purchase->delivery_time_dates();

Shipping Address

By default as shipping address is used the billing address of the purchase. If you want to change that address, you'll have to change the shipping_same_as_billing field and set the shipping_address association, which is the same Model_Address object. After that all the calculation will take the country of shiping_address instead of billing_address:

$purchase = Jam::find('purchase', 1);
$purchase->shipping_same_as_billing = FALSE;
$purchase->build('shipping_address', array(
'country' => Jam::find('country', 'United Kingdom'),
'line1' => 'Street 1',
// ...
));
## LicenseCopyright (c) 2012-2013, OpenBuildings Ltd. Developed by Ivan Kerin as part of [clippings.com](http://clippings.com)
Under BSD-3-Clause license, read LICENSE file.

About

Shipping for OpenBuildings/purchases

Resources

Contributing

Stars

0 stars

Watchers

10 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Purchases Shipping

Build StatusScrutinizer Quality ScoreCode CoverageLatest Stable Version

Usage

Purchase_items that you want to ship must implement Shippable, like this:

class Model_Product extends Jam_Model implements Sellable, Shippable {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
$meta
->associations(array(
'shipping' => Jam::association('belongsto', array('inverse_of' => 'products')),
))
->fields(array(
'id' => Jam::field('primary'),
'name' => Jam::field('string'),
'currency' => Jam::field('string'),
'price' => Jam::field('price'),
))
->validator('type', 'price', 'quantity', array(
'present' => TRUE
));
}
// Implement Sellablepublicfunctionprice(Model_Purchase_Item$item)
{
return$this->price;
}
// Implement Sellablepublicfunctioncurrency()
{
return$this->currency;
}
// Implement Shippable// Must return a ``Model_Shipping`` object holding all the data for the shippingpublicfunctionshipping()
{
return$this->shipping;
}
// Implement Shippable// Must return a boolean whether or not the product ships can to that locationpublicfunctionships_to(Model_Location$location)
{
return$this->shipping ? $this->shipping->ships_to($location) : FALSE;
}
}
class Model_Purchase_Item_Product extends Kohana_Model_Purchase_Item_Product {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_purchase_item' => Jam::behavior('shippable_purchase_item'),
));
}
}
class Model_Shipping extends Kohana_Model_Shipping {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->associations(array(
'products' => Jam::association('hasmany', [
'inverse_of' => 'shipping',
]),
));
}
}

Also you need to add the shippable purchase to your purchase and brand purchase:

class Model_Brand_Purchase extends Kohana_Model_Brand_Purchase {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_brand_purchase' => Jam::behavior('shippable_brand_purchase'),
));
}
}
class Model_Purchase extends Kohana_Model_Purchase {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_purchase' => Jam::behavior('shippable_purchase'),
));
}
}

This behaviors will add the 'shipping' association to the brand_pruchase, also listen to update_items event and add a shipping purchase_item, and listen to the filter_items event, adding some more flags to filter by.

Once you have added the shipping data to your products:

$post = Jam::find('shipping_method', 'Post');
$europe = Jam::find('location', 'Europe');
$france = Jam::find('location', 'France');
$product->shipping = Jam::create('shipping', array(
'currency' => 'GBP',
'ships_from' => $france,
'groups' => array(
// Ships to all of Europe for 20 GBParray('method' => $post, 'location' => $europe, 'price' => 20),
// Specifically for France - only 10 GBParray('method' => $post, 'location' => $france, 'price' => 10),
)
));

You can start to select which shipping applies to each purchase item.

$brand_purchase = Jam::find('brand_purchase', 1);
// If you want to set the informaction explicitly on which purchase_item what shipping_group to use$brand_purchase->build('shipping', array(
'items' => array(
array(
'purchase_item' => $brand_purchase->items[0],
'shipping_group' => $brand_purchase->items[0]->reference->shipping()->groups[0],
),
)
));
// Or if you want ones selected automatically, based on a preffered shipping method and purchaser location$post = Jam::find('shipping_method', 'Post');
$france = Jam::find('location', 'France');
$brand_purchase_shipping = $brand_purchase->build('shipping', array(
'location' => $france,
));
$brand_purchase_shipping->build_items_from($brand_purchase->items, $post);

Having configured that, you can now call update_items() method on the purchase / brand_purchase, adding to the purchase_items a shipping item.

$brand_purchase->update_items();
echo$brand_purchase->items_count('shipping'); // should return 1

Shipping Groups and Price Calculations

Each shipping group has several properties that affect how much muney the shipping of this item will cost:

  • price - this is the base price for shipping of 1 item.
  • additional_item_price - for more than one item, the second, third, etc items require this price, instead of the base one.
  • discount_threshold - whenever the brand_purchase is more than this amount - free shipping

Here are some examples:

If an item costs 10, with additional_item_price of 6, then you will pay 10+6+6 for 3 of the same item.

Also items are grouped per shipping method, per "ships_from" location so 3 different item shipped by post will be grouped. Only the most expensive base price will be used, all others will use additional_item_price. So:

Item 1: price 10, additional_item_price 6, quantity: 3
Item 2: price 12, additional_item_price 8, quantity: 2
Total Price will be (12 + 8) + 6 * 3

When searching for a country, the most specific one will be used for calculation, so if you are shipping for France, and you have a shipping_group for Europe, and one for France, the second one will be used.

Advanced Item Splitting

If you want to allow people to use different methods for different products, here is how you might accomplish this:

First of all - finding all purchase_items that can / cannot ship to your country

$available = $brand_purchase->items(array('can_ship' => TRUE));
$not_shippable = $brand_purchase->items(array('can_ship' => FALSE));

If you want to be more precise, you can get available items, but grouped by available shipping methods, so that if you have purchase_items that can ship with both post and courier and other that can ship only with post, they will be in different groups:

$group_shipping_methods = $brand_purchase->group_shipping_methods()
foreach ($group_shipping_methodsas$group)
{
foreach ($group->group_shipping_items() as$items)
{
// Get all the purchase items, shippable to this location by this method.$items->purchase_items;
// Calculate the price of these items, provide a total price to remove ones that are discounted based on it.$items->total_price();
// Delivery$items->total_delivery_time();
}
}

Delivery Times

This shipping module comes with extensive support for calculating delivery times.

Model_Shipping_Group has "delivery_time" - min - max workdays to deliver the item. Model_Shipping has process_time - min - max workdays to 'build' the item. Both of these are Jam_Ranges, and combined represent the total_delivery_time for a specific location.

Model_Shipping has this interface:

$france = Jam::find('locaiton', 'France');
$shipping = $product->shipping();
// To get a Jam_Range object only for the delivery to that location$shipping->delivery_time_for($france);
// To get a Jam_Range for delivery + processing for a specific country$shipping->total_delivery_time_for($france);

The shippable purchase behavior also adds some methods to the Model_Brand_Purchase for handling delivery time calculations:

// Get the Jam_Range object for the delivery time for the brand_purchase$brand_purchase->total_delivery_time();
// Get the Jam_Range object if the dates that the purchase will arraive// This is calculate based on the time the payment was made. If its not yet payed purchase, the current time is used.$brand_purchase->delivery_time_dates();

Shipping Address

By default as shipping address is used the billing address of the purchase. If you want to change that address, you'll have to change the shipping_same_as_billing field and set the shipping_address association, which is the same Model_Address object. After that all the calculation will take the country of shiping_address instead of billing_address:

$purchase = Jam::find('purchase', 1);
$purchase->shipping_same_as_billing = FALSE;
$purchase->build('shipping_address', array(
'country' => Jam::find('country', 'United Kingdom'),
'line1' => 'Street 1',
// ...
));
## LicenseCopyright (c) 2012-2013, OpenBuildings Ltd. Developed by Ivan Kerin as part of [clippings.com](http://clippings.com)
Under BSD-3-Clause license, read LICENSE file.

About

Shipping for OpenBuildings/purchases

Resources

Contributing

Stars

0 stars

Watchers

10 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Purchases Shipping

Build StatusScrutinizer Quality ScoreCode CoverageLatest Stable Version

Usage

Purchase_items that you want to ship must implement Shippable, like this:

class Model_Product extends Jam_Model implements Sellable, Shippable {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
$meta
->associations(array(
'shipping' => Jam::association('belongsto', array('inverse_of' => 'products')),
))
->fields(array(
'id' => Jam::field('primary'),
'name' => Jam::field('string'),
'currency' => Jam::field('string'),
'price' => Jam::field('price'),
))
->validator('type', 'price', 'quantity', array(
'present' => TRUE
));
}
// Implement Sellablepublicfunctionprice(Model_Purchase_Item$item)
{
return$this->price;
}
// Implement Sellablepublicfunctioncurrency()
{
return$this->currency;
}
// Implement Shippable// Must return a ``Model_Shipping`` object holding all the data for the shippingpublicfunctionshipping()
{
return$this->shipping;
}
// Implement Shippable// Must return a boolean whether or not the product ships can to that locationpublicfunctionships_to(Model_Location$location)
{
return$this->shipping ? $this->shipping->ships_to($location) : FALSE;
}
}
class Model_Purchase_Item_Product extends Kohana_Model_Purchase_Item_Product {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_purchase_item' => Jam::behavior('shippable_purchase_item'),
));
}
}
class Model_Shipping extends Kohana_Model_Shipping {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->associations(array(
'products' => Jam::association('hasmany', [
'inverse_of' => 'shipping',
]),
));
}
}

Also you need to add the shippable purchase to your purchase and brand purchase:

class Model_Brand_Purchase extends Kohana_Model_Brand_Purchase {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_brand_purchase' => Jam::behavior('shippable_brand_purchase'),
));
}
}
class Model_Purchase extends Kohana_Model_Purchase {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_purchase' => Jam::behavior('shippable_purchase'),
));
}
}

This behaviors will add the 'shipping' association to the brand_pruchase, also listen to update_items event and add a shipping purchase_item, and listen to the filter_items event, adding some more flags to filter by.

Once you have added the shipping data to your products:

$post = Jam::find('shipping_method', 'Post');
$europe = Jam::find('location', 'Europe');
$france = Jam::find('location', 'France');
$product->shipping = Jam::create('shipping', array(
'currency' => 'GBP',
'ships_from' => $france,
'groups' => array(
// Ships to all of Europe for 20 GBParray('method' => $post, 'location' => $europe, 'price' => 20),
// Specifically for France - only 10 GBParray('method' => $post, 'location' => $france, 'price' => 10),
)
));

You can start to select which shipping applies to each purchase item.

$brand_purchase = Jam::find('brand_purchase', 1);
// If you want to set the informaction explicitly on which purchase_item what shipping_group to use$brand_purchase->build('shipping', array(
'items' => array(
array(
'purchase_item' => $brand_purchase->items[0],
'shipping_group' => $brand_purchase->items[0]->reference->shipping()->groups[0],
),
)
));
// Or if you want ones selected automatically, based on a preffered shipping method and purchaser location$post = Jam::find('shipping_method', 'Post');
$france = Jam::find('location', 'France');
$brand_purchase_shipping = $brand_purchase->build('shipping', array(
'location' => $france,
));
$brand_purchase_shipping->build_items_from($brand_purchase->items, $post);

Having configured that, you can now call update_items() method on the purchase / brand_purchase, adding to the purchase_items a shipping item.

$brand_purchase->update_items();
echo$brand_purchase->items_count('shipping'); // should return 1

Shipping Groups and Price Calculations

Each shipping group has several properties that affect how much muney the shipping of this item will cost:

  • price - this is the base price for shipping of 1 item.
  • additional_item_price - for more than one item, the second, third, etc items require this price, instead of the base one.
  • discount_threshold - whenever the brand_purchase is more than this amount - free shipping

Here are some examples:

If an item costs 10, with additional_item_price of 6, then you will pay 10+6+6 for 3 of the same item.

Also items are grouped per shipping method, per "ships_from" location so 3 different item shipped by post will be grouped. Only the most expensive base price will be used, all others will use additional_item_price. So:

Item 1: price 10, additional_item_price 6, quantity: 3
Item 2: price 12, additional_item_price 8, quantity: 2
Total Price will be (12 + 8) + 6 * 3

When searching for a country, the most specific one will be used for calculation, so if you are shipping for France, and you have a shipping_group for Europe, and one for France, the second one will be used.

Advanced Item Splitting

If you want to allow people to use different methods for different products, here is how you might accomplish this:

First of all - finding all purchase_items that can / cannot ship to your country

$available = $brand_purchase->items(array('can_ship' => TRUE));
$not_shippable = $brand_purchase->items(array('can_ship' => FALSE));

If you want to be more precise, you can get available items, but grouped by available shipping methods, so that if you have purchase_items that can ship with both post and courier and other that can ship only with post, they will be in different groups:

$group_shipping_methods = $brand_purchase->group_shipping_methods()
foreach ($group_shipping_methodsas$group)
{
foreach ($group->group_shipping_items() as$items)
{
// Get all the purchase items, shippable to this location by this method.$items->purchase_items;
// Calculate the price of these items, provide a total price to remove ones that are discounted based on it.$items->total_price();
// Delivery$items->total_delivery_time();
}
}

Delivery Times

This shipping module comes with extensive support for calculating delivery times.

Model_Shipping_Group has "delivery_time" - min - max workdays to deliver the item. Model_Shipping has process_time - min - max workdays to 'build' the item. Both of these are Jam_Ranges, and combined represent the total_delivery_time for a specific location.

Model_Shipping has this interface:

$france = Jam::find('locaiton', 'France');
$shipping = $product->shipping();
// To get a Jam_Range object only for the delivery to that location$shipping->delivery_time_for($france);
// To get a Jam_Range for delivery + processing for a specific country$shipping->total_delivery_time_for($france);

The shippable purchase behavior also adds some methods to the Model_Brand_Purchase for handling delivery time calculations:

// Get the Jam_Range object for the delivery time for the brand_purchase$brand_purchase->total_delivery_time();
// Get the Jam_Range object if the dates that the purchase will arraive// This is calculate based on the time the payment was made. If its not yet payed purchase, the current time is used.$brand_purchase->delivery_time_dates();

Shipping Address

By default as shipping address is used the billing address of the purchase. If you want to change that address, you'll have to change the shipping_same_as_billing field and set the shipping_address association, which is the same Model_Address object. After that all the calculation will take the country of shiping_address instead of billing_address:

$purchase = Jam::find('purchase', 1);
$purchase->shipping_same_as_billing = FALSE;
$purchase->build('shipping_address', array(
'country' => Jam::find('country', 'United Kingdom'),
'line1' => 'Street 1',
// ...
));
## LicenseCopyright (c) 2012-2013, OpenBuildings Ltd. Developed by Ivan Kerin as part of [clippings.com](http://clippings.com)
Under BSD-3-Clause license, read LICENSE file.

About

Shipping for OpenBuildings/purchases

Resources

Contributing

Stars

0 stars

Watchers

10 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Purchases Shipping

Build StatusScrutinizer Quality ScoreCode CoverageLatest Stable Version

Usage

Purchase_items that you want to ship must implement Shippable, like this:

class Model_Product extends Jam_Model implements Sellable, Shippable {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
$meta
->associations(array(
'shipping' => Jam::association('belongsto', array('inverse_of' => 'products')),
))
->fields(array(
'id' => Jam::field('primary'),
'name' => Jam::field('string'),
'currency' => Jam::field('string'),
'price' => Jam::field('price'),
))
->validator('type', 'price', 'quantity', array(
'present' => TRUE
));
}
// Implement Sellablepublicfunctionprice(Model_Purchase_Item$item)
{
return$this->price;
}
// Implement Sellablepublicfunctioncurrency()
{
return$this->currency;
}
// Implement Shippable// Must return a ``Model_Shipping`` object holding all the data for the shippingpublicfunctionshipping()
{
return$this->shipping;
}
// Implement Shippable// Must return a boolean whether or not the product ships can to that locationpublicfunctionships_to(Model_Location$location)
{
return$this->shipping ? $this->shipping->ships_to($location) : FALSE;
}
}
class Model_Purchase_Item_Product extends Kohana_Model_Purchase_Item_Product {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_purchase_item' => Jam::behavior('shippable_purchase_item'),
));
}
}
class Model_Shipping extends Kohana_Model_Shipping {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->associations(array(
'products' => Jam::association('hasmany', [
'inverse_of' => 'shipping',
]),
));
}
}

Also you need to add the shippable purchase to your purchase and brand purchase:

class Model_Brand_Purchase extends Kohana_Model_Brand_Purchase {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_brand_purchase' => Jam::behavior('shippable_brand_purchase'),
));
}
}
class Model_Purchase extends Kohana_Model_Purchase {
publicstaticfunctioninitialize(Jam_Meta$meta)
{
parent::initialize($meta);
$meta
->behaviors(array(
'shippable_purchase' => Jam::behavior('shippable_purchase'),
));
}
}

This behaviors will add the 'shipping' association to the brand_pruchase, also listen to update_items event and add a shipping purchase_item, and listen to the filter_items event, adding some more flags to filter by.

Once you have added the shipping data to your products:

$post = Jam::find('shipping_method', 'Post');
$europe = Jam::find('location', 'Europe');
$france = Jam::find('location', 'France');
$product->shipping = Jam::create('shipping', array(
'currency' => 'GBP',
'ships_from' => $france,
'groups' => array(
// Ships to all of Europe for 20 GBParray('method' => $post, 'location' => $europe, 'price' => 20),
// Specifically for France - only 10 GBParray('method' => $post, 'location' => $france, 'price' => 10),
)
));

You can start to select which shipping applies to each purchase item.

$brand_purchase = Jam::find('brand_purchase', 1);
// If you want to set the informaction explicitly on which purchase_item what shipping_group to use$brand_purchase->build('shipping', array(
'items' => array(
array(
'purchase_item' => $brand_purchase->items[0],
'shipping_group' => $brand_purchase->items[0]->reference->shipping()->groups[0],
),
)
));
// Or if you want ones selected automatically, based on a preffered shipping method and purchaser location$post = Jam::find('shipping_method', 'Post');
$france = Jam::find('location', 'France');
$brand_purchase_shipping = $brand_purchase->build('shipping', array(
'location' => $france,
));
$brand_purchase_shipping->build_items_from($brand_purchase->items, $post);

Having configured that, you can now call update_items() method on the purchase / brand_purchase, adding to the purchase_items a shipping item.

$brand_purchase->update_items();
echo$brand_purchase->items_count('shipping'); // should return 1

Shipping Groups and Price Calculations

Each shipping group has several properties that affect how much muney the shipping of this item will cost:

  • price - this is the base price for shipping of 1 item.
  • additional_item_price - for more than one item, the second, third, etc items require this price, instead of the base one.
  • discount_threshold - whenever the brand_purchase is more than this amount - free shipping

Here are some examples:

If an item costs 10, with additional_item_price of 6, then you will pay 10+6+6 for 3 of the same item.

Also items are grouped per shipping method, per "ships_from" location so 3 different item shipped by post will be grouped. Only the most expensive base price will be used, all others will use additional_item_price. So:

Item 1: price 10, additional_item_price 6, quantity: 3
Item 2: price 12, additional_item_price 8, quantity: 2
Total Price will be (12 + 8) + 6 * 3

When searching for a country, the most specific one will be used for calculation, so if you are shipping for France, and you have a shipping_group for Europe, and one for France, the second one will be used.

Advanced Item Splitting

If you want to allow people to use different methods for different products, here is how you might accomplish this:

First of all - finding all purchase_items that can / cannot ship to your country

$available = $brand_purchase->items(array('can_ship' => TRUE));
$not_shippable = $brand_purchase->items(array('can_ship' => FALSE));

If you want to be more precise, you can get available items, but grouped by available shipping methods, so that if you have purchase_items that can ship with both post and courier and other that can ship only with post, they will be in different groups:

$group_shipping_methods = $brand_purchase->group_shipping_methods()
foreach ($group_shipping_methodsas$group)
{
foreach ($group->group_shipping_items() as$items)
{
// Get all the purchase items, shippable to this location by this method.$items->purchase_items;
// Calculate the price of these items, provide a total price to remove ones that are discounted based on it.$items->total_price();
// Delivery$items->total_delivery_time();
}
}

Delivery Times

This shipping module comes with extensive support for calculating delivery times.

Model_Shipping_Group has "delivery_time" - min - max workdays to deliver the item. Model_Shipping has process_time - min - max workdays to 'build' the item. Both of these are Jam_Ranges, and combined represent the total_delivery_time for a specific location.

Model_Shipping has this interface:

$france = Jam::find('locaiton', 'France');
$shipping = $product->shipping();
// To get a Jam_Range object only for the delivery to that location$shipping->delivery_time_for($france);
// To get a Jam_Range for delivery + processing for a specific country$shipping->total_delivery_time_for($france);

The shippable purchase behavior also adds some methods to the Model_Brand_Purchase for handling delivery time calculations:

// Get the Jam_Range object for the delivery time for the brand_purchase$brand_purchase->total_delivery_time();
// Get the Jam_Range object if the dates that the purchase will arraive// This is calculate based on the time the payment was made. If its not yet payed purchase, the current time is used.$brand_purchase->delivery_time_dates();

Shipping Address

By default as shipping address is used the billing address of the purchase. If you want to change that address, you'll have to change the shipping_same_as_billing field and set the shipping_address association, which is the same Model_Address object. After that all the calculation will take the country of shiping_address instead of billing_address:

$purchase = Jam::find('purchase', 1);
$purchase->shipping_same_as_billing = FALSE;
$purchase->build('shipping_address', array(
'country' => Jam::find('country', 'United Kingdom'),
'line1' => 'Street 1',
// ...
));
## LicenseCopyright (c) 2012-2013, OpenBuildings Ltd. Developed by Ivan Kerin as part of [clippings.com](http://clippings.com)
Under BSD-3-Clause license, read LICENSE file.

About

Shipping for OpenBuildings/purchases

Resources

Contributing

Stars

0 stars

Watchers

10 watching

Forks

Releases

Packages

Used by

Contributors

Languages