I am working on an Ubercart 2.0 project for a client. It is for a fabric store. They want the ability for customers to add fractional quantities (or decimal quantity) like 1.75 m. Does anyone have a comprehensive list of code changes that will allow for this functionality?
The current Uberart (v 2.0) does not allow decimals for their quantities.
If you seach the Ubercart forums for “quantity as decimal”, “fractions for quantity”, and “decimal quantities” you get some hits. This article is an effort to outline some changes that may be made to your installed Ubercart system to allow addition of "fractional quantities" to your cart.
Thank you to Lyle and his post reply that helped me get started on this article.
Add To Ubercart Core?
I hope that the Ubercart developers can find a way to implement the ability for “fractional quantities” to Ubercart Core. I hope that this document / article will help make that happen!
Database Changes
Changing Ubercart to accept fractional quantities means the datatype of some table columns must be changed from INTEGER to FLOAT(M,D). The FLOAT data type allows for the decimal to be stored. Here is a description from http://dev.mysql.com/doc/refman/5.0/en/numeric-types.html
Here, “(M,D)” means than values can be stored with up to M digits in total, of which D digits may be after the decimal point. For example, a column defined as FLOAT(7,4) will look like -999.9999 when displayed. MySQL performs rounding when storing values, so if you insert 999.00009 into a FLOAT(7,4) column, the approximate result is 999.0001.
Below are the changes to the tables to be made to allow 2 decimal places and 6 total digits. Applying the following database table changes should not affect existing data, unless you have quantities greater than 6 digits – in which case you could increase the M value.
// # UC_CART_PRODUCTS
ALTER TABLE `uc_cart_products` MODIFY COLUMN `qty` FLOAT(6,2) UNSIGNED NOT NULL DEFAULT 0;
UC_ORDERS
// # UC_ORDERS
ALTER TABLE `uc_orders` MODIFY COLUMN `product_count` FLOAT(6,2) UNSIGNED NOT NULL DEFAULT 0;
// # UC_PRODUCTS
ALTER TABLE `uc_products` MODIFY COLUMN `default_qty` FLOAT(6,2) UNSIGNED NOT NULL DEFAULT 1.00;
// # UC_ORDER_PRODUCTS
ALTER TABLE `uc_order_products` MODIFY COLUMN `qty` FLOAT(6,2) UNSIGNED NOT NULL DEFAULT 0;
Code Changes
// # uc_cart.module (line 1445)
db_query("UPDATE {uc_cart_products} SET qty = %d, changed = UNIX_TIMESTAMP(), data = '%s' WHERE cart_item_id = %d",
to...
db_query("UPDATE {uc_cart_products} SET qty = %f, changed = UNIX_TIMESTAMP(), data = '%s' WHERE cart_item_id = %d",
--
// # uc_cart.module (line 1509)
db_query("INSERT INTO {uc_cart_products} (cart_id, nid, qty, changed, data) VALUES ('%s', %d, %d, %d, '%s')", $cid, $node->nid, $qty, time(), serialize($data));
to...
db_query("INSERT INTO {uc_cart_products} (cart_id, nid, qty, changed, data) VALUES ('%s', %d, %f, %d, '%s')", $cid, $node->nid, $qty, time(), serialize($data));
--
// # uc_order.module (line 1043)
db_query("UPDATE {uc_orders} SET uid = %d, order_status = '%s', order_total = %f, product_count = %d, primary_email = '%s', "
to...
db_query("UPDATE {uc_orders} SET uid = %d, order_status = '%s', order_total = %f, product_count = %f, primary_email = '%s', "
--
// # uc_order.module (line 1143)
db_query("UPDATE {uc_orders} SET product_count = %d WHERE order_id = %d", $count, $order->order_id);
to...
db_query("UPDATE {uc_orders} SET product_count = %f WHERE order_id = %d", $count, $order->order_id);
--
// # uc_order.install (replace lines 48 to 51)
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
with...
'type' => 'float',
'precision' => '6',
'scale' => '2',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 1.00,
--
// # uc_product.module (line 1207)
db_query("UPDATE {uc_cart_products} SET qty = %d, changed = %d WHERE nid = %d AND cart_id = '%s' AND data = '%s'", $qty, time(), $nid, $cid, serialize($data));
to...
db_query("UPDATE {uc_cart_products} SET qty = %f, changed = %d WHERE nid = %d AND cart_id = '%s' AND data = '%s'", $qty, time(), $nid, $cid, serialize($data));
--
Thoughts - Additional Changes
It would probably be a good idea to add some functionality to allow a choice as to whether or not a certain product type / class is allowed to accept “fractional quantities”. Maybe the addition of a boolean column (like “allow_frac_qty”) in the uc_product_classes table or the uc_products table. Then of course, there would be more code additions / changes to allow for this. Also, the “pkg_qty” column in the uc_products table may also need to be changed
Other Ubercart Forum Posts
http://www.ubercart.org/forum/support/4651/use%5Ffractions%5Fquantity%5F15%5Fyards
http://www.ubercart.org/forum/support/6074/decimal%5Fquantities%5Fitems
http://www.ubercart.org/issue/6044/abiility%5Fhave%5Fdecimal%5Fquantities
http://www.ubercart.org/forum/ideas%5Fand%5Fsuggestions/3283/comma%5Fvalues%5Fquantity%5Ffield
I think changing ubercart core to achieve what you mean is a bad idea. You are basically dooming yourself not to have the ability to update/upgrade when there are security fixes and probably some other module would assume you are using integer, giving way to difficult-to-track bugs and php exceptions.
I did not make an extensive search as the previous poster, but if I had to implement your need myself, off the top of my head I would:
- Use centimeters (integer) as logical measurement unit in the back-end.
- "Mask" the decimal functionality by altering the add_to_cart forms at validation/submit time, for the user input, so that on submit 1,75 m would get converted in 175 cm.
- Alter the product, catalog and order page templates in order for them to display price information in metres, so that the value 0.05 €/cm (stored in the DB) would be displayed as 5 €/m.
Just my two cents, but consider that ubercart is in active development and - despite the recent exit from release candidate state - it still has plenty of bugs: you really want to be able to update your codebase when fixes come out.
EDIT: just to stress what above: since I wrote this answer less than a week ago, two UC updates have come out, of which one fixing a critical security issue...
Hope this helps!
mac's got it right. That approach is much simpler and less prone to maintenance problems.
It would also make it trivial to support any type of measurement using JavaScript to generate a drop down of measurement system and doing a conversion on submit.
I have posted a module I am working on at http://www.ubercart.org/issue/6044/abiility_have_decimal_quantities ... Please leave your feedback.