Merge branch 'new_shop'

Conflicts:
	app/controllers/checkout_controller.rb
This commit is contained in:
Will Marshall
2014-05-20 15:47:32 +10:00
54 changed files with 493 additions and 309 deletions

View File

@@ -0,0 +1,3 @@
Darkswarm.controller "GroupsCtrl", ($scope, Groups) ->
$scope.Groups = Groups
$scope.order = 'position'

View File

@@ -0,0 +1,9 @@
Darkswarm.controller "ProductNodeCtrl", ($scope) ->
$scope.price = ->
if $scope.product.variants.length > 0
prices = (v.price for v in $scope.product.variants)
Math.min.apply(null, prices)
else
$scope.product.price
$scope.hasVariants = $scope.product.variants.length > 0

View File

@@ -1,8 +1,8 @@
Darkswarm.controller "ProductsCtrl", ($scope, $rootScope, Product, OrderCycle) ->
$scope.data = Product.data
$scope.limit = 3
$scope.ordering = {order: "name"}
$scope.order_cycle = OrderCycle.order_cycle
Product.update()
$scope.incrementLimit = ->
if $scope.limit < $scope.data.products.length
@@ -14,8 +14,3 @@ Darkswarm.controller "ProductsCtrl", ($scope, $rootScope, Product, OrderCycle) -
e.preventDefault()
$scope.productPrice = (product) ->
if product.variants.length > 0
prices = (v.price for v in product.variants)
Math.min.apply(null, prices)
else
product.price

View File

@@ -2,13 +2,14 @@ Darkswarm.directive "ofnModal", ($modal)->
restrict: 'E'
replace: true
transclude: true
scope: {}
template: "<a>{{title}}</a>"
link: (scope, elem, attrs, ctrl, transclude)->
scope.title = attrs.title
contents = null
transclude scope, (clone)->
contents = clone
scope.cancel = ->
scope.modalInstance.dismiss("cancel")
elem.on "click", ->
scope.modalInstance = $modal.open(controller: ctrl, template: transclude())
elem.on "click", =>
scope.modalInstance = $modal.open(controller: ctrl, template: contents)

View File

@@ -0,0 +1,4 @@
Darkswarm.factory 'Groups', (groups) ->
new class Groups
constructor: ->
@groups = groups

View File

@@ -1,12 +1,12 @@
Darkswarm.factory 'Product', ($resource) ->
new class Product
data: {
constructor: ->
@update()
data:
products: null
loading: true
}
update: ->
@data.products = $resource("/shop/products").query =>
@data.loading = false
@data
all: ->
@data.products || @update()

View File

@@ -12,7 +12,7 @@
border: 1px solid #999
font-size: 18px
@extend .avenir
padding: 22px 18px
padding: 0.75em 1em
height: auto
margin-bottom: 1em

View File

@@ -0,0 +1,4 @@
.product_table
.row
border: 1px solid black
padding: 8px inherit

View File

@@ -1,8 +1,7 @@
@import mixins
@import variables
@import branding
product
display: block
.darkswarm
#search
@@ -77,68 +76,58 @@ product
products
display: block
padding-top: 2.3em
padding-top: 2.3em
@media all and (max-width: 768px)
padding-top: 1em
input.button.right
float: left
table
table-layout: fixed
width: 100%
border-collapse: collapse
border: none
th
line-height: 50px
&.name
width: 330px
//&.notes
//width: 140px
&.variant
width: 180px
&.quantity, &.bulk, &.price
width: 90px
.notes
max-width: 300px
td, th
product:hover, product:focus, product:active
border-color: $clr-brick
@include box-shadow(0 0 3px 0 $clr-brick-bright)
.row.variants
border-top: 1px solid $clr-brick-light
background: $clr-brick-ultra-light
product
@include csstrans
border: 1px solid #989898
display: block
margin-bottom: 1em !important
input
margin: 0
width: 8em
.columns
padding-top: 1em
padding-bottom: 1em
.row.summary, .row.variants
@include csstrans
margin-left: 0
margin-right: 0
background: #f7f7f7
border-top: 1px solid #dfdfdf
.row.summary
@include csstrans
background: #fff
> span
min-width: 50px
display: block
tbody
border: 1px solid #cccccc
border-left: 0px
border-right: 0px
td
padding: 20px 0px
&.name
img
float: left
margin-right: 30px
@media all and (max-width: 768px)
margin-right: 1em
div
min-width: 150px
tr.product-description
display: none
.summary-header
&, & *
@include avenir
color: $clr-brick
.summary-price
&, & *
@include avenir
// Responsive
@media all and (max-width: 768px)
td.notes, th.notes
display: none
img
width: 20px
height: auto
tr.product-description
display: table-row
td:empty
display: none
input[type=number]
width: 60px
margin: 0px
display: block
float: right
padding-top: 14px

