silvershop / silvershop-core Goto Github PK
View Code? Open in Web Editor NEWSilverShop is an e-commerce shopping cart module for the SilverStripe CMS
Home Page: http://silvershop.github.io
License: BSD 2-Clause "Simplified" License
SilverShop is an e-commerce shopping cart module for the SilverStripe CMS
Home Page: http://silvershop.github.io
License: BSD 2-Clause "Simplified" License
This behavior could be an optional configuration.
Tax should update automatically, according to country, and what items. Some countries calculations are more complex than others.
Store all tax rates in an array / file, allowing for updates to be made every new version of shop, or for developers to make updates.
http://en.wikipedia.org/wiki/Tax_rates_around_the_world
Defining tax classes will allow specific products to be added to those classes, as some countries charge different tax rates for different types of products.
The region restriction system (#94) will help to define tax rates per region.
TaxClass
TaxRate extends RegionRate
TaxClass has many TaxRates.
OrderItem seems to some be acting as a go-between class between [Buyable]_OrderItems.
Just needs some more thought, a bit messy at the moment.
The modifiers system should be extended to allow choosing a shipping type, which will then be added to the order.
Need to enforce that at least one shipping type be added before order is placed.
Eventually not all orders will be processed through the Checkout, one current example is programatically placing an order using a unit test. Currently you need to post the OrderForm request to make it work....it should instead be possible via some class calls, eg:
$orderprocessor->place($order);
Once an order is placed, it should be completely immutable, i.e. not able to change. (Apart from fulfilment related things)
Such objects:
A basic implementation could start by updating the canEdit function to check the current order status is 'Cart', or the member is Admin.
Another aspect to take into account is how the database is affected by removing DataModels, such as Modifiers, Payment types, OrderItem types, etc. Also, you should be able to import data from another ecommerce system and have order totals, and line totals remain unaffected.
The bug exists in OrderItem, where UnitPrice relies heavily on the Buyable (Product) to get it's value.
Also this commit 72c65ef introduces a problem where CalculatedTotal is checked in both UnitPrice and Total.
The product images in email don't show up.
Ability to compare products is useful, particular for gadgets and other hardware.
Comparison values could potentially come from different sources:
One off feature values only apply when a ProductAttributeType
has no values.
Features could be grouped.
Prestashop data diagram may be of use: http://www.daveegerton.com/assets/images/database-schema-prestashop.png
shop diagram: https://docs.google.com/a/burnbright.net/drawings/d/1V3W0CTe-RXrryr4zs_rZFwACx0_K7esGrfmdSz2Sckw/edit
Provide instructions on how to recommend other related products for each product page
A new order is created on every request that gets the cart. Checkout, or any page showing an order summary, that calls or checks $Cart.
This does not allow sites to scale, as there are likely to be many visitors who never add products to their cart. That would result in many empty orders being added to the database.
Allow new customers to create an account after they have placed an order, allowing them to log in later, if so desired.
Display a 'create account link' on checkout finish page, if not logged in.
Also introduce logic when new user logs in to link unlinked orders to new account, or at least ask to.
This could be part of the OrderManipulation class.
There is a silverstripe-mobile module which the shop module can be tested with, to ensure that it is compatible. Mobile is a growing part of web usage, so likewise with ecommerce sales.
The cart contents should not show on the checkout/finish page.
Tried out the new shop and decided that you need to add this to L200 of CheckoutPage.php to make it more compatible with current themes.
Requirements::themedCSS('AccountPage');
Travis (http://travis-ci.org/) looks like a very useful tool for running continuous integration. Probably best to try setting up with silverstripe before attempting to add the shop module.
Start here:
http://about.travis-ci.org/docs/user/getting-started/
Addresses should be stored separate from the order dataobject. Doing so will provide better encapsulation of addresses.
If it is required that addresses be immutable (non-editable), then we can ensure that historical records don't change. A change in address will just produce a new record.
If the user is a logged-in member, they should be able to choose from a list of existing addresses (address book).
To maintain backwards compatibility, the checkout order form could be populated with the last used, or default selected address. Any changes to these fields will result in a new address object being created.
This issue relates to #79. I'm working on both at the same time.
Display these on cart page, regardless of whether there is anything in the cart.
The twitter bootstrap code will be great to use as a basic theme for the Shop module.
Build some tools to automatically generate a large number of database records. This will help with understanding heavily populated and used sites.
Optionally enable randomness:
Sometimes the wrong weight can be entered, resulting in bad shipping cost calculation.
A report showing weights that are strange eg 500kg for a $25 product would be useful.
Also providing an input field that allows choosing the units (eg grams, kg etc) could help. https://gist.github.com/2503707
Convert base unit to grams, rather than kilograms.
Allowing for ounces might help also.
Filters system allows creating custom order items: eg 3ft of cable, or 2m x 6m of carpet. This has not yet been introduced with the new ShoppingCart upgrades.
This subclass of image exists only so that the following resize functions are available:
These functions should be instead somehow be available on every Image.
Having a Product_Image class causes problems when you want to use an Image that has been uploaded by some other means.
In my work with this new shop I discovered that there are one or two template variable that are different - no big deal. But the key tests for the add item / alter item link on a Product page were broken
I traced this to ShoppingCart.php where you had deprecated get_item_by_id() . I had to reinstate that function
at 249:
/**
* @deprecated
*/
//static function get_item_by_id(){}
static function get_item_by_id($id, $variationid = null,$filter = null) {
if(!$id) return null;
$filter = "";//self::get_param_filter($filter);
if(is_numeric($variationid)){
$filter .= ($filter && $filter != "") ? " AND " : "";
$filter .= "\"ProductVariationID\" = $variationid";
}
$order = self::current_order();
$fil = ($filter && $filter != "") ? " AND $filter" : "";
$item = DataObject::get_one('OrderItem', "\"OrderID\" = $order->ID AND \"ProductID\" = $id". $fil);
return $item;
}
Alternatively one can alter the function Item() on Product.php
at 213
function Item() {
$filter = null;
$this->extend('updateItemFilter',$filter);
if (ShoppingCart::get_items("ProductID = '$this->ID'")){
$item = ShoppingCart::get_items("ProductID = '$this->ID'")->First(); // print_r($item);print_r($item->First());
}
else $item = $this->createItem(0,false); //return dummy item so that we can still make use of Item
$this->extend('updateDummyItem',$item);
return $item;
}
Turning the module into a webservice could help make it more modular and customisable. It should help to abstract away the interface from the underlying system logic.
Taking this approach could also allow:
Creating a web service API will not only open stores to be manipulated in a variety of ways, but also will help drive the project towards a solution that is scalable, and well modularised.
This is the proposal for version 1 of the API. Related: issue #33
Sapphire provides a RestfulServer class that might help with getting set up.
Responses will be provided in json or XML format.
Structure: GET baseurl/api/v1/products.format
Example: GET http://www.mysite.com/api/v1/products.json
Produces:
[{title:"Beach Ball",price:5.00},
{title:"Fishing Rod",price:14.00}]
Example:
GET <baseurl>/api/v1/products
...
...
...
...
The shop module is reaching a point where a single price is not enough. Pricing is such a core aspect of eCommerce systems. To get this done right will greatly merit the shop module.
Ideally the pricing system for shop should:
Here's a range of the kinds of price calculations and contributing values:
original google doc illustration
Other related things to display to the user:
Out of this pricing, the user sees some final price, and they click 'add to cart'. This could be called the "Selling Price".
Templates will need to be updated, or provided in documentation on how to display price aspects.
Custom calculations could be performed for items, or per line changes might be applicable.
If the product catalog is updated, then order items also need to be updated.
Some could be totals of item values, or unique values of their own.
Historical product information should always be available via the SilverStripe Versioned system. This means product prices, titles etc will all be available...and can even be accessed from deleted products.
The system has been failing however, as Versioned.php has a bug, where if a version is not available, it outputs a debug message, breaking sites sometimes completely.
The error most people will receive is, for example:
[User Error] Versioned::get_version: Couldn't get Product.389, version 2
This is merely produced by a debug statement / error that the sapphire core. Versioned.php line 920, 980, and 998
If a product is no longer purchasable, existing shopping carts should be updated, and customers notified that the product is no longer available.
This is particularly important to sort out if a store is to have long-lasting carts - eg: months, or infinite...a good idea to encourage sales over time.
Relates to issue #8 - creating a site-wide notification system.
I found that when I modifed the add() function to take a quantity url argument, that when I used that argument to add enough product to get an immediate quanitity discount (using my SimpleDiscount modfier) that the discount didnt show.
Solution. Add calculate() to function GrandTotal in product.php
function GrandTotal(){
$this->calculate();
if($this->Total){
print_r($this->Total."|");
return $this->Total;
}
return $this->getField('Total');
}
Interestinggly when I added it to Modifiers() the system hung on return from payment and the orders drilldown in the cms refused to load (both timeouts) so I must have build a loop.
This might involve modifying the order template, and possibly removing the casting of TableValue in OrderModifier class.
This could open up a few possibilities:
To know the problem more I've added a product in English and I've added the same product in French, so on English front-end when I added the product to the cart and switch back to French and I get the following problem:
Debug (Versioned::get_version() in line 978 of Versioned.php)
SELECT "SiteTree_versions"."ClassName", ....
Debug (Versioned::get_version() in line 979 of Versioned.php)
(bool) false
[User Error] Versioned::get_version: Couldn't get Product.389, version 2
GET /SilverStripe-v2.4.7/products/filter/
Line 980 in D:\server\www\SilverStripe-v2.4.7\sapphire\core\model\Versioned.php
Source
971 Versioned::set_reading_mode('');
972
973 $baseTable = ClassInfo::baseDataClass($class);
974 $query = singleton($class)->buildVersionSQL(""{$baseTable}"."RecordID" = $id AND "{$baseTable}"."Version" = $version");
975 $record = $query->execute()->record();
976 $className = $record['ClassName'];
977 if(!$className) {
978 Debug::show($query->sql());
979 Debug::show($record);
980 user_error("Versioned::get_version: Couldn't get $class.$id, version $version", E_USER_ERROR);
981 }
982
983 Versioned::set_reading_mode($oldMode);
984 return new $className($record);
985 }
986
The directory name is hardcoded and thus must be "shop" and not, say "module-shop"
Feedback from a user:
I found that the installation documentation was missing specifics in terms of what I needed to have (at a minimum) in the mysite/_config.php file to have the module function. After scouring the forum for hours and trying various things I was able to figure it out but felt that if this was included more clearly in the installation documentation I would have saved a ton of time and been more satisfied with the Paypal Payment extension as well as the ease to add extensions to the ecommerce module itself.
Allow adding at least one image per variation.
Allow to dev/shop/config to list the current configuration settings.
The current browsing and searching features are fairly basic. There is plenty of room to improve.
See:
http://www.webcredible.co.uk/user-friendly-resources/web-usability/ecommerce-findability.shtml
Allow updating the cart via AJAX, this includes the SideCart, and cart/checkout pages that display a larger version of the cart.
This somewhat relates to introducing an API.
This went missing/ignored some time ago, but it still should be useful.
Users should be notified about things important to them, eg:
These messages should show to the user on the next request made, and therefore the message will need to be available from the site template. Messages should not clear until they have been rendered (read), or dismissed (press X, or "dismiss").
Rather than the system checking various conditions every request, it would be good for the system to push new notifications to customers.
I need to modify the remove links to either include parameters, or simply make use of the order item id.
Shipping is a complex part of an online shopping system. The shop module uses modifiers, with specific calculators that only really do a good job for basic 1-tier delivery rates. An effort is needed to provide regionalised/zoned shipping options.
This will help people find what they want, and it will also reveal what people are searching for.
I've two language website English and French... I'm using silverstripe-shop module with SilverStripe v2.4.7
Product Group translation is working properly but when I translate a product item I get the following error:
RROR [User Error]: Uncaught Exception: Object->__call(): the method 'productgroups_original' does not exist on 'Product'
IN POST /SilverStripe-v2.4.7/admin/getitem?ID=23&locale=fr_FR&ajax=1
Line 724 in D:\server\www\SilverStripe-v2.4.7\sapphire\core\Object.php
715:
716: default :
717: throw new Exception (
718: "Object->__call(): extra method $method is invalid on $this->class:" . var_export($config,
true)
719: );
720: }
721: } else {
722: // Please do not change the exception code number below.
723:
Product->ProductGroups_original()
line 117 of HasManyComplexTableField.php
HasManyComplexTableField->selectedItemIDs()
line 126 of HasManyComplexTableField.php
HasManyComplexTableField->ExtraData()
line 369 of ViewableData.php
ViewableData->obj(ExtraData,,,1)
line 446 of ViewableData.php
ViewableData->XML_val(ExtraData,,1)
line 763 of .cache.sapphire.templates.RelationComplexTableField.ss
include(C:\Windows\Temp\silverstripe-cacheD--server-www-SilverStripe-v2.4.7.cache.sapphire.templates.RelationComplexTableField.ss)
line 429 of SSViewer.php
SSViewer->process(ManyManyComplexTableField)
line 342 of ViewableData.php
ViewableData->renderWith(RelationComplexTableField)
line 275 of ComplexTableField.php
ComplexTableField->FieldHolder()
line 64 of HasManyComplexTableField.php
HasManyComplexTableField->FieldHolder()
line 93 of CompositeField.php
CompositeField->FieldHolder()
line 369 of ViewableData.php
ViewableData->obj(FieldHolder,,,1)
line 446 of ViewableData.php
ViewableData->XML_val(FieldHolder,,1)
line 73 of .cache.sapphire.templates.TabSetFieldHolder.ss
include(C:\Windows\Temp\silverstripe-cacheD--server-www-SilverStripe-v2.4.7.cache.sapphire.templates.TabSetFieldHolder.ss)
line 429 of SSViewer.php
SSViewer->process(TabSet)
line 342 of ViewableData.php
ViewableData->renderWith(TabSetFieldHolder)
line 80 of TabSet.php
TabSet->FieldHolder()
line 369 of ViewableData.php
ViewableData->obj(FieldHolder,,,1)
line 446 of ViewableData.php
ViewableData->XML_val(FieldHolder,,1)
line 58 of .cache.sapphire.templates.TabSetFieldHolder.ss
include(C:\Windows\Temp\silverstripe-cacheD--server-www-SilverStripe-v2.4.7.cache.sapphire.templates.TabSetFieldHolder.ss)
line 429 of SSViewer.php
SSViewer->process(TabSet)
line 342 of ViewableData.php
ViewableData->renderWith(TabSetFieldHolder)
line 80 of TabSet.php
TabSet->FieldHolder()
line 369 of ViewableData.php
ViewableData->obj(FieldHolder,,,1)
line 446 of ViewableData.php
ViewableData->XML_val(FieldHolder,,1)
line 77 of .cache.sapphire.templates.Includes.Form.ss
include(C:\Windows\Temp\silverstripe-cacheD--server-www-SilverStripe-v2.4.7.cache.sapphire.templates.Includes.Form.ss)
line 429 of SSViewer.php
SSViewer->process(Form)
line 342 of ViewableData.php
ViewableData->renderWith(Array)
line 1108 of Form.php
Form->forTemplate()
line 1135 of Form.php
Form->formHtmlContent()
line 391 of LeftAndMain.php
LeftAndMain->getitem(SS_HTTPRequest)
line 193 of Controller.php
Controller->handleAction(SS_HTTPRequest)
line 143 of RequestHandler.php
RequestHandler->handleRequest(SS_HTTPRequest)
line 147 of Controller.php
Controller->handleRequest(SS_HTTPRequest)
line 282 of Director.php
Director::handleRequest(SS_HTTPRequest,Session)
line 125 of Director.php
Director::direct(/admin/getitem)
line 127 of main.php
Hope there is a solution for this problem
Thank you
Important for money-based systems is keeping a record of everything that happens and changes. This means creating some kind of audit trail, known in the accounting world as a posting table. Every time a product or order is updated, a record is made of this change. This data isn't used often, but will be very useful if ever needed, as it provides accountability.
There are some OrderStatusLog classes and functions which are not actually used currently.
To reduce some of the Order class bloat, try removing all the email related stuff. This can be separate.
Currently there are many past orders sitting with SessionID's, which is not needed, these should be cleaned up.
The SessionID is stored so that guest users can see their order after placing it.
It might even be worth changing SessionID to a cookie value or perhaps just storing 'past orders' in a session variable.
Either through the back or front end, with special privileges / provision. Do not save customer details over admin details.
In the interest of making the shop module more global, it should allow users to view prices in their local currency.
Here is an implementation proposal:
https://groups.google.com/d/topic/silverstripe-ecommerce/vnFVYy54HwU/discussion
Use cases:
Provide an interface for manual entry and adjustments.
Provide ways to get rates from various sources. Perhaps just abstract CurrencyAgregator class.
Storing an order's status in a single Enum db field, as has historically been the case, is to restrictive and simple for accurately storing order statuses. The idea of order 'status' should be shifted to 'state'. A state machine will help keep orders in valid states, and also help us to build systems that properly transition an order's state. State changes can be recorded in a log.
Customers, shop admins, and automatic processes can be allowed to, or prevented from doing certain things, based on the current state.
Eg: tracking API can update received status automatically, but only if the order is in a 'dispatched' state.
Some states and events wont matter to store owners, therefore the system needs to be flexible.
Devs should be able to incorporate their own steps (states), and transitions in the ordering fulfilment pipeline.
About state machines:
Here's a guess at some states that an order might be in:
Of course there could be a number of possible shop configurations, that is different types of order fulfilment: http://en.wikipedia.org/wiki/Order_fulfillment
Here is a guess at the requirements needed for the shop module:
Because not every shop workflow is the same, there should be some leeway for adding and removing some states entirely. For example, a shop with only digital products won't have a 'processing' state.
This may be more difficult than it sounds, as I imagine things could get unstable if certain states/transitions don't exist. This could be treated as a nice-to-have for now.
Ability to assign custom logic to transition events. For example,
In conjunction with making notes on an order, updates (state transitions) should also be recorded.
There are various state machine implementations around that could be used. Another possible option could be to create a silverstripe module that allows turning any data object into a state machine, allowing for greater reuse.
Events that site admins will probably want to record, likely as dates rather than boolean:
All this information and events can show up in the CMS to give a clear picture where things are at. Perhaps the events are visualised along a timeline.
Related: #4
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.