Coder Social home page Coder Social logo

silvershop / silvershop-core Goto Github PK

View Code? Open in Web Editor NEW
113.0 25.0 119.0 6.07 MB

SilverShop is an e-commerce shopping cart module for the SilverStripe CMS

Home Page: http://silvershop.github.io

License: BSD 2-Clause "Simplified" License

PHP 90.04% Scheme 9.96%
silverstripe cart ecommerce php omnipay hacktoberfest

silvershop-core's Introduction

SilverShop Module

The SilverShop module aims to provide developers with a framework for building, and customising ecommerce-based projects. It includes facilities for customers to browse products and place orders, and for administrators to manage products and orders. We've put a strong focus on testing. You can see the build status of this project, running on MySQL, SQLite, Postgres, as well as a few different versions of PHP.

Latest Stable Version Latest Unstable Version CI Code Coverage Scrutinizer Quality Score Total Downloads

Your contributions, and feedback are welcomed and appreciated. There are many ways you can contribute to this project. A tremendous thanks to everyone that has already contributed.

Requirements

See composer.json for exact set of dependencies.

For a SilverStripe 3.x compatible version, please use a 2.x release.

Stay up to date / get in touch

Documentation

Installation Instructions

To install SilverShop using composer, run the following command:

composer require silvershop/core

Build Tasks

There are a few useful tasks that can be run via a url to help you test:

  • {yoursite.com}/dev/tasks/PopulateShopTask - will create cart, checkout, account, category and product pages
  • {yoursite.com}/dev/tasks/PopulateCartTask - will add products to the cart, and navitate you to the checkout

Configuration

You can view various configuration options in the 'example_config.yml' file.

Core Features

  • Product Catalog - Products extend Page, and can be browsed within Product Category pages.
  • Cart Page - For viewing and updating your cart.
  • Checkout - Gather delivery/billing details and anything specific to the order. Can be single-page or multi-step.
  • Online Payments - Via the omnipay module.
  • Administration - Manage the catalog and orders in the CMS.

Futher functionality is provided by add-on submodules.

Add-on Sub Modules

Don't reinvent the wheel! Get additional pre-built functionality with sub modules. All additional functional will be tagged on packgist as #silvershop

silvershop-core's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

silvershop-core's Issues

Rebuild shipping framework

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.

  • Provide different priced / spec'd options for delivery, but possibly require that one be chosen before order is placed. eg: economy 3-4 days vs premium overnight
  • Restrict to only specific countries, which may reside in particular zones.
  • Free shipping calculation
  • Pick up from store option
  • Connect to carrier APIs

Related: #11 #39

Refactor or clarify OrderItem

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.

Fix product version system

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

Create Audit Log / Posting Tables

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.

Clear SessionId from past orders

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.

Order Fulfillment State Machine

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:

order status-state flow scenarios

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

Requirements

Here is a guess at the requirements needed for the shop module:

Add and remove states

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.

Add transition event callbacks

Ability to assign custom logic to transition events. For example,

Logging all transitions

In conjunction with making notes on an order, updates (state transitions) should also be recorded.

FSM Implementations

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 & Logs

Events that site admins will probably want to record, likely as dates rather than boolean:

  • Order (cart) started (currently Created)
  • Order placed
  • Fully paid
  • Receipt emailed
  • Items packaged
  • Package sent
  • Package delivered
  • Any other events along the way, e.g.:
    • partial payments
    • notes
    • or non-standard changes to an order - this is where an order status log should come in

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

Issues with non existent version / language change

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

Can't create translations of Product pages

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