View File

@@ -0,0 +1,3 @@
// Place all the styles related to the groups controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@@ -15,12 +15,10 @@ module Admin
redirect_to main_app.admin_enterprise_groups_path
end
private
def collection
EnterpriseGroup.by_position
end
end
end

View File

@@ -26,7 +26,11 @@ class CheckoutController < Spree::CheckoutController
if @order.next
state_callback(:after)
else
flash[:error] = @order.errors.full_messages.to_sentence
unless @order.errors.empty?
flash[:error] = @order.errors.full_messages.to_sentence
else
flash[:error] = t(:payment_processing_failed)
end
update_failed
return
end

View File

@@ -0,0 +1,7 @@
class GroupsController < BaseController
layout 'darkswarm'
def index
@groups = EnterpriseGroup.on_front_page.by_position
end
end

View File

@@ -11,4 +11,4 @@ Spree::Admin::BaseController.class_eval do
authorize! :admin, record
authorize! action, record
end
end
end

View File

@@ -4,4 +4,17 @@ Spree::Admin::OverviewController.class_eval do
@product_count = Spree::Product.active.managed_by(spree_current_user).count
@order_cycle_count = OrderCycle.active.managed_by(spree_current_user).count
end
end
# This is in Spree::Core::ControllerHelpers::Auth
# But you can't easily reopen modules in Ruby
def unauthorized
if try_spree_current_user
flash[:error] = t(:authorization_failure)
redirect_to '/unauthorized'
else
store_location
url = respond_to?(:spree_login_path) ? spree_login_path : root_path
redirect_to url
end
end
end

View File

@@ -0,0 +1,2 @@
module GroupsHelper
end

View File

@@ -4,6 +4,17 @@ class EnterpriseGroup < ActiveRecord::Base
has_and_belongs_to_many :enterprises
validates :name, presence: true
validates :description, presence: true
attr_accessible :name, :description, :long_description, :on_front_page, :enterprise_ids
attr_accessible :promo_image
has_attached_file :promo_image, styles: {medium: "800>400"}
validates_attachment_content_type :promo_image, :content_type => /\Aimage\/.*\Z/
attr_accessible :logo
has_attached_file :logo, styles: {medium: "100x100"}
validates_attachment_content_type :logo, :content_type => /\Aimage\/.*\Z/
scope :by_position, order('position ASC')
scope :on_front_page, where(on_front_page: true)

View File

@@ -118,6 +118,10 @@ Spree::Product.class_eval do
order_cycle.variants_distributed_by(distributor).where(product_id: self)
end
def primary_taxon
self.taxons.order.first
end
# Build a product distribution for each distributor
def build_product_distributions_for_user user
Enterprise.is_distributor.managed_by(user).each do |distributor|

View File

@@ -3,6 +3,16 @@
%br/
= f.text_field :name
= f.field_container :description do
= f.label :description
%br/
= f.text_field :description
= f.field_container :long_description do
= f.label :long_description
%br/
= f.text_area :long_description
= f.field_container :on_front_page do
= f.label :on_front_page, 'On front page?'
%br/
@@ -12,3 +22,22 @@
= f.label :enterprise_ids, 'Enterprises'
%br/
= f.collection_select :enterprise_ids, Enterprise.all, :id, :name, {}, {class: "select2 fullwidth", multiple: true}
.row
.alpha.three.columns
= f.label :logo, class: 'with-tip', 'data-powertip' => 'This is the logo'
.with-tip{'data-powertip' => 'This is the logo'}
%a What's this?
.omega.eight.columns
= image_tag @object.logo.url if @object.logo.present?
= f.file_field :logo
.row
.alpha.three.columns
= f.label :promo_image, class: 'with-tip', 'data-powertip' => 'This image is displayed at the top of the Group profile'
.with-tip{'data-powertip' => 'This image is displayed at the top of the Group profile'}
%a What's this?
.omega.eight.columns
= image_tag @object.promo_image.url if @object.promo_image.present?
= f.file_field :promo_image

View File

