The current shipping api applies a single method to all products on a site, e.g., $2 per item, unless a fairly undeveloped 'per product' option is chosen. This approach might conceivable be useful on a very few small sites, where only one or two products are sold, but is entirely inapplicable to most use cases, where a variety of shipping options is needed to handle getting different products to different customers.

After discussions with various ecommerce developers and a while looking over the code, I'm thinking we need to refactor the shipping module something like this:

* all shippingapi modules are 'per product'
* shippingapi modules export a set of 'methods', e.g., 'same day shipping'. Each method has a set of product properties associated with it ('weight', etc.).
* site admins can configure a particular product type to accept one or more methods
* on product edit pages, site admins designate which methods to apply for the product, and set applicable settings (e.g., weight of item).
* in the checkout process, a form is presented to purchasers to select from available shipping methods for the particular product.

Comments, please! I'm going to dig into coding this week.

Comments

sime’s picture

Looks very good, nedjo.

Amazon’s picture

Here's some other use cases to consider:

Each type of product has differing shipping costs for different quantities and shipping priorities (also, to complicate matters, when calculating shipping costs we need to maintain multiple quantity counts because some product types are shipped together and some shipped separately).

nedjo’s picture

Here's some other use cases to consider

Yes. I'm thinking (or maybe hoping ;) ) that we can leave most of these complexities to shippingapi modules. Shipping.module provides the openings, and shippingapi modules can do what they want. E.g., we pass a transaction in checkout to relevant shippingapi modules and they decide what options to present to the user, based on whatever criteria they choose (country of residence, etc.).

nedjo’s picture

More details on the approach I'm drafting.

Shipping modules (e.g., shipcalc) will return an array of methods.

Instead of the current:
-------------------
case 'method select':
return array('shipcalc'=>t('Shipping costs are recieved directly from carrier (UPS) during checkout.'));
-------------------

we would have something vaguely like:

-------------------
case 'methods':
return array('nextday' => t('Overnight courier'), 'ground' => t('Ground shipping'));
-------------------

Site admins designate settings for each product type, selecting which methods are available. Then, on the node/add/product or node/999/edit pages users are presented with a list of options to enable for the product and attributes for each. Finally, on checkout, clients are presented with a list of shipping options (methods) to choose from, if multiple are offered for the product.

To implement this I'd prefer to rely primarily on _nodeapi and _form_alter, rather than the current large number of shippingapi $op arguments, which seem to me to be mostly clutter. This approach would take a lot of logic out of shipping.module and into the shippingapi modules--of which shipcalc is really the only one. The checkout work would be left to the checkoutapi as it currently is in shipcalc.

nedjo’s picture

StatusFileSize
new26.57 KB

Here's a first rough patch.

We remove the shippingapi. Instead, each shipping module returns an array of method through a hook_shipping_methods(). This array is structured like a $form array, so that we can manipulate it with the Forms API methods (e.g., element_children()).

We add a new set of configuration options per product type at

admin/settings/content-types/product

This allows us to attach shipping methods to particular product types.

Most of the rest of the logic is handled directly by shipping modules, rather than through shipping.module. The key advantage is flexibility--rather than having to fit into the preassumptions of the API, shipping modules can directly implement their handling.

I'm working on details of how we add shipping option fields to node/add/product and to checkout.

I'm going to post separately zipped versions of the altered modules and a sample shipping module with a shipping_options hook implementation.

nedjo’s picture

StatusFileSize
new13.66 KB

The changed modules, along with a sample shipping type module.

nedjo’s picture

StatusFileSize
new9.29 KB

And a screenshot of the shipping configuration at admin/settings/content-types/product/tangible.

nedjo’s picture

StatusFileSize
new26.59 KB

Minor fix to previous patch. Needed to test for existance of array key, errors were raised on admin/settings/content-types/product/[ptype] if no previously submitted data.

nedjo’s picture

StatusFileSize
new36.47 KB

Here is a patch closer to completion and ready for testing.

Beyond what was in the previous patch, we add settings to product create/add pages as appropriate to designate which shipping methods should be available for that product. Then individual shipping modules can add to the form as necessary. For example, if shipcalc needs a 'product_weight', it is added here.

Jeremy's work on upgrading shipcalc will provide an example implementation. We're working together to ensure that the changes here are harmonized with shipcalc.

Still to come:

1. upgrade path.
2. refining.

nedjo’s picture

StatusFileSize
new931 bytes

Sample module for testing purposes attached. To test:

* apply patch
* enable tangible.module, shipping.module, shippingtest.module
* go to admin/settings/content-types/product,, and click on the link for configuring tangible
* select one or two of the available shipping options and submit
* create a new tangible product and look on the form for a fieldset for selecting methods. You should see only the ones you designated for the product type.

When we have shipcalc module ready, you'll also see here any product attributes that need to be set, e.g., weight.

Keep in mind that there is no checkout work done here. That will be done by individual shipping modules using the checkoutapi.

nedjo’s picture

Status: Active » Needs review
StatusFileSize
new37.42 KB

Last patch was malformed, here's one that should work.

mfb’s picture

For some reason, I could not get this patch to apply.

jeremy’s picture

The ec_shipping_product table has four fields: (vid, nid, type, method). The 'vid' field is defined as the primary key, and thus must be unique. However, if you select more than one shipping method, the same vid gets used each time resulting in a database error. I think vid should just be indexed, not a primary (unique) key.

