diff --git a/app/assets/javascripts/store/all.js b/app/assets/javascripts/store/all.js index 723f03af31..4da67e3567 100644 --- a/app/assets/javascripts/store/all.js +++ b/app/assets/javascripts/store/all.js @@ -9,5 +9,7 @@ //= require store/spree_core //= require store/spree_auth //= require store/spree_promo +//= require shared/angular +//= require shared/angular-resource //= require_tree . diff --git a/app/assets/javascripts/store/controllers/cart.js.coffee b/app/assets/javascripts/store/controllers/cart.js.coffee new file mode 100644 index 0000000000..240cb791f4 --- /dev/null +++ b/app/assets/javascripts/store/controllers/cart.js.coffee @@ -0,0 +1,18 @@ +'use strict' + +angular.module('store', ['ngResource']). + controller 'CartCtrl', ($scope, $window, CartFactory) -> + + $scope.loadCart = -> + $scope.cart = CartFactory.load(1) + + $scope.addVariant = (variant, quantity) -> + + .config(['$httpProvider', ($httpProvider) -> + $httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content') + ]) + + + + + diff --git a/app/assets/javascripts/store/factories/cart.js.coffee b/app/assets/javascripts/store/factories/cart.js.coffee new file mode 100644 index 0000000000..d0d0d8ddd1 --- /dev/null +++ b/app/assets/javascripts/store/factories/cart.js.coffee @@ -0,0 +1,12 @@ +'use strict' + +angular.module('store'). + factory 'CartFactory', ($resource, $window, $http) -> + Cart = $resource '/open_food_web/cart/:cart_id.json', {}, + { 'show': { method: 'GET'} } + + load: (id, callback) -> + Cart.show {cart_id: id}, (cart) -> + callback(cart) + + diff --git a/app/controllers/open_food_web/cart_controller.rb b/app/controllers/open_food_web/cart_controller.rb new file mode 100644 index 0000000000..7b6a37ce0e --- /dev/null +++ b/app/controllers/open_food_web/cart_controller.rb @@ -0,0 +1,25 @@ +module OpenFoodWeb + class CartController < ApplicationController + respond_to :json + + # before_filter :authorize_read!, :except => [:index, :search, :create] + + def new + @cart = Cart.new(current_api_user) + if @cart.save + respond_with(@cart, :status => 201) + else + invalid_resource!(@cart) + end + end + + def show + @cart = Cart.find(params[:id]) + respond_with(@cart) + end + + def add_product + end + + end +end \ No newline at end of file diff --git a/app/models/cart.rb b/app/models/cart.rb new file mode 100644 index 0000000000..32a0ad33da --- /dev/null +++ b/app/models/cart.rb @@ -0,0 +1,12 @@ +class Cart < ActiveRecord::Base + has_many :orders, :class_name => 'Spree::Order' + belongs_to :user, :class_name => Spree.user_class + + def add_variant variant, quantity + if orders.empty? + order = Spree::Order.create + order.add_variant(variant, quantity) + orders << order + end + end +end diff --git a/app/models/spree/order_decorator.rb b/app/models/spree/order_decorator.rb index 458b3eb7df..a5f5f87c0d 100644 --- a/app/models/spree/order_decorator.rb +++ b/app/models/spree/order_decorator.rb @@ -3,6 +3,7 @@ require 'open_food_web/distribution_change_validator' Spree::Order.class_eval do belongs_to :order_cycle belongs_to :distributor, :class_name => 'Enterprise' + belongs_to :cart before_validation :shipping_address_from_distributor validate :products_available_from_new_distribution, :if => lambda { distributor_id_changed? || order_cycle_id_changed? } diff --git a/app/overrides/add_multi_cart_to_home.rb b/app/overrides/add_multi_cart_to_home.rb new file mode 100644 index 0000000000..e11cfaa728 --- /dev/null +++ b/app/overrides/add_multi_cart_to_home.rb @@ -0,0 +1,9 @@ +Deface::Override.new(:virtual_path => "spree/products/index", + :insert_after => "[data-hook='homepage_products']", + :partial => 'spree/shared/multi_cart.html', + :name => 'multi_cart_home') + +Deface::Override.new(:virtual_path => "spree/home/index", + :insert_after => "[data-hook='homepage_products']", + :partial => 'spree/shared/multi_cart.html', + :name => 'multi_cart_products') diff --git a/app/views/open_food_web/cart/_show.html.haml b/app/views/open_food_web/cart/_show.html.haml new file mode 100644 index 0000000000..7ca89c6633 --- /dev/null +++ b/app/views/open_food_web/cart/_show.html.haml @@ -0,0 +1,8 @@ +/ %script = Spree.api_key = raw(try_spree_current_user.try(:spree_api_key).to_s.inspect) + +Hello +%div{ 'ng-app' => 'store', 'ng-controller' => 'CartCtrl', 'ng-init' => "loadCart();" } + {{cart}} + %ul + %li(ng-repeat="order in cart.orders") + {{order.distributor}} diff --git a/app/views/open_food_web/cart/show.v1.rabl b/app/views/open_food_web/cart/show.v1.rabl new file mode 100644 index 0000000000..0e61a17162 --- /dev/null +++ b/app/views/open_food_web/cart/show.v1.rabl @@ -0,0 +1,6 @@ +object @cart +attributes :id + +node( :orders ) do |p| + partial '/open_food_web/orders/index', object: p.orders +end diff --git a/app/views/open_food_web/orders/index.v1.rabl b/app/views/open_food_web/orders/index.v1.rabl new file mode 100644 index 0000000000..b2f25229df --- /dev/null +++ b/app/views/open_food_web/orders/index.v1.rabl @@ -0,0 +1,3 @@ +collection @orders + +extends "open_food_web/orders/show" \ No newline at end of file diff --git a/app/views/open_food_web/orders/show.v1.rabl b/app/views/open_food_web/orders/show.v1.rabl new file mode 100644 index 0000000000..d3812cb9b8 --- /dev/null +++ b/app/views/open_food_web/orders/show.v1.rabl @@ -0,0 +1,4 @@ +object @order +attributes :id + +node( :distributor ) { |p| p.distributor.blank? ? "" : p.distributor.name } diff --git a/app/views/spree/shared/_multi_cart.html.haml b/app/views/spree/shared/_multi_cart.html.haml new file mode 100644 index 0000000000..346ec729f0 --- /dev/null +++ b/app/views/spree/shared/_multi_cart.html.haml @@ -0,0 +1,3 @@ + +- if OpenFoodWeb::FeatureToggle.enabled? :multi_cart + = render :partial => 'open_food_web/cart/show' \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index e5363e7dd8..33b2f77639 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -23,6 +23,10 @@ Openfoodweb::Application.routes.draw do get "new_landing_page", :controller => 'home', :action => "new_landing_page" + namespace :open_food_web do + resources :cart + end + # Mount Spree's routes mount Spree::Core::Engine, :at => '/' end diff --git a/db/migrate/20130807230834_add_cart.rb b/db/migrate/20130807230834_add_cart.rb new file mode 100644 index 0000000000..38d94a7c8e --- /dev/null +++ b/db/migrate/20130807230834_add_cart.rb @@ -0,0 +1,9 @@ +class AddCart < ActiveRecord::Migration + def change + create_table :carts do |t| + t.integer :user_id + end + + add_column :spree_orders, :cart_id, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index c1b850281c..ac8c7f6946 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,11 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20130807002915) do +ActiveRecord::Schema.define(:version => 20130807230834) do + + create_table "carts", :force => true do |t| + t.integer "user_id" + end create_table "cms_blocks", :force => true do |t| t.integer "page_id", :null => false @@ -447,6 +451,7 @@ ActiveRecord::Schema.define(:version => 20130807002915) do t.string "currency" t.string "last_ip_address" t.integer "order_cycle_id" + t.integer "cart_id" end add_index "spree_orders", ["number"], :name => "index_orders_on_number" diff --git a/lib/open_food_web/feature_toggle.rb b/lib/open_food_web/feature_toggle.rb index 2be0c1542f..ecb5fd1e1d 100644 --- a/lib/open_food_web/feature_toggle.rb +++ b/lib/open_food_web/feature_toggle.rb @@ -4,13 +4,13 @@ module OpenFoodWeb features[feature] end - private def self.features {eaterprises: true, local_organics: false, order_cycles: false, + multi_cart: false, enterprises_distributor_info_rich_text: false} end end diff --git a/spec/controllers/cart_controller_spec.rb b/spec/controllers/cart_controller_spec.rb new file mode 100644 index 0000000000..2657c37509 --- /dev/null +++ b/spec/controllers/cart_controller_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' +require 'spree/api/testing_support/helpers' + +module OpenFoodWeb + describe CartController do + render_views + + let(:user) { FactoryGirl.create(:user) } + let(:product1) { FactoryGirl.create(:product) } + let(:cart) { Cart.create(user: user) } + + before do + end + + context "as a normal user" do + + context 'with an existing cart' do + + it "retrieves an empty cart" do + get :show, {id: cart, :format => :json } + json_response = JSON.parse(response.body) + + json_response['id'].should == cart.id + json_response['orders'].size.should == 0 + end + + context 'with an order' do + + let(:order) { FactoryGirl.create(:order_with_totals_and_distributor) } + + before(:each) do + cart.orders << order + cart.save! + end + + it "retrieves a cart with a single order and line item" do + get :show, {id: cart, :format => :json } + json_response = JSON.parse(response.body) + + json_response['orders'].size.should == 1 + json_response['orders'].first['distributor'].should == order.distributor.name + end + end + end + end + end +end \ No newline at end of file diff --git a/spec/models/cart_spec.rb b/spec/models/cart_spec.rb new file mode 100644 index 0000000000..1c8997f15b --- /dev/null +++ b/spec/models/cart_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' + +describe Cart do + + describe "associations" do + it { should have_many(:orders) } + end + + describe 'adding a product' do + + let(:product) { create(:product) } + + it 'when there are no orders in the cart, create one when a product is added' do + subject.add_variant product.master, 3 + + subject.orders.size.should == 1 + subject.orders.first.line_items.first.product.should == product + end + + it 'should create an order when a product from a new distributor is added' + + it 'should create an order when a product from a new order cycle is added' + + it 'should create line items in an order for added product, when in the same distributor' + + it 'should create line items in an order for added product, when in the same distributor and order cycle' + + it 'should not create line items in an order, if the product is in a different order cycle to the order' + + it 'should not create line items in an order, if the product is in a different distributor to the order' + end +end