@@ -0,0 +1,25 @@
#groups{"ng-controller" => "GroupsCtrl"}
:javascript
angular.module('Darkswarm').value('groups', #{render partial: "json/groups", object: @groups})
.row
.small-12.columns.text-center
%h1 Groups / Regions
%h3 Check out our food groups below
%input{type: :text,
"ng-model" => "query",
placeholder: "Search group name",
"ng-debounce" => "150",
"ofn-disable-enter" => true}
.row.group_table{bindonce: true}
.small.12.columns
.group{"ng-repeat" => "group in Groups.groups | filter:query | orderBy:order"}
%h2 {{ group.name }}
%p {{ group.description }}
%p {{ group.long_description }}
%img{"bo-src" => "group.logo"}
%ul
%li{"ng-repeat" => "enterprise in group.enterprises"}
%a{"bo-href" => "enterprise.path"} {{ enterprise.name }}

View File

@@ -2,7 +2,8 @@
.columns.small-4
%strong Shop for
%p.trans-sentence
{{ hub.taxons | printArrayOfObjects }}
%img{"ng-repeat" => "taxon in hub.taxons", "bo-src" => "taxon.icon",
name: "{{taxon.name}}", alt: "{{taxon.name}}"}
.columns.small-4
%strong Delivery options
%ol
@@ -10,8 +11,9 @@
%li.delivery{"bo-if" => "hub.delivery"} Delivery
.columns.small-4
%strong Our producers
%p
Go to our shop to see our current producers
%ul
%li{"ng-repeat" => "producer in hub.producers"}
= render partial: "modals/producer"
.row.active_table_row.link{"ng-show" => "open()", "ng-if" => "hub.active"}
.columns.small-11

View File

@@ -4,3 +4,11 @@ attributes :name, :id, :description
child :address do
extends "json/partials/address"
end
node :path do |enterprise|
shop_enterprise_path(enterprise)
end
node :hash do |enterprise|
enterprise.to_param
end

View File

@@ -0,0 +1,10 @@
collection @groups
attributes :id, :name, :position, :description, :long_description
child enterprises: :enterprises do
extends 'json/enterprises'
end
node :logo do |group|
group.logo(:original)
end

View File

@@ -2,11 +2,15 @@ collection Enterprise.visible.is_distributor
extends 'json/enterprises'
child distributed_taxons: :taxons do
attributes :name, :id
extends "json/taxon"
end
child suppliers: :producers do
attributes :name, :id
attributes :name, :id, :description, :long_description
node :promo_image do |producer|
producer.promo_image.url
end
end
node :pickup do |hub|
@@ -17,14 +21,6 @@ node :delivery do |hub|
not hub.shipping_methods.where(:require_ship_address => true).empty?
end
node :path do |hub|
shop_enterprise_path(hub)
end
node :hash do |hub|
hub.to_param
end
node :active do |hub|
@active_distributors.include?(hub)
end

View File

@@ -2,7 +2,7 @@ collection @producers
extends 'json/enterprises'
child supplied_taxons: :taxons do
attributes :name, :id
extends 'json/taxon'
end
child distributors: :distributors do

View File

@@ -0,0 +1,5 @@
attributes :name, :id, :permalink
node :icon do |taxon|
taxon.icon.url
end

View File

@@ -2,4 +2,4 @@
%h5 Our food hubs are the point of contact between you and the people who make your food!
%p You can search for a convenient hub by location or name. Some hubs have multiple points where you can pick-up your purchases, and some will also provide delivery options. Each food hub is a sales point with independent business operations and logisitics - so variations between hubs are to be expected.
%p You can only shop one food hub at a time.
%a.close-reveal-modal{"ng-click" => "cancel()"} &#215;
%a.close-reveal-modal{"ng-click" => "$close()"} &#215;

View File

@@ -6,4 +6,4 @@
%h5 Learn more
%p If you want to learn more about the Open Food Network, how it works, and get involved, check out:
%a.button.neutral-btn.dark{:href => "http://www.openfoodnetwork.org" , :target => "_blank" } Open Food Network
%a.close-reveal-modal{"ng-click" => "cancel()"} &#215;
%a.close-reveal-modal{"ng-click" => "$close()"} &#215;

View File

@@ -0,0 +1,13 @@
%ofn-modal{title: "{{ producer.name }}"}
#producer_modal{bindonce: true}
.row
.small-12.columns
%img{"bo-src" => "producer.promo_image"}
%h3 {{ producer.name }}
.row
.small-6.columns
%p
{{ producer.description }}
.small-6.columns
Stay in touch with {{ producer.name }}

View File

@@ -21,7 +21,7 @@
%span.nav-primary Producers
%li.divider
%li
%a{href: ""}
%a{href: main_app.groups_path}
%span.nav-primary Groups
%li.divider
- if admin_user? or enterprise_user?

View File

@@ -36,17 +36,14 @@
%li
%a{href: root_path + "#/#hubs"}
%span.nav-primary Hubs
%li
%a{href: ""}
%span.nav-primary Map
%li
%a{href: main_app.producers_path}
%span.nav-primary Producers
%li
%a{href: ""}
%a{href: main_app.groups_path}
%span.nav-primary Groups

View File

@@ -1,79 +0,0 @@
%products{"ng-controller" => "ProductsCtrl", "ng-show" => "order_cycle.order_cycle_id != null",
"infinite-scroll" => "incrementLimit()", "infinite-scroll-distance" => "1"}
= form_for :order, :url => populate_orders_path, html: {:class => "custom"} do
%input#search.text{"ng-model" => "query",
placeholder: "Search",
"ng-debounce" => "150",
"ng-keypress" => "searchKeypress($event)"}
%input.button.right{type: :submit, value: "Add to Cart"}
%table
%thead
%th.name Item
%th.notes Notes
%th.variant Unit
%th.quantity QTY
%th.bulk Bulk
%th.price.text-right Price
%tbody{"ng-show" => "data.loading"}
%tr
%td{colspan: 6}
%h3.text-center Loading Products
%tbody{"ng-repeat" => "product in data.products | filter:query | limitTo: limit track by product.id"}
%tr{"class" => "product product-{{ product.id }}"}
%td.name{bindonce: "product"}
%img{"bo-src" => "product.master.images[0].small_url"}
%div
%h5
{{ product.name }}
%a{"data-reveal-id" => "producer_details_{{product.supplier.id}}", "data-reveal" => ""}
{{ product.supplier.name }}
%td.notes{bindonce: ""} {{ product.notes | truncate:80 }}
%td{bindonce: ""}
%span{"ng-hide" => "product.variants.length > 0"} {{ product.master.options_text }}
%span{"ng-show" => "product.variants.length > 0"}
%img.collapse{src: "/assets/collapse.png",
"ng-show" => "product.show_variants",
"ng-click" => "product.show_variants = !product.show_variants"}
%img.expand{src: "/assets/expand.png",
"ng-show" => "!product.show_variants",
"ng-click" => "product.show_variants = !product.show_variants"}
%td
%span{"ng-show" => "(product.variants.length == 0)"}
%input{type: :number,
value: nil,
min: 0,
"ofn-disable-scroll" => true,
max: "{{product.on_demand && 9999 || product.count_on_hand }}",
name: "variants[{{product.master.id}}]",
id: "variants_{{product.master.id}}",
"ng-model" => "product.quantity"}
%td.group_buy
%span{"ng-show" => "product.group_buy && (product.variants.length == 0)"}
%input{type: :number,
min: 0,
"ofn-disable-scroll" => true,
max: "{{product.on_demand && 9999 || product.count_on_hand }}",
name: "variant_attributes[{{product.master.id}}][max_quantity]",
"ng-model" => "product.max_quantity"}
%td.price.text-right{bindonce: ""}
%small{"ng-show" => "(product.variants.length > 0)"} from
{{ productPrice(product) | currency }}
%tr.product-description{bindonce: ""}
%td{colspan: 2}{{ product.notes | truncate:80 }}
%tr.variant{"ng-repeat" => "variant in product.variants", "ng-if" => "product.show_variants"}
= render partial: "shop/variant"
%input.button.right{type: :submit, value: "Add to Cart"}