Source

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:

  • 724: throw new Exception("Object->__call(): the method '$method' does not exist on '$this->class'",
    2175);
    725: }
    726: }
    727:
    728: //
    -----------------------------------------------------------------------------------------------------------------
    729:
    730: /**

Trace

    Object->__call(ProductGroups_original,Array) line 117 of HasManyComplexTableField.php

    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

Enforce immutability of orders

Once an order is placed, it should be completely immutable, i.e. not able to change. (Apart from fulfilment related things)

Such objects:

  • Order - incl totals, included items, associated member details
  • Shipping and Billing Addresses
  • Order Items
    • Unit Price
    • Quantity
    • Discounts / other modifications to item total
    • Total

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.

Multi-currency support

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:

  • single currency site
  • a few currencies / countries
  • many/every currency and country

Provide an interface for manual entry and adjustments.

Sources

Provide ways to get rates from various sources. Perhaps just abstract CurrencyAgregator class.

Post-Checkout Account Creation

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.

shop directory name

The directory name is hardcoded and thus must be "shop" and not, say "module-shop"

Modifier totals too late for template

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.

Prevent new orders being created on every request

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.

Remove Product_Image

This subclass of image exists only so that the following resize functions are available:

  • Thumbnail
  • ContentImage
  • LargeImage

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.

Web Service API

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:

  • Full javascript front-ends using frameworks such as backbone
  • Mobile / tablet apps

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.

Customer Interactions

Get all products

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}]

Get single product

Example:
GET <baseurl>/api/v1/products

Add product to cart

...

Get cart contents & subtotals

...

Get shipping estimates

...

Place an order

...

Admin Interactions

Prevent incorrect shipping weights

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.

Site-wide notification messages

Users should be notified about things important to them, eg:

  • Price changes
  • Product(s) in cart no longer available, or out of stock etc
  • Specials
  • Order status updates

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.

Deprecated calls: IsInCart & control Item

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;
}

Decouple order processing from OrderForm

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);

How to set up PayPal

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.

Globalised tax calculation

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.

Class Structure

TaxClass
TaxRate extends RegionRate

TaxClass has many TaxRates.

Fix filters system

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.

Ensure mobile module compatibility

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.

Addresses and address book

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.

Address selection

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.

Stress Test Tools

Build some tools to automatically generate a large number of database records. This will help with understanding heavily populated and used sites.

  • Generate products - see #68
  • Generate orders

Optionally enable randomness:

  • Product types
  • Member vs guest orders
  • Payment types
  • Paid / unpaid

Allow choosing from different shipping types

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.

AJAX Cart Support

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.

Cause catalog/product updates to update existing carts

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.

Product Comparison Submodule

Ability to compare products is useful, particular for gadgets and other hardware.

Comparison values could potentially come from different sources:

  • Dataobject field values. e.g. Weight = 23kg
  • Computed values. e.g. sellingPrice = 123.45kg
  • Variation attribute values. e.g. Color = Red, Blue, Green
  • Feature attribute values. e.g. GPS Enabled = yes
  • Feature one-off values. e.g. ScreenResolution = 350 x 1245 px

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

Stylesheet inclusion for theme compatability

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');

Pricing & promotions architecture

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:

  • Allow easy enter of pricing values - via UI, file upload, or API connection.
  • Allow automated price changes.
  • Allow custom calculations.
  • Be flexible as to allow a range of different types of price manipulations, in different configurations and orders.
  • Prevent tampering, eg selling a product for $0 because of some accident

Here's a range of the kinds of price calculations and contributing values:
shop price calculation
original google doc illustration

Other related things to display to the user:

  • Price fluctuations - Display history graph of price changes.
  • Name your price - There may be some circumstances where the customer chooses what to pay.
  • Total savings - Original price, minus discounted price.

Product

  • Cost / Wholesale - the amount paid by the merchant to obtain the goods.
  • Recommended Retail - price that manufacturer recommends.
  • Original - cost + whatever markup merchant has decided. This is what "Price" is currently.
  • Price Adjustments - addition or reduction of original price.
    • Temporary Reduction - time based discount.
    • Tiered / Quantity - different prices for different quantities.
    • Group - specific member groups pay different amounts.
    • Location - charge differently per region.
  • Tax inclusive / exclusive - tax for this product. Item tax can vary in some countries.
  • Currency converted - convert into user-selected currency

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.

Cart Item(s)

Custom calculations could be performed for items, or per line changes might be applicable.

  • Coupon/voucher/gift discount

If the product catalog is updated, then order items also need to be updated.

Order

  • Items Subtotal
  • Discount(s)
  • Tax
  • Shipping + handling
  • Grand total

Some could be totals of item values, or unique values of their own.

Questions to Answer

  • What to keep track of? Should I record the fact that an order item was added with a temporary discount, tiered pricing, group pricing, and used a voucher, and has tax X...or just a single price, and hope that if you ever need to, you can work out those things from some separate history?
  • What order should calculations be done? Prestashop gives the option to choose order.
  • How should/can I allow developers to customise or create price calculations?
  • Do I need to introduce some kind of rules system, like Magento allows?
  • Should I aim for configuration or stick to some convention? What should be: core, module, developer-customisable, merchant-customisable?
  • How do discounts get overridden or appended?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.