Merge branch 'master' into bom

This commit is contained in:
Rob H
2014-04-10 16:30:13 +10:00
76 changed files with 727 additions and 197 deletions

1
.rspec
View File

@@ -1 +1,2 @@
--colour
--profile

View File

@@ -21,6 +21,7 @@ gem 'bugsnag'
gem 'newrelic_rpm'
gem 'haml'
gem 'sass', "~> 3.2"
gem 'sass-rails', '~> 3.2.3', groups: [:default, :assets]
gem 'aws-sdk'
gem 'db2fog'
gem 'andand'
@@ -39,7 +40,6 @@ gem 'rack-ssl', :require => 'rack/ssl'
# Gems used only for assets and not required
# in production environments by default.
group :assets do
gem 'sass-rails', '~> 3.2.3'
gem 'compass-rails'
gem 'coffee-rails', '~> 3.2.1'
@@ -49,6 +49,7 @@ group :assets do
gem 'uglifier', '>= 1.0.3'
gem 'turbo-sprockets-rails3'
gem 'foundation-icons-sass-rails'
end
gem "foundation-rails"

View File

@@ -262,6 +262,9 @@ GEM
nokogiri (~> 1.5)
ruby-hmac
formatador (0.2.4)
foundation-icons-sass-rails (3.0.0)
railties (>= 3.1.1)
sass-rails (>= 3.1.1)
foundation-rails (5.2.1.0)
railties (>= 3.1.0)
sass (>= 3.2.0)
@@ -509,6 +512,7 @@ DEPENDENCIES
eaterprises_feature!
factory_girl_rails
faker
foundation-icons-sass-rails
foundation-rails
foundation_rails_helper!
geocoder

View File