View File

@@ -1,22 +0,0 @@
%td
%td.notes
%td{bindonce: ""} {{variant.options_text}}
%td
%input{type: :number,
value: nil,
min: 0,
"ofn-disable-scroll" => true,
max: "{{variant.on_demand && 9999 || variant.count_on_hand }}",
name: "variants[{{variant.id}}]", id: "variants_{{variant.id}}",
"ng-model" => "variant.quantity"}
%td.group_buy
%span{"ng-show" => "product.group_buy"}
%input{type: :number,
min: 0,
"ofn-disable-scroll" => true,
max: "{{variant.on_demand && 9999 || variant.count_on_hand }}",
name: "variant_attributes[{{variant.id}}][max_quantity]",
"ng-model" => "variant.max_quantity"}
%td.price.text-right{bindonce: ""}
{{ variant.price | currency }}

View File

@@ -1,10 +1,6 @@
collection @products
attributes :id, :name, :permalink, :count_on_hand, :on_demand, :group_buy
node :show_variants do
true
end
node do |product|
{
notes: strip_tags(product.notes),
@@ -17,6 +13,10 @@ child :supplier => :supplier do
attributes :id, :name, :description
end
child :primary_taxon => :primary_taxon do
extends 'json/taxon'
end
child :master => :master do
attributes :id, :is_master, :count_on_hand, :options_text, :count_on_hand, :on_demand
child :images => :images do

View File

@@ -0,0 +1,29 @@
%products.small-12.columns{"ng-controller" => "ProductsCtrl", "ng-show" => "order_cycle.order_cycle_id != null",
"infinite-scroll" => "incrementLimit()", "infinite-scroll-distance" => "1"}
= form_for :order, :url => populate_orders_path, html: {:class => "custom"} do
.row
.small-6.columns
%input#search.text{"ng-model" => "query",
placeholder: "Search",
"ng-debounce" => "150",
"ofn-disable-enter" => true}
.small-6.columns
%input.button.right{type: :submit, value: "Add to Cart"}
%div{bindonce: true}
%product{"ng-controller" => "ProductNodeCtrl",
"ng-repeat" => "product in data.products | filter:query | orderBy:ordering.order | limitTo: limit track by product.id"}
%div
= render partial: "shop/products/summary"
%div{"bo-if" => "hasVariants"}
= render partial: "shop/products/variants"
.variant.row{"bo-if" => "!hasVariants"}
= render partial: "shop/products/master"
.row
.small-12.columns
%input.button.right.add_to_cart{type: :submit, value: "Add to Cart"}