neclimdul’s picture

I'm not sure I'm completely understanding why each module has to implement its own checkoutapi hook. It seems that this should be handled by the shipping module for several reasons. Multiple modules can be running at the same time and attached to a product so let me propose a use case.

Every shipping method in the world wont be in shipcalc so a user wants to use the shipping method "Pony Express" and UPS. They make a shipping module that provides "Pony Express" shipping prices and attaches it to a product along with UPS. Now enter user trying to purchase product. During the checkout the user gets to the shipcalc checkout screen and selects overnight, now the user gets to the "pony express" screen and is prompted by a new set of options?

It seems that shipping.module should provide a checkout api screen that groups the choices. Shipping modules can also have a second checkout screen that optionally prompts for extra information if needed.
Maybe I'm missing something since I can't get the shipcalc patch to apply but that's the shortcoming as I see it.

sime’s picture

Same or different SQL?

nedjo’s picture

neclimdul, I think you're right, we need to have a shipping.module checkoutapi function that pulls together the options offered by various shipping-method modules.

Jeremy has now posted a new version of his shipcalc module upgrade. He's included checkoutapi code there, but noted that the checkout calls should probably be moved to shipping.module so we can pull together all options there.

So I'll work on doing that and then we can modify his shipcalc patch to work accordingly.

And I'll fix up the primary key issue Jeremy noted at the same time.

cobrasound’s picture

I couldn't get patch2 to patch correctly either...

Jeff

nedjo’s picture

I need to do some more work before this and the shipcalc patch are really ready for testing. I'm working on moving some of the logic from Jeremy's shipcalc patch into shipping.module. Aiming for a fresh patch tomorrow (Friday). If not, early next wk.

bs’s picture

Hi all!
I got into a situation where my project needs 3 shipping options before customer proceed to payment screen. I thought it is appropriate for the current topic
Project requirement:
Before the payment page they will have 2 options for receiving their items:

1) Self collect from shop
2) By normal/registered mail

If they select self collect link them to payment page without shipping charges.
If they select normal/ registered mail (registered mail will be extra $2 than normal mail), link them to a page with corresponding shipping fees added to the order.

Any suggestions on how-to proceed with Drupal-4.7 e-commerce module?
Thank you,
Balasatya.

neclimdul’s picture

@balasatya I think this is something that should work easily with the changes nedjo is adding. You can help by reviewing the patch when he posts it though :) This is one of the few large changes left on the roadmap to the 4.7 release and your input would be helpful to get it ready faster.

jeremy’s picture

StatusFileSize
new57.83 KB

Here's the latest version of the shippingapi patch. It modifies three files: shipping.module, shipping.install, and product.module. To test out this new functionality, you should also apply the latest shipcalc patch.

Some functionality has been moved from the new shipcalc module to the core shipping module so that all shippingapi modules can benefit. For example, the shipping module now provides support for fulfillment centers (ie, where shippable products will be shipped from), and stores product attributes defined by shippingapi modules (ie, weight).

gordon’s picture

I have looked at it, and it looks good. However there are a couple of things that stopped me from committing this right now.

1. The shipping form in the checkout always comes up, even if you have no shippable products.
2. If there is only 1 method of shipping applicable, don't show the form.
3. I can't get the ship types to come up on the product.
4. This system is designed for big E-Commerce sites. It doen't support being able to a small company that just drops the 1 or 2 products into the post box.

I want to apply this to cvs in the next 24-48 hours so people are forced to test this.

Great work so far.

jeremy’s picture

Issues #1 and #2 are simple bugs, easy enough to fix. However, I'm unclear what you're reporting in #3? Can you explain what you expect to see that you're not seeing?

Perhaps some configuration instructions would help:

  1. go to administer >> settings >> content types, and configure product types at the top of the screen there. (ie, click "shippable product", if enabled) On the configuration screen, enable all shipping methods that are allowed for that product type.
  2. now edit each shippable product, and enable all shipping methods that are allowed for that specific product. (perhaps they should all be enabled by default, rather than disabled by default? could be helpful, as this is an easy-to-miss configuration step, and it is probable that most sites will only need to tune shipping on a per-product-type basis, not on a pre-product basis...)
  3. now go ahead and purchase a product that has shipping configured -- the selected options will be available to you during checkout.

Regarding issue #4, this needs to be solved through another shippingapi module. Something much simpler than shipcalc, to support the simple flat-rate type of shipping that you describe.

gordon’s picture

issue 3 is step 2 of the proceedure. When I go to edit the product, I do not get fields on the product page.

jeremy’s picture

StatusFileSize
new58.33 KB

This patch replaces the old and addresses two issues:

  1. Don't show shipping form if there are no shippable products
  2. Don't show shipping form if there is only one shipping method (auto-select it)

I am unable to duplicate issue #3. Issue #4 requires the creation of another shippingapi module, unfortunately I don't have time to do this this morning, as I'm heading out the door shortly for a week long trip.

gordon’s picture

Status: Needs review » Fixed

thanks, I have applied this to CVS, so that it will force people to test it.

I did find a small bug in that the setting in the content types always edit "product" content type.

Don't worry about the small freight module, for people who just want to add a handling charge. What I would prefer is to add all this to the documentation for developers to develop there own frieght modules.

Anonymous’s picture

Status: Fixed » Closed (fixed)