@@ -1,3 +1,6 @@
[![Build Status](http://ci.openfood.com.au:8080/buildStatus/icon?job=openfoodweb - tests)](http://ci.openfood.com.au:8080/job/openfoodweb%20-%20tests/)
[![Code Climate](https://codeclimate.com/github/openfoodfoundation/openfoodnetwork.png)](https://codeclimate.com/github/openfoodfoundation/openfoodnetwork)
# Open Food Network
Connect suppliers (ie. farmers), distributors (ie. co-ops) and

View File

@@ -9,9 +9,15 @@ angular.module('order_cycle', ['ngResource'])
$scope.loaded = ->
Enterprise.loaded && EnterpriseFee.loaded
$scope.suppliedVariants = (enterprise_id) ->
Enterprise.suppliedVariants(enterprise_id)
$scope.exchangeSelectedVariants = (exchange) ->
OrderCycle.exchangeSelectedVariants(exchange)
$scope.setExchangeVariants = (exchange, variants, selected) ->
OrderCycle.setExchangeVariants(exchange, variants, selected)
$scope.enterpriseTotalVariants = (enterprise) ->
Enterprise.totalVariants(enterprise)
@@ -83,9 +89,15 @@ angular.module('order_cycle', ['ngResource'])
$scope.loaded = ->
Enterprise.loaded && EnterpriseFee.loaded && OrderCycle.loaded
$scope.suppliedVariants = (enterprise_id) ->
Enterprise.suppliedVariants(enterprise_id)
$scope.exchangeSelectedVariants = (exchange) ->
OrderCycle.exchangeSelectedVariants(exchange)
$scope.setExchangeVariants = (exchange, variants, selected) ->
OrderCycle.setExchangeVariants(exchange, variants, selected)
$scope.enterpriseTotalVariants = (enterprise) ->
Enterprise.totalVariants(enterprise)
@@ -175,6 +187,9 @@ angular.module('order_cycle', ['ngResource'])
toggleProducts: (exchange) ->
exchange.showProducts = !exchange.showProducts
setExchangeVariants: (exchange, variants, selected) ->
exchange.variants[variant] = selected for variant in variants
addSupplier: (new_supplier_id) ->
this.order_cycle.incoming_exchanges.push({enterprise_id: new_supplier_id, incoming: true, active: true, variants: {}, enterprise_fees: []})
@@ -271,12 +286,27 @@ angular.module('order_cycle', ['ngResource'])
console.log('Failed to update order cycle')
dataForSubmit: ->
data = angular.extend({}, this.order_cycle)
data = this.deepCopy()
data = this.removeInactiveExchanges(data)
data = this.translateCoordinatorFees(data)
data = this.translateExchangeFees(data)
data
deepCopy: ->
data = angular.extend({}, this.order_cycle)
# Copy exchanges
data.incoming_exchanges = (angular.extend {}, exchange for exchange in this.order_cycle.incoming_exchanges) if this.order_cycle.incoming_exchanges?
data.outgoing_exchanges = (angular.extend {}, exchange for exchange in this.order_cycle.outgoing_exchanges) if this.order_cycle.outgoing_exchanges?
# Copy exchange fees
all_exchanges = (data.incoming_exchanges || []) + (data.outgoing_exchanges || [])
for exchange in all_exchanges
if exchange.enterprise_fees?
exchange.enterprise_fees = (angular.extend {}, fee for fee in exchange.enterprise_fees)
data
removeInactiveExchanges: (order_cycle) ->
order_cycle.incoming_exchanges =
(exchange for exchange in order_cycle.incoming_exchanges when exchange.active)
@@ -322,6 +352,16 @@ angular.module('order_cycle', ['ngResource'])
this.enterprises
suppliedVariants: (enterprise_id) ->
vs = (this.variantsOf(product) for product in this.enterprises[enterprise_id].supplied_products)
[].concat vs...
variantsOf: (product) ->
if product.variants.length > 0
variant.id for variant in product.variants
else
[product.master_id]
totalVariants: (enterprise) ->
numVariants = 0

View File

@@ -0,0 +1,16 @@
window.AccountSidebarCtrl = Darkswarm.controller "AccountSidebarCtrl", ($scope, $http, $location, SpreeUser, Navigation) ->
$scope.path = "/account"
Navigation.paths.push $scope.path
$scope.active = ->
$location.path() == $scope.path
$scope.select = ->
Navigation.navigate($scope.path)
$scope.emptyCart = (href, ev)->
console.log href
if $(ev.delegateTarget).hasClass "empties-cart"
location.href = href if confirm "Changing your Hub will clear your cart."
else
location.href = href

View File

@@ -1,12 +1,14 @@
window.ForgotSidebarCtrl = Darkswarm.controller "ForgotSidebarCtrl", ($scope, $http, $location, SpreeUser) ->
window.ForgotSidebarCtrl = Darkswarm.controller "ForgotSidebarCtrl", ($scope, $http, $location, SpreeUser, Navigation) ->
$scope.spree_user = SpreeUser.spree_user
$scope.path = "/forgot"
$scope.sent = false
Navigation.paths.push $scope.path
$scope.active = ->
$location.path() == '/forgot'
$location.path() == $scope.path
$scope.select = ->
$location.path("/forgot")
Navigation.navigate($scope.path)
$scope.submit = ->
if $scope.spree_user.email != null

View File

@@ -1,11 +1,14 @@
window.LoginSidebarCtrl = Darkswarm.controller "LoginSidebarCtrl", ($scope, $http, $location, SpreeUser) ->
window.LoginSidebarCtrl = Darkswarm.controller "LoginSidebarCtrl", ($scope, $http, $location, SpreeUser, Navigation) ->
$scope.spree_user = SpreeUser.spree_user
$scope.path = "/login"
Navigation.paths.push $scope.path
$scope.active = ->
$location.path() == '/login'
$location.path() == $scope.path
$scope.select = ->
$location.path("/login")
Navigation.navigate($scope.path)
$scope.submit = ->
$http.post("/user/spree_user/sign_in", {spree_user: $scope.spree_user}).success (data)->

View File

@@ -1,12 +1,13 @@
window.MenuCtrl = Darkswarm.controller "MenuCtrl", ($scope, $location) ->
window.MenuCtrl = Darkswarm.controller "MenuCtrl", ($scope, Navigation) ->
$scope.toggleLogin = ->
if $location.path() == "/login"
$location.path("/")
else
$location.path("login")
Navigation.navigate "/login"
$scope.toggleSignup = ->
if $location.path() == "/signup"
$location.path("/")
else
$location.path("signup")
Navigation.navigate "/signup"
$scope.toggleSignup = ->
Navigation.navigate "/signup"
$scope.toggle = (path = null)->
Navigation.navigate(path)

View File

@@ -1,5 +1,15 @@
Darkswarm.controller "OrderCycleCtrl", ($scope, $rootScope, OrderCycle) ->
Darkswarm.controller "OrderCycleCtrl", ($scope, $rootScope, OrderCycle, $timeout) ->
$scope.order_cycle = OrderCycle.order_cycle
$scope.OrderCycle = OrderCycle
$scope.changeOrderCycle = ->
OrderCycle.push_order_cycle()
$timeout ->
$("#order_cycle_id").trigger("closeTrigger")
# Timeout forces this to be evaluated after everything is loaded
# This is a hack. We should probably write our own "popover" directive
# That takes an expression instead of a trigger, and binds to that
$timeout =>
if !$scope.OrderCycle.selected()
$("#order_cycle_id").trigger("openTrigger")

View File

@@ -1,3 +1,5 @@
window.SidebarCtrl = Darkswarm.controller "SidebarCtrl", ($scope, $location) ->
$scope.sidebarPaths = ["/login", "/signup", "/forgot", "/account"]
$scope.active = ->
$location.path() in ["/login", "/signup", "/forgot"]
$location.path() in $scope.sidebarPaths

View File

@@ -1,14 +1,16 @@
window.SignupSidebarCtrl = Darkswarm.controller "SignupSidebarCtrl", ($scope, $http, $location, SpreeUser) ->
window.SignupSidebarCtrl = Darkswarm.controller "SignupSidebarCtrl", ($scope, $http, $location, SpreeUser, Navigation) ->
$scope.spree_user = SpreeUser.spree_user
$scope.path = "/signup"
Navigation.paths.push $scope.path
$scope.errors =
email: null
password: null
$scope.active = ->
$location.path() == '/signup'
$location.path() == $scope.path
$scope.select = ->
$location.path("/signup")
Navigation.navigate($scope.path)
$scope.submit = ->
$http.post("/user/spree_user", {spree_user: $scope.spree_user}).success (data)->

View File

@@ -1,4 +1,7 @@
window.Darkswarm = angular.module("Darkswarm", ["ngResource", "filters", 'mm.foundation']).config ($httpProvider) ->
window.Darkswarm = angular.module("Darkswarm", ["ngResource", "filters", 'mm.foundation']).config ($httpProvider, $tooltipProvider) ->
$httpProvider.defaults.headers.post['X-CSRF-Token'] = $('meta[name="csrf-token"]').attr('content')
$httpProvider.defaults.headers['common']['X-Requested-With'] = 'XMLHttpRequest'
$httpProvider.defaults.headers.common.Accept = "application/json, text/javascript, */*"
# This allows us to trigger these two events on tooltips
$tooltipProvider.setTriggers( 'openTrigger': 'closeTrigger' )

View File

@@ -0,0 +1,12 @@
Darkswarm.factory 'Navigation', ($location) ->
new class Navigation
paths: []
path: null
navigate: (path = false)->
@path = path || @path || @paths[0]
if $location.path() == @path
$location.path("/")
else
$location.path(@path)

View File

@@ -7,9 +7,8 @@ Darkswarm.factory 'OrderCycle', ($resource, Product, orderCycleData) ->
Product.update()
@orders_close_at: ->
if @order_cycle
if @selected()
@order_cycle.orders_close_at
else
""
@selected: ->
@order_cycle != null
@order_cycle != null and !$.isEmptyObject(@order_cycle) and @order_cycle.orders_close_at != undefined

View File

@@ -2,10 +2,11 @@ Darkswarm.factory 'Product', ($resource) ->
new class Product
data: {
products: null
loading: true
}
update: ->
@data.products = $resource("/shop/products").query =>
#console.log @products
@data.loading = false
@data
all: ->
@data.products || @update()

View File

@@ -2058,7 +2058,7 @@ angular.module( 'mm.foundation.tour', [ 'mm.foundation.position', 'mm.foundation
};
}])
.directive( 'stepText', [ '$position', '$tooltip', '$tour', '$window', function ( $position, $tooltip, $tour, $window ) {
.directive( 'step', [ '$position', '$tooltip', '$tour', '$window', function ( $position, $tooltip, $tour, $window ) {
function isElementInViewport( element ) {
var rect = element[0].getBoundingClientRect();
@@ -2092,6 +2092,7 @@ angular.module( 'mm.foundation.tour', [ 'mm.foundation.position', 'mm.foundation
return $tooltip( 'step', 'step', show );
}]);
angular.module('mm.foundation.typeahead', ['mm.foundation.position', 'mm.foundation.bindHtml'])
/**
@@ -2602,7 +2603,7 @@ angular.module("template/tour/tour.html", []).run(["$templateCache", function($t
" <h4 ng-bind=\"title\" ng-show=\"title\"></h4>\n" +
" <p ng-bind=\"content\"></p>\n" +
" <a class=\"small button joyride-next-tip\" ng-show=\"!isLastStep()\" ng-click=\"nextStep()\">Next</a>\n" +
" <a class=\"small button joyride-next-tip\" ng-show=\"isLastStep()\" ng-click=\"endTour()\">End</a>\n" +
//" <a class=\"small button joyride-next-tip\" ng-show=\"isLastStep()\" ng-click=\"endTour()\">Close</a>\n" +
" <a class=\"joyride-close-tip\" ng-click=\"endTour()\">&times;</a>\n" +
" </div>\n" +
"</div>\n" +

View File

@@ -52,6 +52,11 @@ form.order_cycle {
border-bottom: 2px solid #C3D9FF;
}
.exchange-select-all-variants {
clear: both;
margin: 5px;
}
.exchange-product {
float: left;
overflow: auto;

View File

@@ -7,3 +7,4 @@
*= require foundation
*= require_tree .
*/
@import 'foundation-icons';

View File

@@ -1,6 +1,20 @@
/*body { background: #ff0000; }*/
nav.top-bar
margin-bottom: 0px
a.icon
&:hover
text-decoration: none
height: 45px
color: white
i
font-size: 29px
line-height: 45px
span
font-size: 13px
display: inline-block
line-height: 45px
height: 45px
vertical-align: top
body > section[role='main']
padding: 0px

View File

@@ -2,6 +2,8 @@
// We can't import foundation components?
// See https://github.com/zurb/foundation/issues/3855#issuecomment-30372252
@import "foundation"
@import "variables"
@import "components/global"
@import "components/buttons"
@@ -20,3 +22,12 @@
.tabs dd a
padding: 0.5em 1em
#account
dl
@include clearfix
dt, dd
display: inline-block
p > strong
display: block

View File

@@ -30,7 +30,6 @@ class Shop::CheckoutController < Spree::CheckoutController
if @order.state == "complete" || @order.completed?
flash.notice = t(:order_processed_successfully)
flash[:commerce_tracking] = "nothing special"
respond_with(@order, :location => order_path(@order))
else
clear_ship_address

View File

@@ -10,7 +10,7 @@ class Shop::ShopController < BaseController
def products
unless @products = current_order_cycle.andand
.valid_products_distributed_by(current_distributor).andand
.select { |p| p.has_stock_for_distribution?(current_order_cycle, current_distributor) }.andand
.select { |p| !p.deleted? && p.has_stock_for_distribution?(current_order_cycle, current_distributor) }.andand
.sort_by {|p| p.name }
render json: "", status: 404

View File

@@ -0,0 +1,3 @@
Spree::UsersController.class_eval do
layout 'darkswarm'
end

View File

@@ -1,4 +1,5 @@
class UserPasswordsController < Spree::UserPasswordsController
layout 'darkswarm'
def create
self.resource = resource_class.send_reset_password_instructions(params[resource_name])

View File

@@ -18,4 +18,8 @@ module SharedHelper
[]
end
end
def enterprise_user?
spree_current_user.andand.enterprises.count > 0
end
end

View File

@@ -14,5 +14,13 @@ module Spree
def alternative_available_distributors(order)
DistributionChangeValidator.new(order).available_distributors(Enterprise.all) - [order.distributor]
end
def last_completed_order
spree_current_user.orders.complete.last
end
def cart_count
current_order.andand.line_items.count || 0
end
end
end

View File

@@ -0,0 +1,8 @@
Spree::UserMailer.class_eval do
def signup_confirmation(user)
@user = user
mail(:to => user.email, :from => from_address,
:subject => 'Welcome to ' + Spree::Config[:site_name])
end
end

View File

@@ -11,7 +11,7 @@ class Exchange < ActiveRecord::Base
has_many :enterprise_fees, :through => :exchange_fees
validates_presence_of :order_cycle, :sender, :receiver
validates_uniqueness_of :sender_id, :scope => [:order_cycle_id, :receiver_id]
validates_uniqueness_of :sender_id, :scope => [:order_cycle_id, :receiver_id, :incoming]
accepts_nested_attributes_for :variants

View File

@@ -1,6 +1,6 @@
module Spree
Adjustment.class_eval do
has_one :metadata, class_name: 'AdjustmentMetadata'
has_one :metadata, class_name: 'AdjustmentMetadata', dependent: :destroy
scope :enterprise_fee, where(originator_type: 'EnterpriseFee')
end

View File

@@ -85,6 +85,7 @@ Spree::Order.class_eval do
def set_order_cycle!(order_cycle)
self.order_cycle = order_cycle
self.distributor = nil unless order_cycle.nil? || order_cycle.has_distributor?(distributor)
self.empty!
save!
end

View File

@@ -6,6 +6,7 @@ Spree.user_class.class_eval do
accepts_nested_attributes_for :enterprise_roles, :allow_destroy => true
attr_accessible :enterprise_ids, :enterprise_roles_attributes
after_create :send_signup_confirmation
def build_enterprise_roles
Enterprise.all.each do |enterprise|
@@ -14,4 +15,8 @@ Spree.user_class.class_eval do
end
end
end
def send_signup_confirmation
Spree::UserMailer.signup_confirmation(self).deliver
end
end

View File

@@ -12,6 +12,7 @@ Spree::Variant.class_eval do
if: -> v { v.product.variant_unit.present? && v.unit_value.nil? },
unless: :is_master
before_validation :update_weight_from_unit_value
after_save :update_units
scope :in_stock, where('spree_variants.count_on_hand > 0 OR spree_variants.on_demand=?', true)
@@ -43,6 +44,10 @@ Spree::Variant.class_eval do
private
def update_weight_from_unit_value
self.weight = unit_value / 1000 if self.product.variant_unit == 'weight' && unit_value.present?
end
def update_units
delete_unit_option_values

View File

@@ -155,4 +155,4 @@
.omega.four.columns
= image_tag @object.promo_image.url if @object.promo_image.present?
= f.file_field :pro_image
= f.file_field :promo_image

View File

@@ -1,10 +1,17 @@
%td{:colspan => 3}
.exchange-select-all-variants
%label
= check_box_tag 'order_cycle_outgoing_exchange_{{ $parent.$index }}_select_all_variants', 1, 1, 'ng-model' => 'exchange.select_all_variants', 'ng-click' => 'setExchangeVariants(exchange, incomingExchangesVariants(), exchange.select_all_variants)', 'id' => 'order_cycle_outgoing_exchange_{{ $parent.$index }}_select_all_variants'
Select all
.exchange-product{'ng-repeat' => 'product in supplied_products | filter:productSuppliedToOrderCycle'}
.exchange-product-details
.supplier {{ product.supplier_name }}
= check_box_tag 'order_cycle_outgoing_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}', 1, 1, 'ng-hide' => 'product.variants', 'ng-model' => 'exchange.variants[product.master_id]', 'id' => 'order_cycle_outgoing_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}'
%img{'ng-src' => '{{ product.image_url }}'}
{{ product.name }}
%label
= check_box_tag 'order_cycle_outgoing_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}', 1, 1, 'ng-hide' => 'product.variants', 'ng-disabled' => 'product.variants.length > 0', 'ng-model' => 'exchange.variants[product.master_id]', 'id' => 'order_cycle_outgoing_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}'
%img{'ng-src' => '{{ product.image_url }}'}
{{ product.name }}
.exchange-product-variant{'ng-repeat' => 'variant in product.variants | filter:variantSuppliedToOrderCycle'}
= check_box_tag 'order_cycle_outgoing_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}', 1, 1, 'ng-model' => 'exchange.variants[variant.id]', 'id' => 'order_cycle_outgoing_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}'
{{ variant.label }}
%label
= check_box_tag 'order_cycle_outgoing_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}', 1, 1, 'ng-model' => 'exchange.variants[variant.id]', 'id' => 'order_cycle_outgoing_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}'
{{ variant.label }}

View File

@@ -1,18 +1,26 @@
/ TODO: Unify this with exchange_distributed_products_form
%td{:colspan => 3}
.exchange-select-all-variants
%label
= check_box_tag 'order_cycle_incoming_exchange_{{ $parent.$index }}_select_all_variants', 1, 1, 'ng-model' => 'exchange.select_all_variants', 'ng-click' => 'setExchangeVariants(exchange, suppliedVariants(exchange.enterprise_id), exchange.select_all_variants)', 'id' => 'order_cycle_incoming_exchange_{{ $parent.$index }}_select_all_variants'
Select all
.exchange-product{'ng-repeat' => 'product in enterprises[exchange.enterprise_id].supplied_products'}
.exchange-product-details
= check_box_tag 'order_cycle_incoming_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}', 1, 1, 'ng-hide' => 'product.variants', 'ng-model' => 'exchange.variants[product.master_id]', 'ofn-sync-distributions' => '{{ product.master_id }}', 'id' => 'order_cycle_incoming_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}'
%img{'ng-src' => '{{ product.image_url }}'}
{{ product.name }}
%label
= check_box_tag 'order_cycle_incoming_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}', 1, 1, 'ng-hide' => 'product.variants', 'ng-disabled' => 'product.variants.length > 0', 'ng-model' => 'exchange.variants[product.master_id]', 'ofn-sync-distributions' => '{{ product.master_id }}', 'id' => 'order_cycle_incoming_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}'
%img{'ng-src' => '{{ product.image_url }}'}
{{ product.name }}
-# When the master variant is in the order cycle but the product has variants, we want to
-# be able to remove the master variant, since it serves no purpose. Display a checkbox to do so.
.exchange-product-variant{'ng-show' => 'exchange.variants[product.master_id] && product.variants'}
= check_box_tag 'order_cycle_incoming_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}', 1, 1, 'ng-model' => 'exchange.variants[product.master_id]', 'ofn-sync-distributions' => '{{ product.master_id }}', 'id' => 'order_cycle_incoming_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}'
Obsolete master
%label
= check_box_tag 'order_cycle_incoming_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}', 1, 1, 'ng-model' => 'exchange.variants[product.master_id]', 'ofn-sync-distributions' => '{{ product.master_id }}', 'id' => 'order_cycle_incoming_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}'
Obsolete master
.exchange-product-variant{'ng-repeat' => 'variant in product.variants'}
= check_box_tag 'order_cycle_incoming_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}', 1, 1, 'ng-model' => 'exchange.variants[variant.id]', 'ofn-sync-distributions' => '{{ variant.id }}', 'id' => 'order_cycle_incoming_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}'
{{ variant.label }}
%label
= check_box_tag 'order_cycle_incoming_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}', 1, 1, 'ng-model' => 'exchange.variants[variant.id]', 'ofn-sync-distributions' => '{{ variant.id }}', 'id' => 'order_cycle_incoming_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}'
{{ variant.label }}

View File

@@ -31,7 +31,7 @@
%h2 Coordinator
= f.label :coordinator_id, 'Coordinator'
= f.collection_select :coordinator_id, coordinating_enterprises, :id, :name, {}, {'ng-model' => 'order_cycle.coordinator_id', 'ofn-on-change' => 'order_cycle.coordinator_fees = []', 'required' => true}
= f.collection_select :coordinator_id, coordinating_enterprises, :id, :name, {include_blank: true}, {'ng-model' => 'order_cycle.coordinator_id', 'ofn-on-change' => 'order_cycle.coordinator_fees = []', 'required' => true}
= render 'coordinator_fees', f: f

View File

@@ -9,7 +9,7 @@ r.element :order_cycle, @order_cycle do
r.element :id
end
r.list_of :exchanges do |exchange|
r.list_of :exchanges, @order_cycle.exchanges.order('id ASC') do |exchange|
r.element :id
r.element :sender_id
r.element :receiver_id

View File

@@ -1,4 +1,4 @@
- if Rails.env.staging?
- if Rails.env.staging? or Rails.env.production?
:javascript
(function (d, t) {
var bh = d.createElement(t), s = d.getElementsByTagName(t)[0];
@@ -7,11 +7,12 @@
s.parentNode.insertBefore(bh, s);
})(document, 'script');
- elsif Rails.env.production?
:javascript
(function (d, t) {
var bh = d.createElement(t), s = d.getElementsByTagName(t)[0];
bh.type = 'text/javascript';
bh.src = '//www.bugherd.com/sidebarv2.js?apikey=xro3uv55objies58o2wrua';
s.parentNode.insertBefore(bh, s);
})(document, 'script');
-#- elsif Rails.env.production?
-#:javascript
-#(function (d, t) {
-#var bh = d.createElement(t), s = d.getElementsByTagName(t)[0];
-#bh.type = 'text/javascript';
-#bh.src = '//www.bugherd.com/sidebarv2.js?apikey=xro3uv55objies58o2wrua';
-#s.parentNode.insertBefore(bh, s);
-#})(document, 'script');

View File

@@ -22,6 +22,4 @@
= yield
#footer
= yield :scripts

View File

@@ -0,0 +1,20 @@
#account{"ng-controller" => "AccountSidebarCtrl"}
.row
.panel
%p
%strong= link_to "Manage my account", account_path
- if enterprise_user?
%strong= link_to "Enterprise admin", admin_path
- if order = last_completed_order
%dl
%dt Current Hub:
%dd= link_to current_distributor.name, main_app.shop_path
%br
%dt Last hub:
%dd
- if order.distributor != current_distributor
= link_to "#{order.distributor.name}".html_safe, "",
{class: distributor_link_class(order.distributor),
"ng-click" => "emptyCart('#{main_app.shop_enterprise_path(order.distributor)}', $event)"}
- else
= order.distributor.name

View File

@@ -3,8 +3,10 @@
active: "active()",
select: "select()"}
%form{"ng-submit" => "submit()"}
.alert-box.alert{"ng-show" => "errors != null"}
{{ errors }}
.row
.large-12.columns
.alert-box.alert{"ng-show" => "errors != null"}
{{ errors }}
.row
.large-12.columns
%label{for: "email"} Email

View File

@@ -1,9 +1,21 @@
%nav.top-bar
%section.top-bar-section
%ul.left{"ng-controller" => "MenuCtrl"}
%li
%a.icon{"ng-click" => "toggle()"}
%i.fi-list
%li= link_to image_tag("ofn_logo_small.png"), root_path
%li.divider
- if spree_current_user.nil?
= render 'shared/signed_out'
- else
= render 'shared/signed_in'
%section.top-bar-section
%ul.right
%li.cart
%a.icon{href: cart_url}
%i.fi-shopping-cart
%span
= cart_count
items

View File

@@ -1,7 +1,12 @@
%section#sidebar{ role: "complementary", "ng-controller" => "SidebarCtrl",
"ng-class" => "{'active' : active()}"}
%tabset
= render partial: "shared/login_sidebar"
= render partial: "shared/signup_sidebar"
= render partial: "shared/forgot_sidebar"
- if spree_current_user.nil?
%tabset
= render partial: "shared/login_sidebar"
= render partial: "shared/signup_sidebar"
= render partial: "shared/forgot_sidebar"
- else
= render partial: "shared/account_sidebar"
= yield :sidebar

View File

@@ -1,5 +1,6 @@
%li#login-link.hide= link_to "Login", "#sidebar", id: "sidebarLoginButton", class: "sidebar-button"
%li#login-name= link_to "#{spree_current_user.email}", "#"
%li#login-name
%a.sidebar-button{"ng-click" => "toggle('/account')"}
= spree_current_user.email
%li.divider
%li#sign-up-link.hide= link_to "Sign Up", "#"
%li#sign-out-link= link_to "Sign Out", "/logout"
%li#sign-out-link
= link_to "Sign Out", "/logout"

View File

@@ -1,8 +1,5 @@
%li#login-link
%a.sidebar-button{"ng-click" => "toggleLogin()"} Login
%li#login-name.hide
%a.sidebar-button{"ng-click" => "toggle('/login')"} Login
%li.divider
%li#sign-up-link
%a.sidebar-button{"ng-click" => "toggleSignup()"} Sign Up
%a.sidebar-button{"ng-click" => "toggle('/signup')"} Sign Up

View File

@@ -1,5 +1,5 @@
- for producer in current_producers
.reveal-modal{id: "producer_details_#{producer.id}"}
.reveal-modal{id: "producer_details_#{producer.id}", "data-reveal" => ""}
.row
- if producer.logo.exists?
.large-1.columns
@@ -17,10 +17,9 @@
%a.close-reveal-modal &#215;
- for group in current_distributor.groups
- for sibling in group.enterprises.except(current_distributor)
.reveal-modal{id: "sibling_details_#{sibling.id}"}
.reveal-modal{id: "sibling_details_#{sibling.id}", "data-reveal" => ""}
.row
- if sibling.logo.exists?
.large-1.columns
@@ -35,4 +34,3 @@
.large-4.columns
%img.about.right{src: sibling.promo_image.url(:large)}
%a.close-reveal-modal &#215;

View File

@@ -24,12 +24,12 @@
.large-6.columns
= ba.text_field :lastname, "ng-model" => "order.bill_address.lastname"
%fieldset
%fieldset#billing
%legend Billing Address
= f.fields_for :bill_address, @order.bill_address do |ba|
.row
.large-12.columns
= ba.text_field :address1, label: "Billing Address",
= ba.text_field :address1,
"ng-model" => "order.bill_address.address1"
.row
.large-12.columns

View File

@@ -6,5 +6,5 @@
%ul
- for sibling in group.enterprises.except(current_distributor)
%li
%a{"data-reveal-id" => "sibling_details_#{sibling.id}"}
%a{"data-reveal-id" => "sibling_details_#{sibling.id}", "data-reveal" => ""}
= sibling.name

View File

@@ -2,5 +2,5 @@
%ul
- for producer in current_producers
%li
%a{"data-reveal-id" => "producer_details_#{producer.id}"}
%a{"data-reveal-id" => "producer_details_#{producer.id}", "data-reveal" => ""}
= producer.name

View File

@@ -12,6 +12,10 @@
%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"}
%tr{"class" => "product product-{{ product.id }}"}
%td.name
@@ -19,7 +23,7 @@
%div
%h5
{{ product.name }}
%a{"data-reveal-id" => "producer_details_{{product.supplier.id}}"}
%a{"data-reveal-id" => "producer_details_{{product.supplier.id}}", "data-reveal" => ""}
{{ product.supplier.name }}
%td.notes {{ product.notes | truncate:80 }}
%td

View File

@@ -1,14 +1,16 @@
%shop.darkswarm
- content_for :order_cycle_form do
%strong.avenir Ready for
%select.avenir#order_cycle_id{"ng-model" => "order_cycle.order_cycle_id",
"ng-change" => "changeOrderCycle()",
"ng-options" => "oc.id as oc.time for oc in #{@order_cycles.map {|oc| {time: pickup_time(oc), id: oc.id}}.to_json}"}
"ng-options" => "oc.id as oc.time for oc in #{@order_cycles.map {|oc| {time: pickup_time(oc), id: oc.id}}.to_json}",
"popover-placement" => "bottom", "popover" => "testy", "popover-trigger" => "openTrigger"}
%closing
-#%img{src: "/icon/goes/here"}
%closing{"ng-if" => "OrderCycle.selected()"}
Orders close
%strong {{ OrderCycle.orders_close_at() | date_in_words }}
= render partial: "shop/details"
%products.row

View File

@@ -23,6 +23,15 @@ Payment Details
<%= @order.payments.first.andand.payment_method.andand.description.andand.html_safe %>
<% end %>
<%- if @order.shipping_method.andand.require_ship_address %>
============================================================
Shipping Details
============================================================
Your order will be shipped to:
<%= @order.ship_address.to_s %>
<% else %>
============================================================
Collection / Delivery Details
============================================================
@@ -34,9 +43,11 @@ Collection / Delivery Details
<% else %>
<%= @order.distributor.next_collection_at %>
<% end %>
<% end %>
Thanks for your support.
<%= @order.distributor.contact %>,
<%= @order.distributor.name %>
<%= @order.distributor.phone %>

View File

@@ -41,18 +41,18 @@
\:
%span.order-total.grand-total= @order.display_total
.links{'data-hook' => "cart_buttons"}
.row
#empty-cart.columns.large-9{"data-hook" => ""}
= form_tag empty_cart_path, :method => :put do
#clear_cart_link{"data-hook" => ""}
= link_to "Continue Shopping", main_app.shop_path, class: "button secondary"
= t(:or)
= submit_tag t(:empty_cart), :class => 'button secondary'
.links{'data-hook' => "cart_buttons"}
.row
#empty-cart.columns.large-8{"data-hook" => ""}
= form_tag empty_cart_path, :method => :put do
#clear_cart_link{"data-hook" => ""}
= link_to "Continue Shopping", main_app.shop_path, class: "button secondary"
= t(:or)
= submit_tag t(:empty_cart), :class => 'button secondary'
.columns.large-1
= button_tag :class => 'secondary', :id => 'update-button' do
= t(:update)
.columns.large-2
= link_to "Checkout", main_app.shop_checkout_path, class: "button checkout primary", id: "checkout-link"
.columns.large-4.text-right
= button_tag :class => 'secondary', :id => 'update-button' do
= t(:update)
= t(:or)
= link_to "Checkout", main_app.shop_checkout_path, class: "button checkout primary", id: "checkout-link"

View File

@@ -0,0 +1,13 @@
Hello,
Welcome to Australia's Open Food Network! Your login email is <%= @user.email %>
You can go online and start shopping through food hubs and local producers you like at vic.openfoodnetwork.org.au
We welcome all your questions and feedback; you can use the Send Feedback button on the site or email us at hello@openfoodnetwork.org
Thanks for getting on board and we look forward to introducing you to many more great farmers, food hubs and food!
Cheers,
Kirsten Larsen and the OFN Team

View File

@@ -0,0 +1,8 @@
.darkswarm
.row
= render :partial => 'spree/shared/error_messages', :locals => { :target => @user }
%h1= t(:editing_user)
= form_for Spree::User.new, :as => @user, :url => spree.user_path(@user), :method => :put do |f|
= render :partial => 'spree/shared/user_form', :locals => { :f => f }
%p
= f.submit t(:update), :class => 'button primary'

View File

@@ -0,0 +1,33 @@
.darkswarm
.row
%h1= accurate_title
.account-summary{"data-hook" => "account_summary"}
%dl#user-info
%dt= t(:email)
%dd
= @user.email
(#{link_to t(:edit), spree.edit_account_path})
.account-my-orders{"data-hook" => "account_my_orders"}
%h3= t(:my_orders)
- if @orders.present?
%table.order-summary
%thead
%tr
%th.order-number= t(:order_number)
%th.order-date= t(:order_date)
%th.order-status= t(:status)
%th.order-payment-state= t(:payment_state)
%th.order-shipment-state= t(:shipment_state)
%th.order-total= t(:total)
%tbody
- @orders.each do |order|
%tr{class: cycle('even', 'odd')}
%td.order-number= link_to order.number, order_url(order)
%td.order-date= l order.completed_at.to_date
%td.order-status= t(order.state).titleize
%td.order-payment-state= t("payment_states.#{order.payment_state}") if order.payment_state
%td.order-shipment-state= t("shipment_states.#{order.shipment_state}") if order.shipment_state
%td.order-total= money order.total
- else
%p= t(:you_have_no_orders_yet)
%br/

View File

@@ -0,0 +1,16 @@
= f_form_for @spree_user, :as => :spree_user, :url => spree.spree_user_password_path, :method => :put do |f|
= render :partial => 'spree/shared/error_messages', :locals => { :target => @spree_user }
%fieldset
.row
.small-12.medium-6.large-4.columns.medium-centered.large-centered
%legend= t(:change_my_password)
.row
.small-12.medium-6.large-4.columns.medium-centered.large-centered
= f.password_field :password
.row
.small-12.medium-6.large-4.columns.medium-centered.large-centered
= f.password_field :password_confirmation
= f.hidden_field :reset_password_token
.row
.small-10.medium-6.large-4.columns.small-centered
= f.submit t(:update_password), :class => 'button primary'

View File

@@ -0,0 +1,38 @@
class AddMissingIndexes < ActiveRecord::Migration
def change
add_index :adjustment_metadata, :enterprise_id
add_index :carts, :user_id
add_index :coordinator_fees, :order_cycle_id
add_index :coordinator_fees, :enterprise_fee_id
add_index :distributors_payment_methods, :distributor_id
add_index :distributors_payment_methods, :payment_method_id
add_index :enterprise_fees, :enterprise_id
add_index :enterprise_groups_enterprises, :enterprise_group_id
add_index :enterprise_groups_enterprises, :enterprise_id
add_index :enterprise_roles, :user_id
add_index :enterprise_roles, :enterprise_id
add_index :enterprises, :address_id
add_index :exchange_fees, :exchange_id
add_index :exchange_fees, :enterprise_fee_id
add_index :exchange_variants, :exchange_id
add_index :exchange_variants, :variant_id
add_index :exchanges, :order_cycle_id
add_index :exchanges, :sender_id
add_index :exchanges, :receiver_id
add_index :exchanges, :payment_enterprise_id
add_index :product_distributions, :product_id
add_index :product_distributions, :distributor_id
add_index :product_distributions, :enterprise_fee_id
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 => 20140324025840) do
ActiveRecord::Schema.define(:version => 20140402032034) do
create_table "adjustment_metadata", :force => true do |t|
t.integer "adjustment_id"
@@ -22,11 +22,14 @@ ActiveRecord::Schema.define(:version => 20140324025840) do
end
add_index "adjustment_metadata", ["adjustment_id"], :name => "index_adjustment_metadata_on_adjustment_id"
add_index "adjustment_metadata", ["enterprise_id"], :name => "index_adjustment_metadata_on_enterprise_id"
create_table "carts", :force => true do |t|
t.integer "user_id"
end
add_index "carts", ["user_id"], :name => "index_carts_on_user_id"
create_table "cms_blocks", :force => true do |t|
t.integer "page_id", :null => false
t.string "identifier", :null => false
@@ -149,11 +152,17 @@ ActiveRecord::Schema.define(:version => 20140324025840) do
t.integer "enterprise_fee_id"
end
add_index "coordinator_fees", ["enterprise_fee_id"], :name => "index_coordinator_fees_on_enterprise_fee_id"
add_index "coordinator_fees", ["order_cycle_id"], :name => "index_coordinator_fees_on_order_cycle_id"
create_table "distributors_payment_methods", :id => false, :force => true do |t|
t.integer "distributor_id"
t.integer "payment_method_id"
end
add_index "distributors_payment_methods", ["distributor_id"], :name => "index_distributors_payment_methods_on_distributor_id"
add_index "distributors_payment_methods", ["payment_method_id"], :name => "index_distributors_payment_methods_on_payment_method_id"
create_table "distributors_shipping_methods", :id => false, :force => true do |t|
t.integer "distributor_id"
t.integer "shipping_method_id"
@@ -170,6 +179,8 @@ ActiveRecord::Schema.define(:version => 20140324025840) do
t.datetime "updated_at", :null => false
end
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"
@@ -181,11 +192,17 @@ ActiveRecord::Schema.define(:version => 20140324025840) do
t.integer "enterprise_id"
end
add_index "enterprise_groups_enterprises", ["enterprise_group_id"], :name => "index_enterprise_groups_enterprises_on_enterprise_group_id"
add_index "enterprise_groups_enterprises", ["enterprise_id"], :name => "index_enterprise_groups_enterprises_on_enterprise_id"
create_table "enterprise_roles", :force => true do |t|
t.integer "user_id"
t.integer "enterprise_id"
end
add_index "enterprise_roles", ["enterprise_id"], :name => "index_enterprise_roles_on_enterprise_id"
add_index "enterprise_roles", ["user_id"], :name => "index_enterprise_roles_on_user_id"
create_table "enterprises", :force => true do |t|
t.string "name"
t.string "description"
@@ -215,6 +232,8 @@ ActiveRecord::Schema.define(:version => 20140324025840) do
t.datetime "promo_image_updated_at"
end
add_index "enterprises", ["address_id"], :name => "index_enterprises_on_address_id"
create_table "exchange_fees", :force => true do |t|
t.integer "exchange_id"
t.integer "enterprise_fee_id"
@@ -222,6 +241,9 @@ ActiveRecord::Schema.define(:version => 20140324025840) do
t.datetime "updated_at", :null => false
end
add_index "exchange_fees", ["enterprise_fee_id"], :name => "index_exchange_fees_on_enterprise_fee_id"
add_index "exchange_fees", ["exchange_id"], :name => "index_exchange_fees_on_exchange_id"
create_table "exchange_variants", :force => true do |t|
t.integer "exchange_id"
t.integer "variant_id"
@@ -229,6 +251,9 @@ ActiveRecord::Schema.define(:version => 20140324025840) do
t.datetime "updated_at", :null => false
end
add_index "exchange_variants", ["exchange_id"], :name => "index_exchange_variants_on_exchange_id"
add_index "exchange_variants", ["variant_id"], :name => "index_exchange_variants_on_variant_id"
create_table "exchanges", :force => true do |t|
t.integer "order_cycle_id"
t.integer "sender_id"
@@ -241,6 +266,11 @@ ActiveRecord::Schema.define(:version => 20140324025840) do
t.boolean "incoming", :default => false, :null => false
end
add_index "exchanges", ["order_cycle_id"], :name => "index_exchanges_on_order_cycle_id"
add_index "exchanges", ["payment_enterprise_id"], :name => "index_exchanges_on_payment_enterprise_id"
add_index "exchanges", ["receiver_id"], :name => "index_exchanges_on_receiver_id"
add_index "exchanges", ["sender_id"], :name => "index_exchanges_on_sender_id"
create_table "landing_page_images", :force => true do |t|
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
@@ -267,6 +297,10 @@ ActiveRecord::Schema.define(:version => 20140324025840) do
t.integer "enterprise_fee_id"
end
add_index "product_distributions", ["distributor_id"], :name => "index_product_distributions_on_distributor_id"
add_index "product_distributions", ["enterprise_fee_id"], :name => "index_product_distributions_on_enterprise_fee_id"
add_index "product_distributions", ["product_id"], :name => "index_product_distributions_on_product_id"
create_table "spree_activators", :force => true do |t|
t.string "description"
t.datetime "expires_at"

View File

@@ -2,6 +2,7 @@ require 'spec_helper'
require 'spree/api/testing_support/helpers'
describe UserPasswordsController do
let(:user) { create(:user) }
before do
@request.env["devise.mapping"] = Devise.mappings[:spree_user]
@@ -15,11 +16,16 @@ describe UserPasswordsController do
end
it "redirects to login when data is valid" do
user = create(:user)
spree_post :create, spree_user: { email: user.email}
response.should be_redirect
end
it "renders Darkswarm" do
user.send_reset_password_instructions
spree_get :edit, reset_password_token: user.reset_password_token
response.should render_template "user_passwords/edit"
end
describe "via ajax" do
it "returns errors" do
xhr :post, :create, spree_user: {}, use_route: :spree

View File

@@ -141,9 +141,9 @@ feature %q{
page.should have_selector 'td.distributors', text: 'My distributor'
# And it should have some fees
OrderCycle.last.exchanges.first.enterprise_fees.should == [supplier_fee]
OrderCycle.last.coordinator_fees.should == [coordinator_fee]
OrderCycle.last.exchanges.last.enterprise_fees.should == [distributor_fee]
OrderCycle.last.exchanges.incoming.first.enterprise_fees.should == [supplier_fee]
OrderCycle.last.coordinator_fees.should == [coordinator_fee]
OrderCycle.last.exchanges.outgoing.first.enterprise_fees.should == [distributor_fee]
# And it should have some variants selected
OrderCycle.last.exchanges.first.variants.count.should == 2

View File

@@ -58,7 +58,6 @@ feature "enterprises distributor info as rich text" do
end
scenario "viewing distributor info with product distribution", js: true do
ActionMailer::Base.deliveries.clear
d = create(:distributor_enterprise, distributor_info: 'Chu ge sai yubi dan <strong>bisento</strong> tobi ashi yubi ge omote.', next_collection_at: 'Thursday 2nd May')
p = create(:product, :distributors => [d])
@@ -67,6 +66,7 @@ feature "enterprises distributor info as rich text" do
login_to_consumer_section
visit spree.select_distributor_order_path(d)
ActionMailer::Base.deliveries.clear
# -- Product details page
visit spree.product_path p
@@ -110,6 +110,7 @@ feature "enterprises distributor info as rich text" do
setup_shipping_details d
login_to_consumer_section
ActionMailer::Base.deliveries.clear
click_link 'Green Grass'
visit enterprise_path d
@@ -146,7 +147,7 @@ feature "enterprises distributor info as rich text" do
zone = create(:zone)
c = Spree::Country.find_by_name('Australia')
Spree::ZoneMember.create(:zoneable => c, :zone => zone)
create(:shipping_method, zone: zone)
create(:shipping_method, zone: zone, require_ship_address: false)
create(:payment_method, :description => 'Cheque payment method', distributors: [distributor])
end

View File

@@ -3,16 +3,16 @@ require 'spec_helper'
feature "As a consumer I want to check out my cart", js: true do
include AuthenticationWorkflow
include WebHelper
include ShopWorkflow
let(:distributor) { create(:distributor_enterprise) }
let(:supplier) { create(:supplier_enterprise) }
let(:order_cycle) { create(:order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise)) }
let(:product) { create(:simple_product, supplier: supplier) }
let(:order) { Spree::Order.last }
before do
create_enterprise_group_for distributor
exchange = Exchange.find(order_cycle.exchanges.to_enterprises(distributor).outgoing.first.id)
exchange.variants << product.master
end
describe "Login behaviour" do

View File

@@ -3,17 +3,17 @@ require 'spec_helper'
feature "As a consumer I want to check out my cart", js: true do
include AuthenticationWorkflow
include ShopWorkflow
include WebHelper
let(:distributor) { create(:distributor_enterprise) }
let(:supplier) { create(:supplier_enterprise) }
let(:order_cycle) { create(:order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise)) }
let(:product) { create(:simple_product, supplier: supplier) }
let(:order) { Spree::Order.last }
before do
create_enterprise_group_for distributor
exchange = Exchange.find(order_cycle.exchanges.to_enterprises(distributor).outgoing.first.id)
exchange.variants << product.master
end
describe "Attempting to access checkout without meeting the preconditions" do
it "redirects to the homepage if no distributor is selected" do

View File

@@ -3,19 +3,20 @@ require 'spec_helper'
feature "As a consumer I want to check out my cart", js: true do
include AuthenticationWorkflow
include ShopWorkflow
include WebHelper
let(:distributor) { create(:distributor_enterprise) }
let(:supplier) { create(:supplier_enterprise) }
let(:order_cycle) { create(:order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise)) }
let(:product) { create(:simple_product, supplier: supplier) }
let(:order) { Spree::Order.last }
before do
create_enterprise_group_for distributor
exchange = Exchange.find(order_cycle.exchanges.to_enterprises(distributor).outgoing.first.id)
exchange.variants << product.master
end
# Disabled :in for performance reasons
[:out].each do |auth_state|
describe "logged #{auth_state.to_s}, distributor selected, order cycle selected, product in cart" do
let(:user) { create_enterprise_user }
@@ -36,12 +37,9 @@ feature "As a consumer I want to check out my cart", js: true do
distributor.shipping_methods << sm2
visit "/shop/checkout"
end
it "shows all shipping methods" do
it "shows all shipping methods, but doesn't show ship address when not needed" do
page.should have_content "Frogs"
page.should have_content "Donkeys"
end
it "doesn't show ship address forms when a shipping method wants no address" do
choose(sm2.name)
find("#ship_address", visible: false).visible?.should be_false
end
@@ -74,7 +72,9 @@ feature "As a consumer I want to check out my cart", js: true do
it "copies billing address to hidden shipping address fields" do
choose(sm1.name)
check "Shipping address same as billing address?"
fill_in "Billing Address", with: "testy"
within "#billing" do
fill_in "Address", with: "testy"
end
within "#ship_address_hidden" do
find("#order_ship_address_attributes_address1", visible: false).value.should == "testy"
end
@@ -112,7 +112,7 @@ feature "As a consumer I want to check out my cart", js: true do
within "#details" do
fill_in "First Name", with: "Will"
fill_in "Last Name", with: "Marshall"
fill_in "Billing Address", with: "123 Your Face"
fill_in "Address", with: "123 Your Face"
select "Australia", from: "Country"
select "Victoria", from: "State"
fill_in "Customer E-Mail", with: "test@test.com"
@@ -130,7 +130,7 @@ feature "As a consumer I want to check out my cart", js: true do
within "#details" do
fill_in "First Name", with: "Will"
fill_in "Last Name", with: "Marshall"
fill_in "Billing Address", with: "123 Your Face"
fill_in "Address", with: "123 Your Face"
select "Australia", from: "Country"
select "Victoria", from: "State"
fill_in "Customer E-Mail", with: "test@test.com"
@@ -149,19 +149,3 @@ feature "As a consumer I want to check out my cart", js: true do
end
end
def select_distributor
visit "/"
click_link distributor.name
end
def select_order_cycle
exchange = Exchange.find(order_cycle.exchanges.to_enterprises(distributor).outgoing.first.id)
visit "/shop"
select exchange.pickup_time, from: "order_cycle_id"
end
def add_product_to_cart
fill_in "variants[#{product.master.id}]", with: product.master.on_hand - 1
first("form.custom > input.button.right").click
end

View File

@@ -13,13 +13,10 @@ feature "As a consumer I want to shop with a distributor", js: true do
click_link distributor.name
end
it "shows a distributor" do
it "shows a distributor with images" do
visit shop_path
page.should have_text distributor.name
end
it "shows distributor images" do
visit shop_path
find("#tab_about a").click
first("distributor img")['src'].should == distributor.logo.url(:thumb)
first("#about img")['src'].should == distributor.promo_image.url(:large)
@@ -43,32 +40,27 @@ feature "As a consumer I want to shop with a distributor", js: true do
end
describe "selecting an order cycle" do
let(:oc1) {create(:simple_order_cycle, distributors: [distributor], orders_close_at: 2.days.from_now)}
let(:oc2) {create(:simple_order_cycle, distributors: [distributor], orders_close_at: 3.days.from_now)}
let(:exchange1) { Exchange.find(oc1.exchanges.to_enterprises(distributor).outgoing.first.id) }
let(:exchange2) { Exchange.find(oc2.exchanges.to_enterprises(distributor).outgoing.first.id) }
it "selects an order cycle if only one is open" do
# create order cycle
oc1 = create(:simple_order_cycle, distributors: [distributor])
exchange = Exchange.find(oc1.exchanges.to_enterprises(distributor).outgoing.first.id)
exchange.update_attribute :pickup_time, "turtles"
exchange1.update_attribute :pickup_time, "turtles"
visit shop_path
page.should have_selector "option[selected]", text: 'turtles'
end
describe "with multiple order cycles" do
let(:oc1) {create(:simple_order_cycle, distributors: [distributor], orders_close_at: 2.days.from_now)}
let(:oc2) {create(:simple_order_cycle, distributors: [distributor], orders_close_at: 3.days.from_now)}
before do
exchange = Exchange.find(oc1.exchanges.to_enterprises(distributor).outgoing.first.id)
exchange.update_attribute :pickup_time, "frogs"
exchange = Exchange.find(oc2.exchanges.to_enterprises(distributor).outgoing.first.id)
exchange.update_attribute :pickup_time, "turtles"
exchange1.update_attribute :pickup_time, "frogs"
exchange2.update_attribute :pickup_time, "turtles"
visit shop_path
end
it "shows a select with all order cycles" do
it "shows a select with all order cycles, but doesn't show the products by default" do
page.should have_selector "option", text: 'frogs'
page.should have_selector "option", text: 'turtles'
end
it "doesn't show the table before an order cycle is selected" do
page.should_not have_selector("input.button.right", visible: true)
end
@@ -80,33 +72,20 @@ feature "As a consumer I want to shop with a distributor", js: true do
describe "with products in our order cycle" do
let(:product) { create(:simple_product) }
before do
exchange = Exchange.find(oc1.exchanges.to_enterprises(distributor).outgoing.first.id)
exchange.variants << product.master
exchange1.variants << product.master
visit shop_path
end
it "allows us to select an order cycle" do
select "frogs", :from => "order_cycle_id"
it "allows us to select an order cycle, thus showing products" do
page.should_not have_content product.name
Spree::Order.last.order_cycle.should == nil
select "frogs", :from => "order_cycle_id"
page.should have_selector "products"
page.should have_content "Orders close 2 days from now"
Spree::Order.last.order_cycle.should == oc1
end
it "doesn't show products before an order cycle is selected" do
page.should_not have_content product.name
end
it "shows products when an order cycle has been selected" do
select "frogs", :from => "order_cycle_id"
page.should have_content product.name
end
it "updates the orders close note when order cycle is changed" do
oc1.stub(:orders_close_at).and_return 3.days.from_now
select "turtles", :from => "order_cycle_id"
page.should have_content "Orders close 3 days from now"
end
end
end
@@ -164,13 +143,14 @@ feature "As a consumer I want to shop with a distributor", js: true do
end
end
describe "filtering on hand and on demand products" do
describe "filtering products" do
let(:oc) { create(:simple_order_cycle, distributors: [distributor]) }
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(: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) }
@@ -183,6 +163,8 @@ feature "As a consumer I want to shop with a distributor", js: true do
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
v1.update_attribute(:count_on_hand, 1)
v2.update_attribute(:count_on_hand, 0)
v3.update_attribute(:count_on_hand, 0)
@@ -193,6 +175,7 @@ feature "As a consumer I want to shop with a distributor", js: true do
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
@@ -224,6 +207,9 @@ feature "As a consumer I want to shop with a distributor", js: true do
# 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
end
end

View File

@@ -0,0 +1,16 @@
describe 'Navigation service', ->
Navigation = null
beforeEach ->
module 'Darkswarm'
inject ($injector)->
Navigation = $injector.get("Navigation")
it "caches the path provided", ->
Navigation.navigate "/foo"
expect(Navigation.path).toEqual "/foo"
it "defaults to the first path in the list", ->
Navigation.paths = ["/test", "/bar"]
Navigation.navigate()
expect(Navigation.path).toEqual "/test"

View File

@@ -19,6 +19,7 @@ describe 'OrderCycle controllers', ->
variantSuppliedToOrderCycle: jasmine.createSpy('variantSuppliedToOrderCycle').andReturn('variant supplied')
exchangeDirection: jasmine.createSpy('exchangeDirection').andReturn('exchange direction')
toggleProducts: jasmine.createSpy('toggleProducts')
setExchangeVariants: jasmine.createSpy('setExchangeVariants')
addSupplier: jasmine.createSpy('addSupplier')
addDistributor: jasmine.createSpy('addDistributor')
removeExchange: jasmine.createSpy('removeExchange')
@@ -31,6 +32,7 @@ describe 'OrderCycle controllers', ->
Enterprise =
index: jasmine.createSpy('index').andReturn('enterprises list')
supplied_products: 'supplied products'
suppliedVariants: jasmine.createSpy('suppliedVariants').andReturn('supplied variants')
totalVariants: jasmine.createSpy('totalVariants').andReturn('variants total')
EnterpriseFee =
index: jasmine.createSpy('index').andReturn('enterprise fees list')
@@ -63,10 +65,18 @@ describe 'OrderCycle controllers', ->
EnterpriseFee.loaded = false
expect(scope.loaded()).toBe(false)
it "delegates suppliedVariants to Enterprise", ->
expect(scope.suppliedVariants('enterprise_id')).toEqual('supplied variants')
expect(Enterprise.suppliedVariants).toHaveBeenCalledWith('enterprise_id')
it 'Delegates exchangeSelectedVariants to OrderCycle', ->
expect(scope.exchangeSelectedVariants('exchange')).toEqual('variants selected')
expect(OrderCycle.exchangeSelectedVariants).toHaveBeenCalledWith('exchange')
it "delegates setExchangeVariants to OrderCycle", ->
scope.setExchangeVariants('exchange', 'variants', 'selected')
expect(OrderCycle.setExchangeVariants).toHaveBeenCalledWith('exchange', 'variants', 'selected')
it 'Delegates enterpriseTotalVariants to Enterprise', ->
expect(scope.enterpriseTotalVariants('enterprise')).toEqual('variants total')
expect(Enterprise.totalVariants).toHaveBeenCalledWith('enterprise')
@@ -169,6 +179,7 @@ describe 'OrderCycle controllers', ->
variantSuppliedToOrderCycle: jasmine.createSpy('variantSuppliedToOrderCycle').andReturn('variant supplied')
exchangeDirection: jasmine.createSpy('exchangeDirection').andReturn('exchange direction')
toggleProducts: jasmine.createSpy('toggleProducts')
setExchangeVariants: jasmine.createSpy('setExchangeVariants')
addSupplier: jasmine.createSpy('addSupplier')
addDistributor: jasmine.createSpy('addDistributor')
removeExchange: jasmine.createSpy('removeExchange')
@@ -181,6 +192,7 @@ describe 'OrderCycle controllers', ->
Enterprise =
index: jasmine.createSpy('index').andReturn('enterprises list')
supplied_products: 'supplied products'
suppliedVariants: jasmine.createSpy('suppliedVariants').andReturn('supplied variants')
totalVariants: jasmine.createSpy('totalVariants').andReturn('variants total')
EnterpriseFee =
index: jasmine.createSpy('index').andReturn('enterprise fees list')
@@ -213,10 +225,18 @@ describe 'OrderCycle controllers', ->
OrderCycle.loaded = false
expect(scope.loaded()).toBe(false)
it "delegates suppliedVariants to Enterprise", ->
expect(scope.suppliedVariants('enterprise_id')).toEqual('supplied variants')
expect(Enterprise.suppliedVariants).toHaveBeenCalledWith('enterprise_id')
it 'Delegates exchangeSelectedVariants to OrderCycle', ->
expect(scope.exchangeSelectedVariants('exchange')).toEqual('variants selected')
expect(OrderCycle.exchangeSelectedVariants).toHaveBeenCalledWith('exchange')
it "delegates setExchangeVariants to OrderCycle", ->
scope.setExchangeVariants('exchange', 'variants', 'selected')
expect(OrderCycle.setExchangeVariants).toHaveBeenCalledWith('exchange', 'variants', 'selected')
it 'Delegates totalVariants to Enterprise', ->
expect(scope.enterpriseTotalVariants('enterprise')).toEqual('variants total')
expect(Enterprise.totalVariants).toHaveBeenCalledWith('enterprise')
@@ -332,6 +352,25 @@ describe 'OrderCycle services', ->
$httpBackend.flush()
expect(Enterprise.supplied_products).toEqual [1, 2, 3, 4, 5, 6]
it "finds supplied variants for an enterprise", ->
spyOn(Enterprise, 'variantsOf').andReturn(10)
Enterprise.index()
$httpBackend.flush()
expect(Enterprise.suppliedVariants(1)).toEqual [10, 10]
describe "finding the variants of a product", ->
it "returns the master for products without variants", ->
p =
master_id: 1
variants: []
expect(Enterprise.variantsOf(p)).toEqual [1]
it "returns the variant ids for products with variants", ->
p =
master_id: 1
variants: [{id: 2}, {id: 3}]
expect(Enterprise.variantsOf(p)).toEqual [2, 3]
it 'counts total variants supplied by an enterprise', ->
enterprise =
supplied_products: [
@@ -450,6 +489,12 @@ describe 'OrderCycle services', ->
OrderCycle.toggleProducts(exchange)
expect(exchange.showProducts).toEqual(true)
describe "setting exchange variants", ->
it "sets all variants to the provided value", ->
exchange = {variants: {2: false}}
OrderCycle.setExchangeVariants(exchange, [1, 2, 3], true)
expect(exchange.variants).toEqual {1: true, 2: true, 3: true}
describe 'adding suppliers', ->
exchange = null
@@ -725,35 +770,62 @@ describe 'OrderCycle services', ->
]
it 'converts coordinator fees into a list of ids', ->
data =
order_cycle =
coordinator_fees: [
{id: 1}
{id: 2}
]
data = OrderCycle.translateCoordinatorFees(data)
data = OrderCycle.translateCoordinatorFees(order_cycle)
expect(data.coordinator_fees).toBeUndefined()
expect(data.coordinator_fee_ids).toEqual [1, 2]
it 'converts exchange fees into a list of ids', ->
data =
incoming_exchanges: [
enterprise_fees: [
{id: 1}
{id: 2}
it "preserves original data when converting coordinator fees", ->
OrderCycle.order_cycle =
coordinator_fees: [
{id: 1}
{id: 2}
]
]
outgoing_exchanges: [
enterprise_fees: [
{id: 3}
{id: 4}
data = OrderCycle.deepCopy()
data = OrderCycle.translateCoordinatorFees(data)
expect(OrderCycle.order_cycle.coordinator_fees).toEqual [{id: 1}, {id: 2}]
expect(OrderCycle.order_cycle.coordinator_fee_ids).toBeUndefined()
describe "converting exchange fees into a list of ids", ->
order_cycle = null
data = null
beforeEach ->
order_cycle =
incoming_exchanges: [
enterprise_fees: [
{id: 1}
{id: 2}
]
]
]
outgoing_exchanges: [
enterprise_fees: [
{id: 3}
{id: 4}
]
]
OrderCycle.order_cycle = order_cycle
data = OrderCycle.translateExchangeFees(data)
data = OrderCycle.deepCopy()
data = OrderCycle.translateExchangeFees(data)
expect(data.incoming_exchanges[0].enterprise_fees).toBeUndefined()
expect(data.outgoing_exchanges[0].enterprise_fees).toBeUndefined()
expect(data.incoming_exchanges[0].enterprise_fee_ids).toEqual [1, 2]
expect(data.outgoing_exchanges[0].enterprise_fee_ids).toEqual [3, 4]
it 'converts exchange fees into a list of ids', ->
expect(data.incoming_exchanges[0].enterprise_fees).toBeUndefined()
expect(data.outgoing_exchanges[0].enterprise_fees).toBeUndefined()
expect(data.incoming_exchanges[0].enterprise_fee_ids).toEqual [1, 2]
expect(data.outgoing_exchanges[0].enterprise_fee_ids).toEqual [3, 4]
it "preserves original data when converting exchange fees", ->
expect(order_cycle.incoming_exchanges[0].enterprise_fees).toEqual [{id: 1}, {id: 2}]
expect(order_cycle.outgoing_exchanges[0].enterprise_fees).toEqual [{id: 3}, {id: 4}]
expect(order_cycle.incoming_exchanges[0].enterprise_fee_ids).toBeUndefined()
expect(order_cycle.outgoing_exchanges[0].enterprise_fee_ids).toBeUndefined()

View File

@@ -17,6 +17,7 @@ describe Spree::OrderMailer do
product_distribution = create(:product_distribution, :product => product, :distributor => @distributor)
@shipping_instructions = "pick up on thursday please!"
@order1 = create(:order, :distributor => @distributor, :bill_address => @bill_address, :special_instructions => @shipping_instructions)
ActionMailer::Base.deliveries = []
end
it "should send an email when given an order" do

View File

@@ -0,0 +1,20 @@
require 'spec_helper'
describe Spree::UserMailer do
let(:user) { build(:user) }
after do
ActionMailer::Base.deliveries.clear
end
before do
ActionMailer::Base.delivery_method = :test
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.deliveries = []
end
it "sends an email when given a user" do
Spree::UserMailer.signup_confirmation(user).deliver
ActionMailer::Base.deliveries.count.should == 1
end
end

View File

@@ -13,13 +13,17 @@ describe Exchange do
end
end
it "should not be valid when sender and receiver pair are not unique for its order cycle" do
it "should not be valid when (sender, receiver, direction) set are not unique for its order cycle" do
e1 = create(:exchange)
e2 = build(:exchange,
:order_cycle => e1.order_cycle, :sender => e1.sender, :receiver => e1.receiver)
:order_cycle => e1.order_cycle, :sender => e1.sender, :receiver => e1.receiver, :incoming => e1.incoming)
e2.should_not be_valid
e2.incoming = !e2.incoming
e2.should be_valid
e2.incoming = !e2.incoming
e2.receiver = create(:enterprise)
e2.should be_valid

View File

@@ -181,14 +181,19 @@ describe Spree::Order do
end
describe "setting the order cycle" do
let(:oc) { create(:simple_order_cycle) }
it "empties the cart when changing the order cycle" do
subject.should_receive(:empty!)
subject.set_order_cycle! oc
end
it "sets the order cycle when no distributor is set" do
oc = create(:simple_order_cycle)
subject.set_order_cycle! oc
subject.order_cycle.should == oc
end
it "keeps the distributor when it is available in the new order cycle" do
oc = create(:simple_order_cycle)
d = create(:distributor_enterprise)
create(:exchange, order_cycle: oc, sender: oc.coordinator, receiver: d, incoming: false)
@@ -200,7 +205,6 @@ describe Spree::Order do
end
it "clears the distributor if it is not available at that order cycle" do
oc = create(:simple_order_cycle)
d = create(:distributor_enterprise)
subject.distributor = d
@@ -211,7 +215,6 @@ describe Spree::Order do
end
it "clears the order cycle when setting to nil" do
oc = create(:simple_order_cycle)
d = create(:distributor_enterprise)
subject.set_order_cycle! oc
subject.distributor = d

View File

@@ -0,0 +1,9 @@
describe Spree.user_class do
context "#create" do
it "should send a signup email" do
Spree::UserMailer.should_receive(:signup_confirmation).and_return(double(:deliver => true))
create(:user)
end
end
end

View File

@@ -115,6 +115,41 @@ module Spree
end
describe "unit value/description" do
describe "setting the variant's weight from the unit value" do
it "sets the variant's weight when unit is weight" do
p = create(:simple_product, variant_unit: nil, variant_unit_scale: nil)
v = create(:variant, product: p, weight: nil)
p.update_attributes! variant_unit: 'weight', variant_unit_scale: 1
v.update_attributes! unit_value: 10, unit_description: 'foo'
v.reload.weight.should == 0.01
end
it "does nothing when unit is not weight" do
p = create(:simple_product, variant_unit: nil, variant_unit_scale: nil)
v = create(:variant, product: p, weight: 123)
p.update_attributes! variant_unit: 'volume', variant_unit_scale: 1
v.update_attributes! unit_value: 10, unit_description: 'foo'
v.reload.weight.should == 123
end
it "does nothing when unit_value is not set" do
p = create(:simple_product, variant_unit: nil, variant_unit_scale: nil)
v = create(:variant, product: p, weight: 123)
p.update_attributes! variant_unit: 'weight', variant_unit_scale: 1
# Although invalid, this calls the before_validation callback, which would
# error if not handling unit_value == nil case
v.update_attributes(unit_value: nil, unit_description: 'foo').should be_false
v.reload.weight.should == 123
end
end
context "when the variant initially has no value" do
context "when the required option value does not exist" do
let!(:p) { create(:simple_product, variant_unit: nil, variant_unit_scale: nil) }

View File

@@ -0,0 +1,19 @@
module ShopWorkflow
def select_distributor
# If no order cycles are available this is much faster
visit "/"
click_link distributor.name
end
# These methods are naughty and write to the DB directly
# Because loading the whole Angular app is slow
def select_order_cycle
exchange = Exchange.find(order_cycle.exchanges.to_enterprises(distributor).outgoing.first.id)
exchange.variants << product.master
order.update_attribute :order_cycle, order_cycle
end
def add_product_to_cart
create(:line_item, variant: product.master, order: order)
end
end