View File

@@ -0,0 +1,39 @@
.small-1.column
%span.bulk{"bo-if" => "product.group_buy"} bulk
&nbsp;
.small-4.columns
({{ product.master.options_text }})
-# WITHOUT GROUP BUY
.small-5.columns{"bo-if" => "!product.group_buy"}
%input{type: :number,
min: 0,
"ofn-disable-scroll" => true,
max: "{{product.on_demand && 9999 || product.count_on_hand }}",
name: "variants[{{product.master.id}}]",
id: "variants_{{product.master.id}}",
"ng-model" => "product.quantity"}
-# WITH GROUP BUY
.small-2.columns{"bo-if" => "product.group_buy"}
%input{type: :number,
min: 0,
"ofn-disable-scroll" => true,
max: "{{product.on_demand && 9999 || product.count_on_hand }}",
name: "variants[{{product.master.id}}]",
id: "variants_{{product.master.id}}",
"ng-model" => "product.quantity"}
(min)
.small-3.columns{"bo-if" => "product.group_buy"}
%input{type: :number,
min: 0,
"ofn-disable-scroll" => true,
max: "{{product.on_demand && 9999 || product.count_on_hand }}",
name: "variant_attributes[{{product.master.id}}][max_quantity]",
"ng-model" => "product.max_quantity"}
(max)
.small-2.columns.text-right
{{ product.price | currency }}

View File

@@ -0,0 +1,2 @@
%ofn-modal{title: "{{product.name}}"}
{{ product.description }}

View File

@@ -0,0 +1,18 @@
.row.summary
.small-1.column
%img{"bo-src" => "product.master.images[0].small_url"}
.small-4.columns.summary-header
%img{"bo-src" => "product.primary_taxon.icon",
"ng-click" => "ordering.order = 'primary_taxon.name'",
name: "{{product.primary_taxon.name}}"}
{{ product.name}}
-#= render partial: "shop/products/modal"
.small-5.columns.summary-header
{{ product.supplier.name }}
.small-2.columns.summary-price.text-right.price
%span{"ng-if" => "hasVariants"}
%em from
{{ price() | currency }}

View File

@@ -0,0 +1,42 @@
.row.variants{bindonce: true,
"ng-repeat" => "variant in product.variants"}
.small-1.column
%span.bulk{"bo-if" => "product.group_buy"} bulk
&nbsp;
.small-4.columns
{{ variant.options_text }}
-# WITHOUT GROUP BUY
.small-5.columns{"bo-if" => "!product.group_buy"}
%input{type: :number,
value: nil,
min: 0,
"ofn-disable-scroll" => true,
max: "{{variant.on_demand && 9999 || variant.count_on_hand }}",
name: "variants[{{variant.id}}]", id: "variants_{{variant.id}}",
"bo-model" => "variant.quantity"}
-# WITH GROUP BUY
.small-2.columns{"bo-if" => "product.group_buy"}
%input{type: :number,
value: nil,
min: 0,
"ofn-disable-scroll" => true,
max: "{{variant.on_demand && 9999 || variant.count_on_hand }}",
name: "variants[{{variant.id}}]", id: "variants_{{variant.id}}",
"bo-model" => "variant.quantity"}
(min)
.small-3.columns{"bo-if" => "product.group_buy"}
%input{type: :number,
min: 0,
"ofn-disable-scroll" => true,
max: "{{variant.on_demand && 9999 || variant.count_on_hand }}",
name: "variant_attributes[{{variant.id}}][max_quantity]",
"ng-model" => "variant.max_quantity"}
(max)
.small-2.columns.text-right.price
{{ variant.price | currency }}

View File

@@ -13,5 +13,5 @@
= render partial: "shopping_shared/details"
%products.row
= render partial: "shop/products"
.row
= render partial: "shop/products/form"

View File

@@ -1,12 +1,15 @@
Openfoodnetwork::Application.routes.draw do
root :to => 'home#index'
get "/#/login", to: "home#index", as: :spree_login
resource :shop, controller: "shop" do
get :products
post :order_cycle
get :order_cycle
end
resources :groups
resources :producers
get '/checkout', :to => 'checkout#edit' , :as => :checkout

View File

@@ -0,0 +1,15 @@
class AddAttachmentPromoImageToEnterpriseGroup < ActiveRecord::Migration
def self.up
add_column :enterprise_groups, :promo_image_file_name, :string
add_column :enterprise_groups, :promo_image_content_type, :string
add_column :enterprise_groups, :promo_image_file_size, :integer
add_column :enterprise_groups, :promo_image_updated_at, :datetime
end
def self.down
remove_column :enterprise_groups, :promo_image_file_name
remove_column :enterprise_groups, :promo_image_content_type
remove_column :enterprise_groups, :promo_image_file_size
remove_column :enterprise_groups, :promo_image_updated_at
end
end

View File

@@ -0,0 +1,6 @@
class AddFieldsToGroups < ActiveRecord::Migration
def change
add_column :enterprise_groups, :description, :text
add_column :enterprise_groups, :long_description, :text
end
end

View File

@@ -0,0 +1,15 @@
class AddAttachmentLogoToEnterpriseGroup < ActiveRecord::Migration
def self.up
add_column :enterprise_groups, :logo_file_name, :string
add_column :enterprise_groups, :logo_content_type, :string
add_column :enterprise_groups, :logo_file_size, :integer
add_column :enterprise_groups, :logo_updated_at, :datetime
end
def self.down
remove_column :enterprise_groups, :logo_file_name
remove_column :enterprise_groups, :logo_content_type
remove_column :enterprise_groups, :logo_file_size
remove_column :enterprise_groups, :logo_updated_at
end
end

View File

@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20140514044959) do
ActiveRecord::Schema.define(:version => 20140516045323) do
create_table "adjustment_metadata", :force => true do |t|
t.integer "adjustment_id"
@@ -182,9 +182,19 @@ ActiveRecord::Schema.define(:version => 20140514044959) do
add_index "enterprise_fees", ["enterprise_id"], :name => "index_enterprise_fees_on_enterprise_id"
create_table "enterprise_groups", :force => true do |t|
t.string "name"
t.boolean "on_front_page"
t.integer "position"
t.string "name"
t.boolean "on_front_page"
t.integer "position"
t.string "promo_image_file_name"
t.string "promo_image_content_type"
t.integer "promo_image_file_size"
t.datetime "promo_image_updated_at"
t.text "description"
t.text "long_description"
t.string "logo_file_name"
t.string "logo_content_type"
t.integer "logo_file_size"
t.datetime "logo_updated_at"
end
create_table "enterprise_groups_enterprises", :id => false, :force => true do |t|

View File

@@ -0,0 +1,9 @@
require 'spec_helper'
describe GroupsController do
it "gets all visible groups" do
EnterpriseGroup.stub_chain :on_front_page, :by_position
EnterpriseGroup.should_receive :on_front_page
get :index
end
end

View File

@@ -111,90 +111,6 @@ describe ShopController do
response.body.should be_empty
end
# TODO: this should be a controller test baby
pending "filtering products" do
let(:distributor) { create(:distributor_enterprise) }
let(:supplier) { create(:supplier_enterprise) }
let(:oc1) { create(:simple_order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise), orders_close_at: 2.days.from_now) }
let(:p1) { create(:simple_product, on_demand: false) }
let(:p2) { create(:simple_product, on_demand: true) }
let(:p3) { create(:simple_product, on_demand: false) }
let(:p4) { create(:simple_product, on_demand: false) }
let(:p5) { create(:simple_product, on_demand: false) }
let(:p6) { create(:simple_product, on_demand: false) }
let(:p7) { create(:simple_product, on_demand: false) }
let(:v1) { create(:variant, product: p4, unit_value: 2) }
let(:v2) { create(:variant, product: p4, unit_value: 3, on_demand: false) }
let(:v3) { create(:variant, product: p4, unit_value: 4, on_demand: true) }
let(:v4) { create(:variant, product: p5) }
let(:v5) { create(:variant, product: p5) }
let(:v6) { create(:variant, product: p7) }
let(:order) { create(:order, distributor: distributor, order_cycle: order_cycle) }
before do
p1.master.count_on_hand = 1
p2.master.count_on_hand = 0
p1.master.update_attribute(:count_on_hand, 1)
p2.master.update_attribute(:count_on_hand, 0)
p3.master.update_attribute(:count_on_hand, 0)
p6.master.update_attribute(:count_on_hand, 1)
p6.delete
p7.master.update_attribute(:count_on_hand, 1)
v1.update_attribute(:count_on_hand, 1)
v2.update_attribute(:count_on_hand, 0)
v3.update_attribute(:count_on_hand, 0)
v4.update_attribute(:count_on_hand, 1)
v5.update_attribute(:count_on_hand, 0)
v6.update_attribute(:count_on_hand, 1)
v6.update_attribute(:deleted_at, Time.now)
exchange = Exchange.find(oc1.exchanges.to_enterprises(distributor).outgoing.first.id)
exchange.update_attribute :pickup_time, "frogs"
exchange.variants << p1.master
exchange.variants << p2.master
exchange.variants << p3.master
exchange.variants << p6.master
exchange.variants << v1
exchange.variants << v2
exchange.variants << v3
# v4 is in stock but not in distribution
# v5 is out of stock and in the distribution
# Neither should display, nor should their product, p5
exchange.variants << v5
exchange.variants << v6
controller.stub(:current_order).and_return order
visit shop_path
end
it "filters products based on availability" do
# It shows on hand products
page.should have_content p1.name
page.should have_content p4.name
# It shows on demand products
page.should have_content p2.name
# It does not show products that are neither on hand or on demand
page.should_not have_content p3.name
# It shows on demand variants
page.should have_content v3.options_text
# It does not show variants that are neither on hand or on demand
page.should_not have_content v2.options_text
# It does not show products that have no available variants in this distribution
page.should_not have_content p5.name
# It does not show deleted products
page.should_not have_content p6.name
# It does not show deleted variants
page.should_not have_content v6.name
page.should_not have_content p7.name
end
end
context "RABL tests" do
render_views
before do
@@ -211,6 +127,7 @@ describe ShopController do
xhr :get, :products
response.body.should_not have_content product.name
end
it "strips html from description" do
product.update_attribute(:description, "<a href='44'>turtles</a> frogs")
xhr :get, :products
@@ -223,6 +140,14 @@ describe ShopController do
xhr :get, :products
response.body.should have_content "998.0"
end
it "includes the primary taxon" do
taxon = mock_model(Spree::Taxon, name: "fruitbat")
Spree::Product.any_instance.stub(:primary_taxon).and_return taxon
taxon.stub_chain(:icon, :url).and_return ""
xhr :get, :products
response.body.should have_content "fruitbat"
end
end
end
end

View File

@@ -98,6 +98,7 @@ FactoryGirl.define do
factory :enterprise_group, :class => EnterpriseGroup do
name 'Enterprise group'
description 'this is a group'
on_front_page false
end

View File

@@ -33,6 +33,7 @@ feature %q{
click_link 'New Enterprise Group'
fill_in 'enterprise_group_name', with: 'EGEGEG'
fill_in 'enterprise_group_description', with: 'This is a description'
check 'enterprise_group_on_front_page'
select e1.name, from: 'enterprise_group_enterprise_ids'
select e2.name, from: 'enterprise_group_enterprise_ids'
@@ -42,6 +43,7 @@ feature %q{
eg = EnterpriseGroup.last
eg.name.should == 'EGEGEG'
eg.description.should == 'This is a description'
eg.on_front_page.should be_true
eg.enterprises.sort.should == [e1, e2].sort
end
@@ -62,6 +64,7 @@ feature %q{
fill_in 'enterprise_group_name', with: 'xyzzy'
uncheck 'enterprise_group_on_front_page'
unselect e1.name, from: 'enterprise_group_enterprise_ids'
select e2.name, from: 'enterprise_group_enterprise_ids'
click_button 'Update'
@@ -99,7 +102,6 @@ feature %q{
EnterpriseGroup.all.should_not include eg
end
context "as an enterprise user" do
xit "should show me only enterprises I manage when creating a new enterprise group"
end

View File

@@ -90,10 +90,6 @@ feature "As a consumer I want to shop with a distributor", js: true do
it "should not show quantity field for product with variants" do
visit shop_path
page.should_not have_selector("#variants_#{product.master.id}", visible: true)
#it "expands variants" do
find(".collapse").trigger "click"
page.should_not have_text variant1.options_text
end
it "uses the adjusted price" do
@@ -104,15 +100,16 @@ feature "As a consumer I want to shop with a distributor", js: true do
visit shop_path
# Page should not have product.price (with or without fee)
page.should_not have_selector 'tr.product > td', text: "from $10.00"
page.should_not have_selector 'tr.product > td', text: "from $33.00"
page.should_not have_price "from $10.00"
page.should_not have_price "from $33.00"
# Page should have variant prices (with fee)
page.should have_selector 'tr.variant > td.price', text: "$43.00"
page.should have_selector 'tr.variant > td.price', text: "$53.00"
page.should have_price "$43.00"
page.should have_price "$53.00"
# Product price should be listed as the lesser of these
page.should have_selector 'tr.product > td', text: "from $43.00"
#page.should have_selector 'tr.product > td', text: "from $43.00"
page.should have_price "from $43.00"
end
end
@@ -131,7 +128,7 @@ feature "As a consumer I want to shop with a distributor", js: true do
it "should save group buy data to ze cart" do
fill_in "variants[#{product.master.id}]", with: 5
fill_in "variant_attributes[#{product.master.id}][max_quantity]", with: 9
first("form.custom > input.button.right").click
add_to_cart
page.should have_content product.name
li = Spree::Order.order(:created_at).last.line_items.order(:created_at).last
li.max_quantity.should == 9
@@ -142,7 +139,7 @@ feature "As a consumer I want to shop with a distributor", js: true do
pending "adding a product with a max quantity less than quantity results in max_quantity==quantity" do
fill_in "variants[#{product.master.id}]", with: 5
fill_in "variant_attributes[#{product.master.id}][max_quantity]", with: 1
first("form.custom > input.button.right").click
add_to_cart
page.should have_content product.name
li = Spree::Order.order(:created_at).last.line_items.order(:created_at).last
li.max_quantity.should == 5
@@ -161,7 +158,7 @@ feature "As a consumer I want to shop with a distributor", js: true do
it "should save group buy data to ze cart" do
fill_in "variants[#{variant.id}]", with: 6
fill_in "variant_attributes[#{variant.id}][max_quantity]", with: 7
first("form.custom > input.button.right").click
add_to_cart
page.should have_content product.name
li = Spree::Order.order(:created_at).last.line_items.order(:created_at).last
li.max_quantity.should == 7
@@ -181,7 +178,7 @@ feature "As a consumer I want to shop with a distributor", js: true do
end
it "should let us add products to our cart" do
fill_in "variants[#{variant.id}]", with: "1"
first("form.custom > input.button.right").click
add_to_cart
current_path.should == "/cart"
page.should have_content product.name
end

View File

@@ -0,0 +1,15 @@
require 'spec_helper'
# Specs in this file have access to a helper object that includes
# the GroupsHelper. For example:
#
# describe GroupsHelper do
# describe "string concat" do
# it "concats two strings with spaces" do
# expect(helper.concat_strings("this","that")).to eq("this that")
# end
# end
# end
describe GroupsHelper do
pending "add some examples to (or delete) #{__FILE__}"
end

View File

@@ -11,6 +11,13 @@ describe EnterpriseGroup do
e = build(:enterprise_group, name: '')
e.should_not be_valid
end
it "requires a description" do
e = build(:enterprise_group, description: '')
end
it { should have_attached_file :promo_image }
it { should have_attached_file :logo }
end
describe "relations" do

View File

@@ -547,5 +547,15 @@ module Spree
end
end
end
describe "Taxons" do
let(:taxon1) { create(:taxon) }
let(:taxon2) { create(:taxon) }
let(:product) { create(:simple_product, taxons: [taxon1, taxon2]) }
it "returns the first taxon as the primary taxon" do
product.primary_taxon.should == taxon1
end
end
end
end

View File

@@ -1,4 +1,12 @@
module ShopWorkflow
def add_to_cart
first("input.add_to_cart").click
end
def have_price(price)
have_selector ".price", text: price
end
def set_order(order)
ApplicationController.any_instance.stub(:session).and_return({order_id: order.id, access_token: order.token})
end