mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-01 02:03:22 +00:00
Merge branch 'master' into bom
This commit is contained in:
BIN
app/assets/images/noimage/large.png
Normal file
BIN
app/assets/images/noimage/large.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
BIN
app/assets/images/noimage/mini.png
Normal file
BIN
app/assets/images/noimage/mini.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
BIN
app/assets/images/noimage/product.png
Normal file
BIN
app/assets/images/noimage/product.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
BIN
app/assets/images/noimage/small.png
Normal file
BIN
app/assets/images/noimage/small.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
@@ -379,7 +379,11 @@ productEditModule.controller "AdminProductEditCtrl", [
|
||||
else
|
||||
product.variant_unit = product.variant_unit_with_scale
|
||||
product.variant_unit_scale = null
|
||||
else
|
||||
product.variant_unit = product.variant_unit_scale = null
|
||||
|
||||
$scope.packVariant product, product.master if product.master
|
||||
|
||||
if product.variants
|
||||
for id, variant of product.variants
|
||||
$scope.packVariant product, variant
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
#
|
||||
#= require ../shared/jquery.timeago
|
||||
#= require foundation
|
||||
#= require ./shop
|
||||
#= require ./darkswarm
|
||||
#= require_tree .
|
||||
|
||||
$ ->
|
||||
$(document).foundation()
|
||||
$(document).foundation('reveal', {animation: 'fade'})
|
||||
|
||||
20
app/assets/javascripts/darkswarm/cart.js.coffee
Normal file
20
app/assets/javascripts/darkswarm/cart.js.coffee
Normal file
@@ -0,0 +1,20 @@
|
||||
$ ->
|
||||
if ($ 'form#update-cart').is('*')
|
||||
($ 'form#update-cart a.delete').show().one 'click', ->
|
||||
($ this).parents('.line-item').first().find('input.line_item_quantity').val 0
|
||||
($ this).parents('form').first().submit()
|
||||
false
|
||||
|
||||
($ 'form#update-cart').submit ->
|
||||
($ 'form#update-cart #update-button').attr('disabled', true)
|
||||
|
||||
|
||||
# Temporarily handles the cart showing stuff
|
||||
$(document).ready ->
|
||||
$('#cart_adjustments').hide()
|
||||
|
||||
$('th.cart-adjustment-header').html('<a href="#">Distribution...</a>')
|
||||
$('th.cart-adjustment-header a').click ->
|
||||
$('#cart_adjustments').toggle()
|
||||
$('th.cart-adjustment-header a').html('Distribution')
|
||||
false
|
||||
@@ -1,2 +0,0 @@
|
||||
window.Checkout = angular.module("Checkout", ["ngResource", "filters"]).config ($httpProvider) ->
|
||||
$httpProvider.defaults.headers.post['X-CSRF-Token'] = $('meta[name="csrf-token"]').attr('content')
|
||||
@@ -1,20 +1,29 @@
|
||||
angular.module("Checkout").controller "CheckoutCtrl", ($scope, $rootScope, order) ->
|
||||
Darkswarm.controller "CheckoutCtrl", ($scope, $rootScope, order) ->
|
||||
$scope.require_ship_address = false
|
||||
$scope.shipping_method = -1
|
||||
$scope.payment_method = -1
|
||||
$scope.same_as_billing = true
|
||||
$scope.order = order
|
||||
|
||||
$scope.initialize = ->
|
||||
# Our shipping_methods comes through as a hash like so: {id: requires_shipping_address}
|
||||
# Here we default to the first shipping method if none is selected
|
||||
$scope.order.shipping_method_id ||= Object.keys(order.shipping_methods)[0]
|
||||
$scope.order.ship_address_same_as_billing = true if $scope.order.ship_address_same_as_billing == null
|
||||
$scope.shippingMethodChanged()
|
||||
|
||||
# Our shipping_methods comes through as a hash like so: {id: requires_shipping_address}
|
||||
# Here we default to the first shipping method if none is selected
|
||||
$scope.order.shipping_method_id ||= Object.keys(order.shipping_methods)[0]
|
||||
$scope.require_ship_address = $scope.order.shipping_methods[$scope.order.shipping_method_id]
|
||||
|
||||
$scope.shippingMethodChanged = ->
|
||||
$scope.require_ship_address = $scope.order.shipping_methods[$scope.order.shipping_method_id]
|
||||
$scope.shippingPrice = ->
|
||||
$scope.shippingMethod().price
|
||||
|
||||
$scope.cartTotal = ->
|
||||
$scope.shippingPrice() + $scope.order.display_total
|
||||
|
||||
$scope.shippingMethod = ->
|
||||
$scope.order.shipping_methods[$scope.order.shipping_method_id]
|
||||
|
||||
$scope.shippingMethodChanged = ->
|
||||
$scope.require_ship_address = $scope.shippingMethod().require_ship_address if $scope.shippingMethod()
|
||||
|
||||
$scope.purchase = (event)->
|
||||
event.preventDefault()
|
||||
checkout.submit()
|
||||
|
||||
$scope.initialize()
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
window.LoginSidebarCtrl = Darkswarm.controller "LoginSidebarCtrl", ($scope, $http) ->
|
||||
$scope.spree_user = {
|
||||
remember_me: 0
|
||||
}
|
||||
|
||||
$scope.active = ->
|
||||
$scope.active_sidebar == '/login'
|
||||
|
||||
$scope.submit = ->
|
||||
$http.post("/user/spree_user/sign_in", {spree_user: $scope.spree_user}).success (data)->
|
||||
location.href = location.origin + location.pathname # Strips out hash fragments
|
||||
.error (data) ->
|
||||
$scope.errors = data.message
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Shop.controller "OrderCycleCtrl", ($scope, $rootScope, OrderCycle) ->
|
||||
Darkswarm.controller "OrderCycleCtrl", ($scope, $rootScope, OrderCycle) ->
|
||||
$scope.order_cycle = OrderCycle.order_cycle
|
||||
$scope.changeOrderCycle = ->
|
||||
OrderCycle.push_order_cycle()
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
angular.module("Shop").controller "ProductsCtrl", ($scope, $rootScope, Product, OrderCycle) ->
|
||||
Darkswarm.controller "ProductsCtrl", ($scope, $rootScope, Product, OrderCycle) ->
|
||||
$scope.data = Product.data
|
||||
$scope.order_cycle = OrderCycle.order_cycle
|
||||
Product.update()
|
||||
|
||||
$scope.searchKeypress = (e)->
|
||||
code = e.keyCode || e.which
|
||||
if code == 13
|
||||
e.preventDefault()
|
||||
|
||||
$scope.productPrice = (product) ->
|
||||
if product.variants.length > 0
|
||||
prices = (v.price for v in product.variants)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
window.SidebarCtrl = Darkswarm.controller "SidebarCtrl", ($scope, $location) ->
|
||||
$scope.$watch ->
|
||||
$location.path()
|
||||
, ->
|
||||
$scope.active_sidebar = $location.path()
|
||||
|
||||
$scope.active = ->
|
||||
return "active" if $scope.active_sidebar != null and $scope.active_sidebar != ""
|
||||
@@ -0,0 +1,3 @@
|
||||
window.SignupSidebarCtrl = Darkswarm.controller "SignupSidebarCtrl", ($scope) ->
|
||||
$scope.active = ->
|
||||
$scope.active_sidebar == '/signup'
|
||||
5
app/assets/javascripts/darkswarm/darkswarm.js.coffee
Normal file
5
app/assets/javascripts/darkswarm/darkswarm.js.coffee
Normal file
@@ -0,0 +1,5 @@
|
||||
window.Darkswarm = angular.module("Darkswarm", ["ngResource", "filters"]).config ($httpProvider) ->
|
||||
$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, */*"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Shop.factory 'OrderCycle', ($resource, Product, orderCycleData) ->
|
||||
Darkswarm.factory 'OrderCycle', ($resource, Product, orderCycleData) ->
|
||||
class OrderCycle
|
||||
@order_cycle = orderCycleData || {orders_close_at: ""}
|
||||
@push_order_cycle: ->
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Shop.factory 'Product', ($resource) ->
|
||||
Darkswarm.factory 'Product', ($resource) ->
|
||||
new class Product
|
||||
data: {
|
||||
products: null
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
window.Shop = angular.module("Shop", ["ngResource", "filters"]).config ($httpProvider) ->
|
||||
$httpProvider.defaults.headers.post['X-CSRF-Token'] = $('meta[name="csrf-token"]').attr('content')
|
||||
|
||||
|
||||
angular.module("filters", []).filter "truncate", ->
|
||||
(text, length, end) ->
|
||||
text = text || ""
|
||||
|
||||
@@ -5,4 +5,4 @@ $(document).ready ->
|
||||
$('th.cart-adjustment-header a').click ->
|
||||
$('#cart_adjustments').toggle()
|
||||
$('th.cart-adjustment-header a').html('Distribution')
|
||||
false
|
||||
false
|
||||
|
||||
@@ -126,3 +126,10 @@ table#listing_enterprise_groups {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
.fullwidth_inputs {
|
||||
input[type=text], select {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,5 +7,3 @@
|
||||
*= require foundation
|
||||
*= require_tree .
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
checkout
|
||||
display: block
|
||||
|
||||
orderdetails
|
||||
.button, table
|
||||
width: 100%
|
||||
|
||||
50
app/assets/stylesheets/darkswarm/offcanvas.css
Normal file
50
app/assets/stylesheets/darkswarm/offcanvas.css
Normal file
@@ -0,0 +1,50 @@
|
||||
/* Off canvas layout CSS/JS provided by or adapted from work by Jason Weaver and Luke Wroblewski Requires globals.css grid.css */
|
||||
body.off-canvas { padding: 0; margin: 0;}
|
||||
|
||||
.container { width: 100%; }
|
||||
|
||||
.row { overflow: hidden; }
|
||||
|
||||
.row .row { overflow: visible; }
|
||||
|
||||
.paneled .container { overflow: hidden; }
|
||||
|
||||
.paneled .row { width: 100%; }
|
||||
|
||||
[role="main"]:before { content: " "; position: absolute; z-index: -1; top: 0; left: -100%; width: 100%; height: 100%; }
|
||||
|
||||
[role="complementary"], [role="main"] { width: 100%; padding: 0 15px; display: block; position: relative; z-index: 1; -webkit-transition: 0.25s all ease-in; -moz-transition: 0.25s all ease-in; -o-transition: 0.25s all ease-in; transition: 0.25s all ease-in; }
|
||||
|
||||
.paneled [role="main"] { padding: 0; }
|
||||
|
||||
.page-panel { width: 100%; padding: 0 15px; -webkit-transition: 0.3s margin ease-in-out; -moz-transition: 0.3s margin ease-in-out; -o-transition: 0.3s margin ease-in-out; transition: 0.3s margin ease-in-out; background: #fff; }
|
||||
|
||||
#switchPanels { margin: 0 -15px; }
|
||||
|
||||
.hide-extras [role="complementary"] { display: block; }
|
||||
|
||||
[role="navigation"]#topMenu { -webkit-transition: 0.25s all ease-in; -moz-transition: 0.25s all ease-in; -o-transition: 0.25s all ease-in; transition: 0.25s all ease-in; }
|
||||
|
||||
[role="navigation"]#topMenu ul { margin-top: 0; }
|
||||
|
||||
[role="complementary"] { margin-left: -100%; width: 400px; float: left; z-index: 2; }
|
||||
|
||||
[role="main"] { margin-left: 0; float: right; z-index: 1; position: relative; }
|
||||
|
||||
.paneled [role="main"] { background: #fff; width: 500%; overflow: hidden; float: none; position: relative; left: 0; -webkit-transition: 0.15s all ease-in; -moz-transition: 0.15s all ease-in; -o-transition: 0.15s all ease-in; transition: 0.15s all ease-in; }
|
||||
|
||||
.page-panel { min-height: 400px; float: left; margin: 0; width: 20%; }
|
||||
|
||||
[role="complementary"].active { margin-left: 0; }
|
||||
.active + [role="main"] { margin-right: -420px; }
|
||||
|
||||
.active-menu [role="navigation"]#topMenu { margin-top: 0 !important; }
|
||||
|
||||
@media all and (min-width: 768px) { menu-button, .sidebar-button { display: none; }
|
||||
/*[role="complementary"] { width: 20%; margin-left: 0; float: left; padding: 0 15px; }*/
|
||||
[role="main"] { width: 100%; padding: 0 15px; }
|
||||
.paneled [role="main"] { width: 100%; padding: 0; background: #f4f4f4; left: 0 !important; }
|
||||
.page-panel { display: block; min-height: 800px; float: none; margin: 0; width: 100%; background: #f4f4f4; }
|
||||
.hide-extras [role="main"] { width: 100%; }
|
||||
.hide-extras [role="complementary"] { display: none; }
|
||||
[role="navigation"]#topMenu { display: none; } }
|
||||
@@ -1,2 +1,5 @@
|
||||
.row
|
||||
max-width: 74em
|
||||
|
||||
.reveal-modal
|
||||
position: fixed
|
||||
|
||||
@@ -90,6 +90,12 @@ product
|
||||
max-width: 555px
|
||||
@media all and (max-width: 768px)
|
||||
height: auto !important
|
||||
ul
|
||||
list-style-type: none
|
||||
padding-left: none
|
||||
.panel
|
||||
padding-bottom: 1.25em
|
||||
|
||||
& > .title, &.active > .title
|
||||
text-transform: uppercase
|
||||
line-height: 50px
|
||||
|
||||
13
app/assets/stylesheets/darkswarm/sidepanel.css.sass
Normal file
13
app/assets/stylesheets/darkswarm/sidepanel.css.sass
Normal file
@@ -0,0 +1,13 @@
|
||||
@import "foundation/variables"
|
||||
@import "foundation/components/global"
|
||||
@import "foundation/components/buttons"
|
||||
@import "foundation/components/panels"
|
||||
|
||||
|
||||
#sidebar
|
||||
margin-top: 1.875em
|
||||
.login-panel
|
||||
$bg: #222
|
||||
$padding: emCalc(20)
|
||||
$adjust: true
|
||||
@include panel($bg, $padding, $adjust)
|
||||
@@ -1,6 +1,7 @@
|
||||
table thead tr, table tbody tr
|
||||
th, td
|
||||
box-sizing: border-box
|
||||
padding-left: 12px
|
||||
padding-right: 12px
|
||||
overflow: hidden
|
||||
table
|
||||
thead tr, tbody tr
|
||||
th, td
|
||||
box-sizing: border-box
|
||||
padding-left: 12px
|
||||
padding-right: 12px
|
||||
overflow: hidden
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
//body
|
||||
//font-family: "AvenirBla_IE", "AvenirBla"
|
||||
|
||||
a
|
||||
color: #267D97
|
||||
&:hover
|
||||
text-decoration: underline
|
||||
|
||||
h1, h2, h3, h4, h5, h6, .avenir
|
||||
color: #333333
|
||||
font-family: "AvenirBla_IE", "AvenirBla"
|
||||
|
||||
@@ -4,6 +4,14 @@
|
||||
.landing-page-row {
|
||||
padding-top: emCalc(40);
|
||||
padding-bottom: emCalc(30);
|
||||
|
||||
#environment {
|
||||
font-size: 110%;
|
||||
font-weight: bold;
|
||||
padding: emCalc(5);
|
||||
border-radius: emCalc(5);
|
||||
background-color: #98ca45;
|
||||
}
|
||||
}
|
||||
|
||||
.distributor-link-row {
|
||||
@@ -49,7 +57,7 @@ a.inactive {
|
||||
}
|
||||
}
|
||||
.top-bar-section ul li {
|
||||
float: left;
|
||||
float: left;
|
||||
}
|
||||
.top-bar-section .divider, .top-bar-section [role="separator"] {
|
||||
clear: none;
|
||||
|
||||
@@ -67,7 +67,7 @@ class EnterprisesController < BaseController
|
||||
order.order_cycle = order_cycle_options.first if order_cycle_options.count == 1
|
||||
order.save!
|
||||
|
||||
redirect_to main_app.enterprise_path(distributor)
|
||||
redirect_to main_app.shop_path
|
||||
end
|
||||
|
||||
# essentially the new 'show' action that renders non-spree view
|
||||
|
||||
@@ -4,6 +4,7 @@ class Shop::CheckoutController < Spree::CheckoutController
|
||||
prepend_before_filter :require_order_cycle
|
||||
prepend_before_filter :require_distributor_chosen
|
||||
skip_before_filter :check_registration
|
||||
skip_before_filter :redirect_to_paypal_express_form_if_needed
|
||||
|
||||
include EnterprisesHelper
|
||||
|
||||
@@ -13,13 +14,17 @@ class Shop::CheckoutController < Spree::CheckoutController
|
||||
def update
|
||||
if @order.update_attributes(params[:order])
|
||||
fire_event('spree.checkout.update')
|
||||
|
||||
while @order.state != "complete"
|
||||
if @order.state == "payment"
|
||||
return if redirect_to_paypal_express_form_if_needed
|
||||
end
|
||||
|
||||
if @order.next
|
||||
state_callback(:after)
|
||||
else
|
||||
flash[:error] = t(:payment_processing_failed)
|
||||
respond_with @order, location: main_app.shop_checkout_path
|
||||
clear_ship_address
|
||||
render :edit
|
||||
return
|
||||
end
|
||||
end
|
||||
@@ -29,15 +34,25 @@ class Shop::CheckoutController < Spree::CheckoutController
|
||||
flash[:commerce_tracking] = "nothing special"
|
||||
respond_with(@order, :location => order_path(@order))
|
||||
else
|
||||
respond_with @order, location: main_app.shop_checkout_path
|
||||
clear_ship_address
|
||||
render :edit
|
||||
end
|
||||
else
|
||||
respond_with @order, location: main_app.shop_checkout_path
|
||||
clear_ship_address
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# When we have a pickup Shipping Method, we clone the distributor address into ship_address before_save
|
||||
# We don't want this data in the form, so we clear it out
|
||||
def clear_ship_address
|
||||
unless current_order.shipping_method.andand.require_ship_address
|
||||
current_order.ship_address = Spree::Address.default
|
||||
end
|
||||
end
|
||||
|
||||
def skip_state_validation?
|
||||
true
|
||||
end
|
||||
@@ -76,4 +91,36 @@ class Shop::CheckoutController < Spree::CheckoutController
|
||||
flash[:error] = t(:spree_inventory_error_flash_for_insufficient_quantity)
|
||||
redirect_to main_app.shop_path
|
||||
end
|
||||
|
||||
# Overriding from github.com/spree/spree_paypal_express
|
||||
def redirect_to_paypal_express_form_if_needed
|
||||
return unless params[:order][:payments_attributes]
|
||||
|
||||
payment_method = Spree::PaymentMethod.find(params[:order][:payments_attributes].first[:payment_method_id])
|
||||
return unless payment_method.kind_of?(Spree::BillingIntegration::PaypalExpress) || payment_method.kind_of?(Spree::BillingIntegration::PaypalExpressUk)
|
||||
|
||||
update_params = object_params.dup
|
||||
update_params.delete(:payments_attributes)
|
||||
if @order.update_attributes(update_params)
|
||||
fire_event('spree.checkout.update')
|
||||
render :edit and return unless apply_coupon_code
|
||||
end
|
||||
|
||||
load_order
|
||||
if not @order.errors.empty?
|
||||
render :edit and return
|
||||
end
|
||||
|
||||
redirect_to(main_app.shop_paypal_payment_url(@order, :payment_method_id => payment_method.id))
|
||||
true
|
||||
|
||||
end
|
||||
|
||||
# Overriding to customize the cancel url
|
||||
def order_opts_with_new_cancel_return_url(order, payment_method_id, stage)
|
||||
opts = order_opts_without_new_cancel_return_url(order, payment_method_id, stage)
|
||||
opts[:cancel_return_url] = main_app.shop_checkout_url
|
||||
opts
|
||||
end
|
||||
alias_method_chain :order_opts, :new_cancel_return_url
|
||||
end
|
||||
|
||||
@@ -5,13 +5,11 @@ class Shop::ShopController < BaseController
|
||||
before_filter :set_order_cycles
|
||||
|
||||
def show
|
||||
# All suppliers of all our products
|
||||
@producers = Exchange.where(receiver_id: @distributor.id).map{ |ex| ex.variants.map {|v| v.product.supplier }}.flatten.uniq
|
||||
end
|
||||
|
||||
def products
|
||||
unless @products = current_order_cycle.andand
|
||||
.products_distributed_by(current_distributor).andand
|
||||
.valid_products_distributed_by(current_distributor).andand
|
||||
.select { |p| p.has_stock_for_distribution?(current_order_cycle, current_distributor) }.andand
|
||||
.sort_by {|p| p.name }
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ Spree::CheckoutController.class_eval do
|
||||
past = Spree::Order.order("id desc").where(:email => email).where("state != 'cart'").limit(8)
|
||||
if order = past.detect(&:bill_address)
|
||||
bill_address = order.bill_address.clone if order.bill_address
|
||||
ship_address = order.ship_address.clone if order.ship_address
|
||||
ship_address = order.ship_address.clone if order.ship_address and order.shipping_method.andand.require_ship_address
|
||||
end
|
||||
|
||||
[bill_address, ship_address]
|
||||
|
||||
@@ -5,6 +5,8 @@ Spree::OrdersController.class_eval do
|
||||
before_filter :update_distribution, :only => :update
|
||||
before_filter :filter_order_params, :only => :update
|
||||
|
||||
layout 'darkswarm'
|
||||
|
||||
# Patch Orders#populate to populate multi_cart (if enabled)
|
||||
def populate
|
||||
if OpenFoodNetwork::FeatureToggle.enabled? :multi_cart
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
module HtmlHelper
|
||||
def strip_html(html)
|
||||
strip_tags(html).andand.gsub(/ /i, ' ').andand.gsub(/&/i, '&')
|
||||
strip_surrounding_whitespace substitute_entities strip_tags add_linebreaks html
|
||||
end
|
||||
|
||||
def substitute_entities(html)
|
||||
html.andand.gsub(/ /i, ' ').andand.gsub(/&/i, '&')
|
||||
end
|
||||
|
||||
def add_linebreaks(html)
|
||||
# I know Cthulu is coming for me. Forgive me.
|
||||
# http://stackoverflow.com/a/1732454/2720566
|
||||
html.
|
||||
andand.gsub(/<\/h[^>]>|<\/p>|<\/div>/, "\\1\n\n").
|
||||
andand.gsub(/<br[^>]*>/, "\\1\n")
|
||||
end
|
||||
|
||||
def strip_surrounding_whitespace(html)
|
||||
html.andand.strip
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,5 +8,10 @@ module SharedHelper
|
||||
klass += @active_distributors.include?(distributor) ? ' active' : ' inactive'
|
||||
klass
|
||||
end
|
||||
|
||||
# all suppliers of current distributor's products
|
||||
def current_producers
|
||||
Exchange.where(receiver_id: current_distributor.id).map{ |ex| ex.variants.map {|v| v.product.supplier }}.flatten.uniq
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
module Spree
|
||||
BaseHelper.class_eval do
|
||||
|
||||
# TODO can we delete this?
|
||||
# Spree code we are overriding to render sidebar
|
||||
# No longer rendering sidebar
|
||||
def taxons_tree(root_taxon, current_taxon, max_level = 1)
|
||||
return '' if max_level < 1 || root_taxon.children.empty?
|
||||
content_tag :ul, :class => 'taxons-list' do
|
||||
|
||||
@@ -20,7 +20,7 @@ class Exchange < ActiveRecord::Base
|
||||
scope :from_enterprises, lambda { |enterprises| where('exchanges.sender_id IN (?)', enterprises) }
|
||||
scope :to_enterprises, lambda { |enterprises| where('exchanges.receiver_id IN (?)', enterprises) }
|
||||
scope :with_variant, lambda { |variant| joins(:exchange_variants).where('exchange_variants.variant_id = ?', variant) }
|
||||
scope :any_variant, lambda { |variants| joins(:exchange_variants).where('exchange_variants.variant_id IN (?)', variants) }
|
||||
scope :with_any_variant, lambda { |variants| joins(:exchange_variants).where('exchange_variants.variant_id IN (?)', variants).select('DISTINCT exchanges.*') }
|
||||
scope :with_product, lambda { |product| joins(:exchange_variants).where('exchange_variants.variant_id IN (?)', product.variants_including_master) }
|
||||
|
||||
def clone!(new_order_cycle)
|
||||
|
||||
@@ -23,7 +23,7 @@ class OrderCycle < ActiveRecord::Base
|
||||
scope :distributing_product, lambda { |product|
|
||||
joins(:exchanges => :variants).
|
||||
merge(Exchange.outgoing).
|
||||
where('spree_variants.id IN (?)', product.variants_including_master.map(&:id)).
|
||||
where('spree_variants.id IN (?)', product.variants_including_master.pluck(:id)).
|
||||
select('DISTINCT order_cycles.*') }
|
||||
|
||||
scope :with_distributor, lambda { |distributor|
|
||||
@@ -105,6 +105,16 @@ class OrderCycle < ActiveRecord::Base
|
||||
variants_distributed_by(distributor).map(&:product).uniq
|
||||
end
|
||||
|
||||
# If a product without variants is added to an order cycle, and then some variants are added
|
||||
# to that product, then the master variant is still part of the order cycle, but customers
|
||||
# should not be able to purchase it.
|
||||
# This method filters out such products so that the customer cannot purchase them.
|
||||
def valid_products_distributed_by(distributor)
|
||||
variants = variants_distributed_by(distributor)
|
||||
products = variants.map(&:product).uniq
|
||||
products.reject { |p| product_has_only_obsolete_master_in_distribution?(p, variants) }
|
||||
end
|
||||
|
||||
def products
|
||||
self.variants.map(&:product).uniq
|
||||
end
|
||||
@@ -214,12 +224,26 @@ class OrderCycle < ActiveRecord::Base
|
||||
fees
|
||||
end
|
||||
|
||||
|
||||
# -- Misc
|
||||
|
||||
# If a product without variants is added to an order cycle, and then some variants are added
|
||||
# to that product, then the master variant is still part of the order cycle, but customers
|
||||
# should not be able to purchase it.
|
||||
# This method is used by #valid_products_distributed_by to filter out such products so that
|
||||
# the customer cannot purchase them.
|
||||
def product_has_only_obsolete_master_in_distribution?(product, distributed_variants)
|
||||
product.has_variants? &&
|
||||
distributed_variants.include?(product.master) &&
|
||||
(product.variants & distributed_variants).empty?
|
||||
end
|
||||
|
||||
def exchanges_carrying(variant, distributor)
|
||||
exchanges.to_enterprises([coordinator, distributor]).with_variant(variant)
|
||||
end
|
||||
|
||||
def exchanges_supplying(order)
|
||||
variants = order.line_items.map(&:variant)
|
||||
exchanges.to_enterprises([coordinator, order.distributor]).any_variant(variants)
|
||||
exchanges.to_enterprises([coordinator, order.distributor]).with_any_variant(variants)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -15,8 +15,8 @@ class AbilityDecorator
|
||||
end
|
||||
|
||||
can [:admin, :index, :read, :create, :edit, :update, :search, :destroy], Spree::Variant
|
||||
can [:admin, :index, :read, :create, :edit, :destroy], Spree::ProductProperty
|
||||
can [:admin, :index, :read, :create, :edit], Spree::Image
|
||||
can [:admin, :index, :read, :create, :edit, :update_positions, :destroy], Spree::ProductProperty
|
||||
can [:admin, :index, :read, :create, :edit, :update, :destroy], Spree::Image
|
||||
|
||||
can [:admin, :index, :read, :search], Spree::Taxon
|
||||
can [:admin, :index, :read, :create, :edit], Spree::Classification
|
||||
|
||||
@@ -65,6 +65,12 @@ Spree::Order.class_eval do
|
||||
where("state != ?", state)
|
||||
}
|
||||
|
||||
# Accessors
|
||||
#
|
||||
def ship_address_same_as_billing=(string_value)
|
||||
@ship_address_same_as_billing = (string_value == "true")
|
||||
end
|
||||
|
||||
|
||||
# -- Methods
|
||||
def products_available_from_new_distribution
|
||||
@@ -127,10 +133,10 @@ Spree::Order.class_eval do
|
||||
line_items.map { |li| li.variant }
|
||||
end
|
||||
|
||||
# Show payment methods with no distributor or for this distributor
|
||||
# Show payment methods for this distributor
|
||||
def available_payment_methods
|
||||
@available_payment_methods ||= Spree::PaymentMethod.available(:front_end).select do |pm|
|
||||
(self.distributor && (pm.distributors.include? self.distributor)) || pm.distributors.empty?
|
||||
(self.distributor && (pm.distributors.include? self.distributor))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ Spree::Product.class_eval do
|
||||
if variant_unit_changed?
|
||||
option_types.delete self.class.all_variant_unit_option_types
|
||||
option_types << variant_unit_option_type if variant_unit.present?
|
||||
variants.each { |v| v.delete_unit_option_values }
|
||||
variants_including_master.each { |v| v.delete_unit_option_values }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
Spree::ShippingMethod.class_eval do
|
||||
has_and_belongs_to_many :distributors, join_table: 'distributors_shipping_methods', :class_name => 'Enterprise', association_foreign_key: 'distributor_id'
|
||||
attr_accessible :distributor_ids
|
||||
attr_accessible :require_ship_address
|
||||
|
||||
scope :managed_by, lambda { |user|
|
||||
if user.has_spree_role?('admin')
|
||||
@@ -34,6 +35,6 @@ Spree::ShippingMethod.class_eval do
|
||||
end
|
||||
|
||||
def adjustment_label
|
||||
'Delivery'
|
||||
'Shipping'
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
/ insert_after "[data-hook='long_description']"
|
||||
%tr{"data-hook" => "distributor_info"}
|
||||
%td Distributor Info:
|
||||
%td= f.text_area :distributor_info, :class => 'rich_text'
|
||||
@@ -1,3 +0,0 @@
|
||||
/ replace_contents "[data-hook='long_description']"
|
||||
%td Profile Info:
|
||||
%td= f.text_area :long_description, :class => 'rich_text'
|
||||
@@ -1,6 +0,0 @@
|
||||
# Remove column layout from cart form items so we can style it with CSS
|
||||
Deface::Override.new(:virtual_path => "spree/orders/edit",
|
||||
:replace => "#empty-cart[data-hook]",
|
||||
:partial => "spree/orders/empty_cart_form",
|
||||
:name => "rearrange_empty_cart_form",
|
||||
:original => 'b5a751777e66ccbd45d7f1b980ecd201af94cb5b')
|
||||
@@ -1,6 +0,0 @@
|
||||
# Remove column layout from cart form items so we can style it with CSS
|
||||
Deface::Override.new(:virtual_path => "spree/orders/edit",
|
||||
:replace => "[data-hook='inside_cart_form']",
|
||||
:partial => "spree/orders/inside_cart_form",
|
||||
:name => "rearrange_inside_cart_form",
|
||||
:original => 'e30b0e749869c51f004242b0cb7be582b45e044e')
|
||||
@@ -1,17 +0,0 @@
|
||||
/ insert_before "[data-hook='new_product_attrs']"
|
||||
|
||||
.row
|
||||
.alpha.six.columns
|
||||
= f.label :variant_unit, 'Variant unit'
|
||||
= f.select :variant_unit, product_variant_unit_options, {:include_blank => true}, {:class => "select2 fullwidth"}
|
||||
= f.error_message_on :variant_unit
|
||||
|
||||
.four.columns
|
||||
= f.label :variant_unit_scale, 'Variant unit scale'
|
||||
= f.text_field :variant_unit_scale, {class: "fullwidth"}
|
||||
= f.error_message_on :variant_unit_scale
|
||||
|
||||
.omega.six.columns
|
||||
= f.label :variant_unit_name, 'Variant unit name'
|
||||
= f.text_field :variant_unit_name, {class: "fullwidth"}
|
||||
= f.error_message_on :variant_unit_name
|
||||
@@ -1,4 +0,0 @@
|
||||
/ insert_bottom "[id='clear_cart_link']"
|
||||
|
||||
%div
|
||||
= link_to "Shop in List View", main_app.shop_path
|
||||
@@ -1,4 +0,0 @@
|
||||
/ insert_bottom "[data-hook='cart_buttons']"
|
||||
|
||||
%div
|
||||
= link_to "Quick Checkout", main_app.shop_checkout_path
|
||||
@@ -1,8 +0,0 @@
|
||||
/ replace_contents 'tfoot#order-charges'
|
||||
|
||||
- checkout_adjustments_for_summary(@order).each do |adjustment|
|
||||
%tr.total
|
||||
%td{:colspan => "4"}
|
||||
%strong= adjustment.label
|
||||
%td.total
|
||||
%span= adjustment.display_amount.to_html
|
||||
@@ -1,67 +1,158 @@
|
||||
- content_for :head do
|
||||
= render 'shared/cms_elrte_head'
|
||||
|
||||
%table{"data-hook" => "distributors"}
|
||||
%tr{"data-hook" => "name"}
|
||||
%td Name:
|
||||
%td= f.text_field :name
|
||||
%tr{"data-hook" => "description"}
|
||||
%td Description:
|
||||
%td= f.text_field :description
|
||||
%tr{'data-hook' => "long_description"}
|
||||
%td Extended Description:
|
||||
%td= f.text_area :long_description, :class => 'rich_text'
|
||||
%tr{'data-hook' => "is_primary_producer"}
|
||||
%td Primary Producer?
|
||||
%td= f.check_box :is_primary_producer
|
||||
%tr{'data-hook' => "is_distributor"}
|
||||
%td Distributor?
|
||||
%td= f.check_box :is_distributor
|
||||
%tr{'data-hook' => "enterprise_group_ids"}
|
||||
%td Groups
|
||||
%td= f.collection_select :group_ids, EnterpriseGroup.all, :id, :name, {}, {class: "select2 fullwidth", multiple: true}
|
||||
%tr{"data-hook" => "contact"}
|
||||
%td Contact Person:
|
||||
%td= f.text_field :contact
|
||||
%tr{"data-hook" => "phone"}
|
||||
%td Phone:
|
||||
%td= f.text_field :phone
|
||||
%tr{"data-hook" => "email"}
|
||||
%td Email:
|
||||
%td= f.text_field :email
|
||||
%tr{"data-hook" => "website"}
|
||||
%td Website:
|
||||
%td= f.text_field :website
|
||||
%tr{"data-hook" => "twitter"}
|
||||
%td Twitter:
|
||||
%td= f.text_field :twitter
|
||||
%tr{"data-hook" => "abn"}
|
||||
%td ABN:
|
||||
%td= f.text_field :abn
|
||||
%tr{"data-hook" => "acn"}
|
||||
%td ACN:
|
||||
%td= f.text_field :acn
|
||||
%tr{"data-hook" => "logo"}
|
||||
%td Logo:
|
||||
%td
|
||||
= f.file_field :logo
|
||||
= image_tag @object.logo.url
|
||||
%tr{"data-hook" => "promo"}
|
||||
%td Promo Image:
|
||||
%td
|
||||
= f.file_field :promo_image
|
||||
= image_tag @object.promo_image.url
|
||||
%fieldset
|
||||
%legend Address
|
||||
%table
|
||||
= f.fields_for :address do |address_form|
|
||||
= render 'spree/admin/shared/address_form_simple', :f => address_form
|
||||
%fieldset
|
||||
%legend Pickup details
|
||||
%table{"data-hook" => "distributors_pickup_details"}
|
||||
%tr{"data-hook" => "next_collection_at"}
|
||||
%td Next collection date/time:
|
||||
%td= f.text_field :next_collection_at
|
||||
%tr{"data-hook" => "pickup_times"}
|
||||
%td Regular pickup times:
|
||||
%td= f.text_field :pickup_times
|
||||
- content_for :page_title do
|
||||
New Enterprise
|
||||
|
||||
- content_for :page_actions do
|
||||
%li= button_link_to "Back to enterprises list", main_app.admin_enterprises_path, icon: 'icon-arrow-left'
|
||||
|
||||
|
||||
.fullwidth_inputs
|
||||
.row
|
||||
.alpha.six.columns
|
||||
.two.columns.alpha
|
||||
= f.label :name
|
||||
.four.columns.omega
|
||||
= f.text_field :name
|
||||
.omega.six.columns
|
||||
.two.columns.alpha
|
||||
= f.label :group_ids, 'Groups'
|
||||
.with-tip{'data-powertip' => "Select any groups or regions that you are a member of. This will help customers find your enterprise."}
|
||||
%a What's this?
|
||||
|
||||
.four.columns.omega
|
||||
= f.collection_select :group_ids, EnterpriseGroup.all, :id, :name, {}, {class: "select2 fullwidth", multiple: true}
|
||||
.row
|
||||
.alpha.two.columns
|
||||
.omega.ten.columns
|
||||
= f.check_box :is_primary_producer
|
||||
= f.label :is_primary_producer, 'Producer'
|
||||
|
||||
= f.check_box :is_distributor
|
||||
= f.label :is_distributor, 'Hub'
|
||||
|
||||
.with-tip{'data-powertip' => "Select 'Producer' if you are a primary producer of food. Select 'Hub' if you want a shop-front. You can choose either or both."}
|
||||
%a What's this?
|
||||
|
||||
= f.fields_for :address do |af|
|
||||
%fieldset.no-border-bottom
|
||||
%legend Address
|
||||
.row
|
||||
.alpha.six.columns
|
||||
.alpha.two.columns
|
||||
= af.label :address1
|
||||
.omega.four.columns
|
||||
= af.text_field :address1
|
||||
.omega.six.columns
|
||||
.alpha.two.columns
|
||||
= af.label :address2
|
||||
.omega.four.columns
|
||||
= af.text_field :address2
|
||||
.row
|
||||
.six.columns.alpha
|
||||
.alpha.two.columns
|
||||
= af.label :city, 'Suburb'
|
||||
.omega.four.columns
|
||||
= af.text_field :city
|
||||
.six.columns.omega
|
||||
.alpha.two.columns
|
||||
= af.label :zipcode, 'Postcode'
|
||||
.omega.four.columns
|
||||
= af.text_field :zipcode
|
||||
.row
|
||||
.alpha.two.columns
|
||||
.omega.three.columns
|
||||
= af.collection_select(:state_id, af.object.country.states, :id, :name)
|
||||
.row
|
||||
.alpha.two.columns
|
||||
.omega.three.columns
|
||||
= af.collection_select(:country_id, available_countries, :id, :name)
|
||||
.row
|
||||
.alpha.six.columns
|
||||
%fieldset.no-border-bottom
|
||||
%legend Contact Details
|
||||
.row
|
||||
.alpha.two.columns
|
||||
= f.label :contact, 'Name'
|
||||
.omega.four.columns
|
||||
= f.text_field :contact
|
||||
.row
|
||||
.alpha.two.columns
|
||||
= f.label :email
|
||||
.omega.four.columns
|
||||
= f.text_field :email
|
||||
.row
|
||||
.alpha.two.columns
|
||||
= f.label :phone
|
||||
.omega.four.columns
|
||||
= f.text_field :phone
|
||||
.omega.six.columns
|
||||
%fieldset.no-border-bottom
|
||||
%legend Enterprise Details
|
||||
.row
|
||||
.alpha.two.columns
|
||||
= f.label :abn, 'ABN'
|
||||
.omega.four.columns
|
||||
= f.text_field :abn
|
||||
.row
|
||||
.alpha.two.columns
|
||||
= f.label :acn, 'ACN'
|
||||
.omega.four.columns
|
||||
= f.text_field :acn
|
||||
.row
|
||||
.alpha.two.columns
|
||||
= f.label :website
|
||||
.omega.four.columns
|
||||
= f.text_field :website
|
||||
-# TODO: Facebook model field
|
||||
-#.row
|
||||
-# .alpha.two.columns
|
||||
-# = f.label :facebook, 'Facebook'
|
||||
-# .omega.four.columns
|
||||
-# = f.text_field :facebook
|
||||
.row
|
||||
.alpha.two.columns
|
||||
= f.label :twitter
|
||||
.omega.four.columns
|
||||
= f.text_field :twitter
|
||||
%fieldset.no-border-bottom
|
||||
%legend About Us
|
||||
.row
|
||||
.alpha.two.columns
|
||||
= f.label :description, 'Short Description'
|
||||
.omega.ten.columns
|
||||
= f.text_field :description, placeholder: 'Tell us about your enterprise in one or two sentences'
|
||||
.row
|
||||
.alpha.two.columns
|
||||
= f.label :long_description, 'About Us'
|
||||
%br
|
||||
Tell us about yourself. This information appears on your public profile (under "About Us")
|
||||
.omega.eight.columns
|
||||
= f.text_area :long_description, class: 'rich_text', placeholder: 'Tell us about yourself. This information appears on your public profile (under "About Us")'
|
||||
.row
|
||||
.alpha.two.columns
|
||||
= f.label :distributor_info, 'How does your hub work?'
|
||||
%br
|
||||
%em (Hub only)
|
||||
%br
|
||||
Explain your distribution offer/s - this information appears on your public profile (under "How does it work?")
|
||||
.omega.eight.columns
|
||||
= f.text_area :distributor_info, class: 'rich_text', placeholder: 'Hub only: Explain your distribution offer/s - this is more detailed information that the user can access by clicking on "How does it work?"'
|
||||
/ TODO: editor breaks scrolling with arrow keys
|
||||
.row
|
||||
.alpha.two.columns
|
||||
= f.label :logo
|
||||
%br
|
||||
100 x 100 pixels
|
||||
.omega.four.columns
|
||||
= image_tag @object.logo.url if @object.logo.present?
|
||||
= f.file_field :logo
|
||||
.omega.two.columns
|
||||
= f.label :promo_image, class: 'with-tip', 'data-powertip' => 'This image is displayed in "About Us"'
|
||||
.with-tip{'data-powertip' => 'This image is displayed on the right hand side of the "About Us" section of your public profile.'}
|
||||
%a What's this?
|
||||
|
||||
.omega.four.columns
|
||||
= image_tag @object.promo_image.url if @object.promo_image.present?
|
||||
= f.file_field :pro_image
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
|
||||
<%= form_for [main_app, :admin, @enterprise] do |f| %>
|
||||
<%= render :partial => 'form', :locals => { :f => f } %>
|
||||
<!-- Save, Save & Close and Cancel button -->
|
||||
<%= render :partial => 'spree/admin/shared/new_resource_links' %>
|
||||
<% end %>
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
/ TODO: Unify this with exchange_distributed_products_form
|
||||
%td{:colspan => 3}
|
||||
.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 }}
|
||||
|
||||
-# 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
|
||||
|
||||
.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 }}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
%tr.products{'ng-show' => 'exchange.showProducts'}
|
||||
= render 'exchange_supplied_products_form'
|
||||
|
||||
= select_tag :new_supplier_id, options_from_collection_for_select(Enterprise.is_primary_producer.managed_by(spree_current_user), :id, :name), {'ng-model' => 'new_supplier_id'}
|
||||
= select_tag :new_supplier_id, options_from_collection_for_select(Enterprise.is_primary_producer.managed_by(spree_current_user).by_name, :id, :name), {'ng-model' => 'new_supplier_id'}
|
||||
= f.submit 'Add supplier', 'ng-click' => 'addSupplier($event)'
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
%tr.products{'ng-show' => 'exchange.showProducts'}
|
||||
= render 'exchange_distributed_products_form'
|
||||
|
||||
= select_tag :new_distributor_id, options_from_collection_for_select(Enterprise.is_distributor.managed_by(spree_current_user), :id, :name), {'ng-model' => 'new_distributor_id'}
|
||||
= select_tag :new_distributor_id, options_from_collection_for_select(Enterprise.is_distributor.managed_by(spree_current_user).by_name, :id, :name), {'ng-model' => 'new_distributor_id'}
|
||||
= f.submit 'Add distributor', 'ng-click' => 'addDistributor($event)'
|
||||
|
||||
.actions
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
.large-12.columns.centered
|
||||
%h3 WHERE WOULD YOU LIKE TO SHOP?
|
||||
%p.secondary Select your hub from the list below
|
||||
- if Rails.env.development? || Rails.env.staging?
|
||||
.large-12.columns.centered
|
||||
#environment= Rails.env.capitalize
|
||||
|
||||
- @groups.in_groups_of(4, false) do |row|
|
||||
.row.landing-page-row.hub_group{:class => (row.last == @groups.last ? "with-bottom-border" : "")}
|
||||
|
||||
@@ -12,16 +12,19 @@
|
||||
= render "layouts/bugherd_script"
|
||||
= csrf_meta_tags
|
||||
|
||||
%body.off-canvas
|
||||
%body.off-canvas{"ng-app" => "Darkswarm"}
|
||||
= render partial: "shared/menu"
|
||||
= display_flash_messages
|
||||
|
||||
%section{ role: "main" }
|
||||
= yield
|
||||
|
||||
%section#sidebar{ role: "complementary" }
|
||||
%section#sidebar{ role: "complementary", "ng-controller" => "SidebarCtrl", "ng-class" => "active()"}
|
||||
= render partial: "shared/login_panel"
|
||||
= yield :sidebar
|
||||
|
||||
%section{ role: "main" }
|
||||
= yield
|
||||
|
||||
#footer
|
||||
|
||||
|
||||
= yield :scripts
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
- if spree_current_user.nil?
|
||||
%li#login-link= link_to "Login", "#sidebar", id: "sidebarLoginButton", class: "sidebar-button"
|
||||
%li#login-link= link_to "Login", "#login", id: "sidebarLoginButton", class: "sidebar-button"
|
||||
%li#login-name.hide
|
||||
%li.divider
|
||||
%li#sign-up-link= link_to "Sign Up", "#sidebar", id: "sidebarSignUpButton", class: "sidebar-button"
|
||||
%li#sign-up-link= link_to "Sign Up", "#signup", id: "sidebarSignUpButton", class: "sidebar-button"
|
||||
%li#sign-out-link.hide= link_to "Sign Out", "/logout"
|
||||
- else
|
||||
%li#login-link.hide= link_to "Login", "#sidebar", id: "sidebarLoginButton", class: "sidebar-button"
|
||||
|
||||
@@ -1,5 +1,38 @@
|
||||
.login-panel
|
||||
#login-content.hide
|
||||
= render "home/login"
|
||||
#sign-up-content.hide
|
||||
%a{href: "#"} Close
|
||||
#login-content{"ng-controller" => "LoginSidebarCtrl", "ng-show" => "active()"}
|
||||
%h2 Login
|
||||
%form{"ng-submit" => "submit()"}
|
||||
.alert-box.alert{"ng-show" => "errors != null"}
|
||||
{{ errors }}
|
||||
.row
|
||||
.large-12.columns
|
||||
%label{for: "email"} Email
|
||||
%input.title.input-text{name: "email",
|
||||
type: "email",
|
||||
tabindex: 1,
|
||||
"ng-model" => "spree_user.email"}
|
||||
.row
|
||||
.large-12.columns
|
||||
%label{for: "password"} Password
|
||||
%input.title.input-text{name: "password",
|
||||
type: "password",
|
||||
autocomplete: "off",
|
||||
tabindex: 2,
|
||||
"ng-model" => "spree_user.password"}
|
||||
.row
|
||||
.large-12.columns
|
||||
%label{for: "remember_me"} Remember Me
|
||||
%input{name: "remember_me",
|
||||
type: "checkbox",
|
||||
value: "1",
|
||||
"ng-model" => "spree_user.remember_me"}
|
||||
.row
|
||||
.large-12.columns
|
||||
%input.button.primary{name: "commit",
|
||||
tabindex: "3",
|
||||
type: "submit",
|
||||
value: "Login"}
|
||||
|
||||
#sign-up-content{"ng-controller" => "SignupSidebarCtrl", "ng-show" => "active()"}
|
||||
= render "home/signup"
|
||||
|
||||
@@ -3,4 +3,7 @@
|
||||
%ul.left
|
||||
%li= link_to image_tag("ofn_logo_small.png"), root_path
|
||||
%li.divider
|
||||
= render partial: "shared/login"
|
||||
- if spree_current_user.nil?
|
||||
= render 'shared/signed_out'
|
||||
- else
|
||||
= render 'shared/signed_in'
|
||||
|
||||
5
app/views/shared/_signed_in.html.haml
Normal file
5
app/views/shared/_signed_in.html.haml
Normal file
@@ -0,0 +1,5 @@
|
||||
%li#login-link.hide= link_to "Login", "#sidebar", id: "sidebarLoginButton", class: "sidebar-button"
|
||||
%li#login-name= link_to "#{spree_current_user.email}", "#"
|
||||
%li.divider
|
||||
%li#sign-up-link.hide= link_to "Sign Up", "#"
|
||||
%li#sign-out-link= link_to "Sign Out", "/logout"
|
||||
5
app/views/shared/_signed_out.html.haml
Normal file
5
app/views/shared/_signed_out.html.haml
Normal file
@@ -0,0 +1,5 @@
|
||||
%li#login-link= link_to "Login", "#login", id: "sidebarLoginButton", class: "sidebar-button"
|
||||
%li#login-name.hide
|
||||
%li.divider
|
||||
%li#sign-up-link= link_to "Sign Up", "#signup", id: "sidebarSignUpButton", class: "sidebar-button"
|
||||
%li#sign-out-link.hide= link_to "Sign Out", "/logout"
|
||||
@@ -1,3 +1,5 @@
|
||||
= render partial: "shop/modals"
|
||||
|
||||
%navigation
|
||||
%distributor.details.row
|
||||
#distributor_title
|
||||
@@ -9,3 +11,5 @@
|
||||
%a{href: "/"} Change location
|
||||
|
||||
= render partial: "shop/shop/order_cycles"
|
||||
|
||||
= render partial: "shop/tabs"
|
||||
|
||||
38
app/views/shop/_modals.html.haml
Normal file
38
app/views/shop/_modals.html.haml
Normal file
@@ -0,0 +1,38 @@
|
||||
- for producer in current_producers
|
||||
.reveal-modal{id: "producer_details_#{producer.id}"}
|
||||
.row
|
||||
- if producer.logo.exists?
|
||||
.large-1.columns
|
||||
%img.left{src: producer.logo.url(:thumb)}
|
||||
.large-11.columns
|
||||
%h2
|
||||
= producer.name
|
||||
.row
|
||||
.large-8.columns
|
||||
= producer.long_description.andand.html_safe
|
||||
|
||||
- if producer.promo_image.exists?
|
||||
.large-4.columns
|
||||
%img.about.right{src: producer.promo_image.url(:large)}
|
||||
%a.close-reveal-modal ×
|
||||
|
||||
|
||||
|
||||
- for group in current_distributor.groups
|
||||
- for sibling in group.enterprises.except(current_distributor)
|
||||
.reveal-modal{id: "sibling_details_#{sibling.id}"}
|
||||
.row
|
||||
- if sibling.logo.exists?
|
||||
.large-1.columns
|
||||
%img.left{src: sibling.logo.url(:thumb)}
|
||||
.large-11.columns
|
||||
%h2
|
||||
= sibling.name
|
||||
.row
|
||||
.large-8.columns
|
||||
= sibling.long_description.andand.html_safe
|
||||
- if sibling.promo_image.exists?
|
||||
.large-4.columns
|
||||
%img.about.right{src: sibling.promo_image.url(:large)}
|
||||
%a.close-reveal-modal ×
|
||||
|
||||
7
app/views/shop/_tabs.html.haml
Normal file
7
app/views/shop/_tabs.html.haml
Normal file
@@ -0,0 +1,7 @@
|
||||
%tabs
|
||||
.row
|
||||
.section-container.auto{"data-section" => "", "data-options" => "one_up: false"}
|
||||
= render 'shop/shop/about_us'
|
||||
= render 'shop/shop/producers'
|
||||
= render 'shop/shop/groups'
|
||||
= render 'shop/shop/contact'
|
||||
@@ -1,8 +1,12 @@
|
||||
%checkout{"ng-controller" => "CheckoutCtrl"}
|
||||
|
||||
= f_form_for current_order, url: main_app.shop_update_checkout_path, html: {name: "checkout", id: "checkout_form"} do |f|
|
||||
|
||||
:javascript
|
||||
angular.module('Checkout').value('order', #{render "shop/checkout/order"})
|
||||
angular.module('Darkswarm').value('order', #{render "shop/checkout/order"})
|
||||
|
||||
-#%pre
|
||||
-#{{ order | json }}
|
||||
|
||||
.large-12.columns
|
||||
%fieldset#details
|
||||
@@ -33,35 +37,47 @@
|
||||
"ng-model" => "order.bill_address.address2"
|
||||
.row
|
||||
.large-6.columns
|
||||
|
||||
= ba.text_field :city,
|
||||
"ng-model" => "order.bill_address.city"
|
||||
|
||||
.large-6.columns
|
||||
= ba.select :country_id, available_countries.map{|c|[c.name, c.id]},
|
||||
{include_blank: false}, "ng-model" => "order.bill_address.country_id"
|
||||
.row
|
||||
.large-6.columns
|
||||
= ba.select :state_id, @order.billing_address.country.states.map{|c|[c.name, c.id]},
|
||||
"ng-model" => "order.bill_address.state_id"
|
||||
.large-6.columns.right
|
||||
= ba.text_field :zipcode,
|
||||
.row
|
||||
.large-6.columns
|
||||
= ba.text_field :zipcode, label: "Postcode",
|
||||
"ng-model" => "order.bill_address.zipcode"
|
||||
.large-6.columns.right
|
||||
= ba.select :country_id, available_countries.map{|c|[c.name, c.id]},
|
||||
{include_blank: false}, "ng-model" => "order.bill_address.country_id"
|
||||
|
||||
%fieldset#shipping
|
||||
%legend Shipping
|
||||
- for ship_method, i in current_distributor.shipping_methods.uniq
|
||||
.row
|
||||
.large-12.columns
|
||||
= f.radio_button :shipping_method_id, ship_method.id,
|
||||
text: ship_method.name,
|
||||
"ng-change" => "shippingMethodChanged()",
|
||||
"ng-model" => "order.shipping_method_id"
|
||||
-#= f.radio_button :shipping_method_id, ship_method.id,
|
||||
-#text: ship_method.name,
|
||||
-#"ng-change" => "shippingMethodChanged()",
|
||||
-#"ng-model" => "order.shipping_method_id"
|
||||
%label
|
||||
= radio_button_tag "order[shipping_method_id]", ship_method.id, false,
|
||||
"ng-change" => "shippingMethodChanged()",
|
||||
"ng-model" => "order.shipping_method_id"
|
||||
= ship_method.name
|
||||
|
||||
#distributor_address.panel{"ng-show" => "!require_ship_address"}
|
||||
= @order.distributor.distributor_info.andand.html_safe
|
||||
= @order.order_cycle.pickup_time_for(@order.distributor)
|
||||
= @order.order_cycle.pickup_instructions_for(@order.distributor)
|
||||
|
||||
= f.fields_for :ship_address, @order.ship_address do |sa|
|
||||
|
||||
#ship_address{"ng-show" => "require_ship_address"}
|
||||
%label
|
||||
= hidden_field_tag "order[ship_address_same_as_billing]", "false"
|
||||
= check_box_tag "order[ship_address_same_as_billing]", true, @order.ship_address_same_as_billing,
|
||||
"ng-checked" => "order.ship_address_same_as_billing == 'true'",
|
||||
"ng-model" => "order.ship_address_same_as_billing"
|
||||
Shipping address same as billing address?
|
||||
|
||||
@@ -78,28 +94,39 @@
|
||||
.large-6.columns
|
||||
= sa.text_field :city
|
||||
.large-6.columns
|
||||
= sa.select :country_id, available_countries.map{|c|[c.name, c.id]},
|
||||
{include_blank: false}
|
||||
= sa.select :state_id, @order.shipping_address.country.states.map{|c|[c.name, c.id]}
|
||||
.row
|
||||
.large-6.columns
|
||||
= sa.select :state_id, @order.shipping_address.country.states.map{|c|[c.name, c.id]}
|
||||
= sa.text_field :zipcode, label: "Postcode"
|
||||
.large-6.columns.right
|
||||
= sa.text_field :zipcode
|
||||
= sa.select :country_id, available_countries.map{|c|[c.name, c.id]},
|
||||
{include_blank: false}
|
||||
.row
|
||||
.large-6.columns
|
||||
= sa.text_field :firstname
|
||||
.large-6.columns
|
||||
= sa.text_field :lastname
|
||||
.row
|
||||
.large-6.columns
|
||||
= sa.text_field :phone
|
||||
|
||||
#ship_address_hidden{"ng-show" => "order.ship_address_same_as_billing"}
|
||||
= sa.hidden_field :address1, "ng-value" => "order.bill_address.address1"
|
||||
= sa.hidden_field :address2, "ng-value" => "order.bill_address.address2"
|
||||
= sa.hidden_field :city, "ng-value" => "order.bill_address.city"
|
||||
= sa.hidden_field :country_id, "ng-value" => "order.bill_address.country_id"
|
||||
= sa.hidden_field :zipcode, "ng-value" => "order.bill_address.zipcode"
|
||||
= sa.hidden_field :firstname, "ng-value" => "order.bill_address.firstname"
|
||||
= sa.hidden_field :lastname, "ng-value" => "order.bill_address.lastname"
|
||||
= sa.hidden_field :phone, "ng-value" => "order.bill_address.phone"
|
||||
= sa.hidden_field :address1, "ng-value" => "order.bill_address.address1",
|
||||
"ng-disabled" => "!order.ship_address_same_as_billing"
|
||||
= sa.hidden_field :address2, "ng-value" => "order.bill_address.address2",
|
||||
"ng-disabled" => "!order.ship_address_same_as_billing"
|
||||
= sa.hidden_field :city, "ng-value" => "order.bill_address.city",
|
||||
"ng-disabled" => "!order.ship_address_same_as_billing"
|
||||
= sa.hidden_field :country_id, "ng-value" => "order.bill_address.country_id",
|
||||
"ng-disabled" => "!order.ship_address_same_as_billing"
|
||||
= sa.hidden_field :zipcode, "ng-value" => "order.bill_address.zipcode",
|
||||
"ng-disabled" => "!order.ship_address_same_as_billing"
|
||||
= sa.hidden_field :firstname, "ng-value" => "order.bill_address.firstname",
|
||||
"ng-disabled" => "!order.ship_address_same_as_billing"
|
||||
= sa.hidden_field :lastname, "ng-value" => "order.bill_address.lastname",
|
||||
"ng-disabled" => "!order.ship_address_same_as_billing"
|
||||
= sa.hidden_field :phone, "ng-value" => "order.bill_address.phone",
|
||||
"ng-disabled" => "!order.ship_address_same_as_billing"
|
||||
|
||||
%fieldset#payment
|
||||
%legend Payment Details
|
||||
@@ -108,9 +135,9 @@
|
||||
.large-12.columns
|
||||
%label
|
||||
= radio_button_tag "order[payments_attributes][][payment_method_id]", method.id, false,
|
||||
"ng-model" => "payment_method"
|
||||
"ng-model" => "order.payment_method_id"
|
||||
= method.name
|
||||
.row{"ng-show" => "payment_method == #{method.id}"}
|
||||
.row{"ng-show" => "order.payment_method_id == #{method.id}"}
|
||||
.large-12.columns
|
||||
= render partial: "spree/checkout/payment/#{method.method_type}", :locals => { :payment_method => method }
|
||||
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
object current_order
|
||||
attributes :id, :email, :shipping_method_id, :ship_address_same_as_billing
|
||||
|
||||
node :display_total do
|
||||
current_order.display_total.money.to_f
|
||||
end
|
||||
|
||||
node :payment_method_id do
|
||||
current_order.payments.first.andand.payment_method_id || current_order.distributor.payment_methods.first.andand.id
|
||||
end
|
||||
|
||||
child current_order.bill_address => :bill_address do
|
||||
attributes :phone, :firstname, :lastname, :address1, :address2, :city, :country_id, :state_id, :zipcode
|
||||
end
|
||||
@@ -11,5 +19,10 @@ end
|
||||
|
||||
# Format here is {id: require_ship_address}
|
||||
node :shipping_methods do
|
||||
Hash[current_order.distributor.shipping_methods.collect { |method| [method.id, method.require_ship_address] }]
|
||||
Hash[current_order.distributor.shipping_methods.collect {
|
||||
|method| [method.id, {
|
||||
require_ship_address: method.require_ship_address,
|
||||
price: method.compute_amount(current_order).to_f
|
||||
}]
|
||||
}]
|
||||
end
|
||||
|
||||
@@ -4,16 +4,19 @@
|
||||
%legend Your Order
|
||||
%table
|
||||
%tr
|
||||
%th Cart subtotal
|
||||
%th Produce
|
||||
%td= current_order.display_item_total
|
||||
|
||||
- checkout_adjustments_for_summary(current_order).each do |adjustment|
|
||||
%tr
|
||||
%th= adjustment.label
|
||||
%td= adjustment.display_amount.to_html
|
||||
%tr
|
||||
%th Shipping
|
||||
%td {{ shippingPrice() | currency }}
|
||||
%tr
|
||||
%th Cart total
|
||||
%td= current_order.display_total.to_html
|
||||
%td {{ cartTotal() | currency }}
|
||||
- if current_order.price_adjustment_totals.present?
|
||||
- current_order.price_adjustment_totals.each do |label, total|
|
||||
%tr
|
||||
@@ -21,3 +24,4 @@
|
||||
%td= total
|
||||
|
||||
= f.submit "Purchase", class: "button"
|
||||
%a.button.secondary{href: cart_url} Back to Cart
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
= render partial: "shop/details"
|
||||
|
||||
%checkout{"ng-app" => "Checkout"}
|
||||
%checkout
|
||||
.row
|
||||
.large-9.columns
|
||||
- unless spree_current_user
|
||||
@@ -23,3 +23,4 @@
|
||||
.large-3.columns
|
||||
.row
|
||||
= render partial: "shop/checkout/summary"
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
.about.right.text-right.small-2.large-3.columns
|
||||
%h3 About Us
|
||||
%p= @distributor.long_description.andand.html_safe
|
||||
%section#about{class: current_order_cycle ? nil : "active" }
|
||||
%p.title.avenir{"data-section-title" => ""}
|
||||
%a{href: "#about"} About Us
|
||||
|
||||
.content{"data-section-content" => ""}
|
||||
%img.about.right{src: current_distributor.promo_image.url(:large)}
|
||||
%p= current_distributor.long_description.andand.html_safe
|
||||
|
||||
-#.panel
|
||||
-#= @distributor.distributor_info.andand.html_safe
|
||||
|
||||
18
app/views/shop/shop/_contact.html.haml
Normal file
18
app/views/shop/shop/_contact.html.haml
Normal file
@@ -0,0 +1,18 @@
|
||||
%section
|
||||
%p.title.avenir{"data-section-title" => ""}
|
||||
%a{href: "#contact"} Contact
|
||||
.content{"data-section-content" => ""}
|
||||
.panel
|
||||
%p
|
||||
%strong E
|
||||
%a{href: "mailto:#{current_distributor.email}"}= current_distributor.email
|
||||
- unless current_distributor.website.blank?
|
||||
%br
|
||||
%strong W
|
||||
%a{href: current_distributor.website}= current_distributor.website
|
||||
%br
|
||||
= [current_distributor.address.address1, current_distributor.address.address2].join ", "
|
||||
%br
|
||||
= current_distributor.address.city
|
||||
= current_distributor.address.state
|
||||
= current_distributor.address.zipcode
|
||||
@@ -1,18 +0,0 @@
|
||||
.contact.small-2.large-3.columns
|
||||
%h3 Contact
|
||||
|
||||
%p
|
||||
%strong E
|
||||
%a{href: "mailto:#{@distributor.email}"}= @distributor.email
|
||||
|
||||
- unless @distributor.website.blank?
|
||||
%p
|
||||
%strong W
|
||||
%a{href: @distributor.website}= @distributor.website
|
||||
|
||||
%p
|
||||
= @distributor.address.address1
|
||||
%br
|
||||
= @distributor.address.address2
|
||||
%br
|
||||
= @distributor.address.city
|
||||
13
app/views/shop/shop/_groups.html.haml
Normal file
13
app/views/shop/shop/_groups.html.haml
Normal file
@@ -0,0 +1,13 @@
|
||||
%section
|
||||
%p.title.avenir{"data-section-title" => ""}
|
||||
%a{href: "#groups"} Our Groups
|
||||
.content{"data-section-content" => ""}
|
||||
%ul
|
||||
- for group in current_distributor.groups
|
||||
%li
|
||||
%h4= group.name
|
||||
%ul
|
||||
- for sibling in group.enterprises.except(current_distributor)
|
||||
%li
|
||||
%a{"data-reveal-id" => "sibling_details_#{sibling.id}"}
|
||||
= sibling.name
|
||||
@@ -1,6 +1,6 @@
|
||||
%ordercycle{"ng-controller" => "OrderCycleCtrl"}
|
||||
:javascript
|
||||
angular.module('Shop').value('orderCycleData', #{render "shop/shop/order_cycle"})
|
||||
angular.module('Darkswarm').value('orderCycleData', #{render "shop/shop/order_cycle"})
|
||||
|
||||
- if @order_cycles.empty?
|
||||
Orders are currently closed for this hub
|
||||
|
||||
9
app/views/shop/shop/_producers.html.haml
Normal file
9
app/views/shop/shop/_producers.html.haml
Normal file
@@ -0,0 +1,9 @@
|
||||
%section
|
||||
%p.title.avenir{"data-section-title" => ""}
|
||||
%a{href: "#producers"} Our Producers
|
||||
.content{"data-section-content" => ""}
|
||||
%ul
|
||||
- for producer in current_producers
|
||||
%li
|
||||
%a{"data-reveal-id" => "producer_details_#{producer.id}"}
|
||||
= producer.name
|
||||
@@ -1,8 +1,9 @@
|
||||
%products{"ng-controller" => "ProductsCtrl", "ng-show" => "order_cycle.order_cycle_id != null"}
|
||||
%h5 Check out when you have selected everything you want
|
||||
= form_for :order, :url => populate_orders_path, html: {:class => "custom"} do
|
||||
%input#search.text{"ng-model" => "query", placeholder: "Search"}
|
||||
%input.button.right{type: :submit, value: "Check Out"}
|
||||
|
||||
%input#search.text{"ng-model" => "query", placeholder: "Search", "ng-keypress" => "searchKeypress($event)"}
|
||||
%input.button.right{type: :submit, value: "Add to Cart"}
|
||||
|
||||
%table
|
||||
%thead
|
||||
%th.name Item
|
||||
@@ -18,7 +19,8 @@
|
||||
%div
|
||||
%h5
|
||||
{{ product.name }}
|
||||
{{ product.supplier.name }}
|
||||
%a{"data-reveal-id" => "producer_details_{{product.supplier.id}}"}
|
||||
{{ product.supplier.name }}
|
||||
%td.notes {{ product.notes | truncate:80 }}
|
||||
%td
|
||||
%span{"ng-hide" => "product.variants.length > 0"} {{ product.master.options_text }}
|
||||
@@ -37,13 +39,15 @@
|
||||
min: 0,
|
||||
max: "{{product.on_demand && 9999 || product.count_on_hand }}",
|
||||
name: "variants[{{product.master.id}}]",
|
||||
id: "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,
|
||||
max: "{{product.on_demand && 9999 || product.count_on_hand }}",
|
||||
name: "variant_attributes[{{product.master.id}}][max_quantity]"}
|
||||
name: "variant_attributes[{{product.master.id}}][max_quantity]",
|
||||
"ng-model" => "product.max_quantity"}
|
||||
%td.price.text-right
|
||||
%small{"ng-show" => "(product.variants.length > 0)"} from
|
||||
{{ productPrice(product) | currency }}
|
||||
@@ -51,4 +55,6 @@
|
||||
%td{colspan: 2}{{ product.notes | truncate:80 }}
|
||||
%tr.variant{"ng-repeat" => "variant in product.variants", "ng-show" => "product.show_variants"}
|
||||
= render partial: "shop/shop/variant"
|
||||
%input.button.right{type: :submit, value: "Check Out"}
|
||||
%input.button.right{type: :submit, value: "Add to Cart"}
|
||||
|
||||
|
||||
|
||||
@@ -7,12 +7,14 @@
|
||||
value: nil,
|
||||
min: 0,
|
||||
max: "{{variant.on_demand && 9999 || variant.count_on_hand }}",
|
||||
name: "variants[{{variant.id}}]", id: "variants_{{variant.id}}"}
|
||||
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,
|
||||
max: "{{variant.on_demand && 9999 || variant.count_on_hand }}",
|
||||
name: "variant_attributes[{{variant.id}}][max_quantity]"}
|
||||
name: "variant_attributes[{{variant.id}}][max_quantity]",
|
||||
"ng-model" => "variant.max_quantity"}
|
||||
%td.price.text-right
|
||||
{{ variant.price | currency }}
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
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),
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
%shop.darkswarm{"ng-app" => "Shop"}
|
||||
|
||||
%shop.darkswarm
|
||||
- content_for :order_cycle_form do
|
||||
%strong.avenir Ready for
|
||||
%select.avenir#order_cycle_id{"ng-model" => "order_cycle.order_cycle_id",
|
||||
@@ -12,41 +11,5 @@
|
||||
%strong {{ order_cycle.orders_close_at | date_in_words }}
|
||||
= render partial: "shop/details"
|
||||
|
||||
|
||||
%tabs
|
||||
.row
|
||||
.section-container.auto{"data-section" => "", "data-options" => "one_up: false"}
|
||||
%section#about{class: current_order_cycle ? nil : "active" }
|
||||
%p.title.avenir{"data-section-title" => ""}
|
||||
%a{href: "#about"} About Us
|
||||
.content{"data-section-content" => ""}
|
||||
%img.about.right{src: @distributor.promo_image.url(:large)}
|
||||
%p= @distributor.long_description.andand.html_safe
|
||||
|
||||
%section
|
||||
%p.title.avenir{"data-section-title" => ""}
|
||||
%a{href: "#producers"} Our Producers
|
||||
.content{"data-section-content" => ""}
|
||||
%ul
|
||||
- for producer in @producers
|
||||
%li= producer.name
|
||||
|
||||
%section
|
||||
%p.title.avenir{"data-section-title" => ""}
|
||||
%a{href: "#groups"} Our Groups
|
||||
.content{"data-section-content" => ""}
|
||||
%p Coming Soon
|
||||
|
||||
%section
|
||||
%p.title.avenir{"data-section-title" => ""}
|
||||
%a{href: "#contact"} Contact
|
||||
.content{"data-section-content" => ""}
|
||||
%p Contact
|
||||
|
||||
%products.row
|
||||
= render partial: "shop/shop/products"
|
||||
#footer
|
||||
%section.row
|
||||
= render partial: "shop/shop/contact_us"
|
||||
= render partial: "shop/shop/about_us"
|
||||
= render partial: "shared/copyright"
|
||||
|
||||
11
app/views/spree/orders/_adjustments.html.haml
Normal file
11
app/views/spree/orders/_adjustments.html.haml
Normal file
@@ -0,0 +1,11 @@
|
||||
%thead
|
||||
%tr{"data-hook" => "cart_adjustments_headers"}
|
||||
%th.cart-adjustment-header{colspan: "6"}
|
||||
Distribution Fees
|
||||
|
||||
%tbody#cart_adjustments{"data-hook" => ""}
|
||||
- @order.adjustments.eligible.each do |adjustment|
|
||||
%tr
|
||||
%td{colspan: "4"}= adjustment.label
|
||||
%td= adjustment.display_amount.to_html
|
||||
%td
|
||||
@@ -1,6 +0,0 @@
|
||||
#empty-cart{'data-hook' => ""}
|
||||
= form_tag empty_cart_path, :method => :put do
|
||||
%p#clear_cart_link{'data-hook' => ""}
|
||||
= link_to t(:continue_shopping), products_path, :class => 'continue button'
|
||||
= t(:or)
|
||||
= submit_tag t(:empty_cart), :class => 'button'
|
||||
22
app/views/spree/orders/_form.html.haml
Normal file
22
app/views/spree/orders/_form.html.haml
Normal file
@@ -0,0 +1,22 @@
|
||||
= render :partial => 'spree/shared/error_messages', :locals => { :target => @order }
|
||||
|
||||
%table#cart-detail{"data-hook" => ""}
|
||||
%col{halign: "center", valign: "middle", width: "30%"}/
|
||||
%col{valign: "middle", width: "25%"}/
|
||||
%col{halign: "center", valign: "middle", width: "15%"}/
|
||||
%col{halign: "center", valign: "middle", width: "15%"}/
|
||||
%col{halign: "center", valign: "middle", width: "10%"}/
|
||||
%col{halign: "center", valign: "middle", width: "5%"}/
|
||||
%thead
|
||||
%tr{"data-hook" => "cart_items_headers"}
|
||||
%th.cart-item-description-header{colspan: "2"}= t(:item)
|
||||
%th.cart-item-price-header= t(:price)
|
||||
%th.cart-item-quantity-header= t(:qty)
|
||||
%th.cart-item-total-header= t(:total)
|
||||
%th.cart-item-delete-header
|
||||
|
||||
%tbody#line_items{"data-hook" => ""}
|
||||
= order_form.fields_for :line_items do |item_form|
|
||||
= render :partial => 'line_item', :locals => { :variant => item_form.object.variant, :line_item => item_form.object, :item_form => item_form }
|
||||
|
||||
= render "spree/orders/adjustments" unless @order.adjustments.eligible.blank?
|
||||
@@ -1,22 +0,0 @@
|
||||
%div{'data-hook' => "inside_cart_form"}
|
||||
%div{'data-hook' => "cart_items"}
|
||||
= render :partial => 'form', :locals => { :order_form => order_form }
|
||||
|
||||
#subtotal{'data-hook' => ""}
|
||||
%h5
|
||||
Item total
|
||||
\:
|
||||
%span.order-total.item-total= number_to_currency @order.item_total
|
||||
%h5
|
||||
Distribution total
|
||||
\:
|
||||
%span.order-total.distribution-total= order_distribution_subtotal(@order)
|
||||
%h4
|
||||
Total
|
||||
\:
|
||||
%span.order-total.grand-total= @order.display_total
|
||||
|
||||
.links{'data-hook' => "cart_buttons"}
|
||||
= button_tag :class => 'primary', :id => 'update-button' do
|
||||
= t(:update)
|
||||
= link_to t(:checkout), checkout_path, :class => 'button checkout primary', :id => 'checkout-link'
|
||||
27
app/views/spree/orders/_line_item.html.haml
Normal file
27
app/views/spree/orders/_line_item.html.haml
Normal file
@@ -0,0 +1,27 @@
|
||||
%tr.line-item
|
||||
%td.cart-item-image{"data-hook" => "cart_item_image"}
|
||||
- if variant.images.length == 0
|
||||
= link_to small_image(variant.product), variant.product
|
||||
- else
|
||||
= link_to image_tag(variant.images.first.attachment.url(:small)), variant.product
|
||||
|
||||
%td.cart-item-description{"data-hook" => "cart_item_description"}
|
||||
%h4= link_to variant.product.name, product_path(variant.product)
|
||||
= variant.options_text
|
||||
- if @order.insufficient_stock_lines.include? line_item
|
||||
%span.out-of-stock
|
||||
= variant.in_stock? ? t(:insufficient_stock, :on_hand => variant.on_hand) : t(:out_of_stock)
|
||||
%br
|
||||
= line_item_description(variant)
|
||||
|
||||
%td.cart-item-price{"data-hook" => "cart_item_price"}
|
||||
= line_item.single_money.to_html
|
||||
%td.cart-item-quantity{"data-hook" => "cart_item_quantity"}
|
||||
= item_form.number_field :quantity, :min => 0, :class => "line_item_quantity", :size => 5
|
||||
%td.cart-item-total{"data-hook" => "cart_item_total"}
|
||||
= line_item.display_amount.to_html unless line_item.quantity.nil?
|
||||
|
||||
%td.cart-item-delete{"data-hook" => "cart_item_delete"}
|
||||
{{ quantity }}
|
||||
= link_to image_tag('icons/delete.png'), '#', :class => 'delete',
|
||||
:id => "delete_#{dom_id(line_item)}"
|
||||
58
app/views/spree/orders/edit.html.haml
Normal file
58
app/views/spree/orders/edit.html.haml
Normal file
@@ -0,0 +1,58 @@
|
||||
- @body_id = 'cart'
|
||||
.darkswarm
|
||||
- content_for :order_cycle_form do
|
||||
%strong.avenir
|
||||
Order ready on
|
||||
- if @order.order_cycle
|
||||
= pickup_time @order.order_cycle
|
||||
- else
|
||||
= @order.distributor.next_collection_at
|
||||
|
||||
= render partial: "shop/details"
|
||||
|
||||
%fieldset
|
||||
- if @order.line_items.empty?
|
||||
%div.row{"data-hook" => "empty_cart"}
|
||||
%p= t(:your_cart_is_empty)
|
||||
%p= link_to t(:continue_shopping), main_app.shop_path, :class => 'button continue'
|
||||
|
||||
- else
|
||||
%div{"data-hook" => "outside_cart_form"}
|
||||
= form_for @order, :url => update_cart_path, :html => {:id => 'update-cart'} do |order_form|
|
||||
%div{"data-hook" => "inside_cart_form"}
|
||||
%div{"data-hook" => "cart_items"}
|
||||
.row
|
||||
= render :partial => 'form', :locals => { :order_form => order_form }
|
||||
|
||||
#subtotal.row{'data-hook' => ""}
|
||||
.columns.large-5
|
||||
%h5
|
||||
Product
|
||||
\:
|
||||
%span.order-total.item-total= number_to_currency @order.item_total
|
||||
.columns.large-4
|
||||
%h5
|
||||
Distribution
|
||||
\:
|
||||
%span.order-total.distribution-total= order_distribution_subtotal(@order)
|
||||
.columns.large-3
|
||||
%h4
|
||||
Cart Total
|
||||
\:
|
||||
%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'
|
||||
|
||||
.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"
|
||||
|
||||
25
app/views/spree/orders/show.html.haml
Normal file
25
app/views/spree/orders/show.html.haml
Normal file
@@ -0,0 +1,25 @@
|
||||
.darkswarm
|
||||
- content_for :order_cycle_form do
|
||||
%strong.avenir
|
||||
Order ready on
|
||||
- if @order.order_cycle
|
||||
= pickup_time @order.order_cycle
|
||||
- else
|
||||
= @order.distributor.next_collection_at
|
||||
|
||||
= render partial: "shop/details"
|
||||
|
||||
.row
|
||||
%fieldset#order_summary{"data-hook" => ""}
|
||||
%legend{align: "center"}= t(:order) + " #" + @order.number
|
||||
|
||||
#order{"data-hook" => ""}
|
||||
- if params.has_key? :checkout_complete
|
||||
%h1= t(:thank_you_for_your_order)
|
||||
|
||||
= render :partial => 'spree/shared/order_details', :locals => { :order => @order }
|
||||
|
||||
= link_to t(:back_to_store), main_app.shop_path, :class => "button"
|
||||
- unless params.has_key? :checkout_complete
|
||||
- if try_spree_current_user && respond_to?(:spree_account_path)
|
||||
= link_to t(:my_account), spree_account_path, :class => "button"
|
||||
97
app/views/spree/shared/_order_details.html.haml
Normal file
97
app/views/spree/shared/_order_details.html.haml
Normal file
@@ -0,0 +1,97 @@
|
||||
.row
|
||||
- if order.has_step?("address")
|
||||
.columns.large-3
|
||||
%h6
|
||||
= t(:shipping_address)
|
||||
= link_to "(#{t(:edit)})", checkout_state_path(:address) unless @order.completed?
|
||||
.address
|
||||
= order.ship_address
|
||||
.columns.large-3
|
||||
%h6
|
||||
= t(:billing_address)
|
||||
= link_to "(#{t(:edit)})", checkout_state_path(:address) unless @order.completed?
|
||||
.address
|
||||
= order.bill_address
|
||||
- if @order.has_step?("delivery")
|
||||
.columns.large-2
|
||||
%h6
|
||||
= t(:shipping_method)
|
||||
\:
|
||||
= link_to "(#{t(:edit)})", checkout_state_path(:delivery) unless @order.completed?
|
||||
.delivery
|
||||
= order.shipping_method.name
|
||||
.columns.large-4
|
||||
%h6
|
||||
= t(:payment_information)
|
||||
= link_to "(#{t(:edit)})", checkout_state_path(:payment) unless @order.completed?
|
||||
.payment-info
|
||||
= render order.payments.valid
|
||||
|
||||
%hr/
|
||||
|
||||
%table#line-items{"data-hook" => "order_details"}
|
||||
%col{halign: "center", valign: "middle", width: "15%"}/
|
||||
%col{valign: "middle", width: "70%"}/
|
||||
%col{halign: "center", valign: "middle", width: "5%"}/
|
||||
%col{halign: "center", valign: "middle", width: "5%"}/
|
||||
%col{halign: "center", valign: "middle", width: "5%"}/
|
||||
%thead{"data-hook" => ""}
|
||||
%tr{"data-hook" => "order_details_line_items_headers"}
|
||||
%th{colspan: "2"}= t(:item)
|
||||
%th.price= t(:price)
|
||||
%th.qty= t(:qty)
|
||||
%th.total
|
||||
%span= t(:total)
|
||||
%tbody{"data-hook" => ""}
|
||||
- @order.line_items.each do |item|
|
||||
%tr{"data-hook" => "order_details_line_item_row"}
|
||||
%td{"data-hook" => "order_item_image"}
|
||||
- if item.variant.images.length == 0
|
||||
= link_to small_image(item.variant.product), item.variant.product
|
||||
- else
|
||||
= link_to image_tag(item.variant.images.first.attachment.url(:small)), item.variant.product
|
||||
%td{"data-hook" => "order_item_description"}
|
||||
%h4= item.variant.product.name
|
||||
= truncated_product_description(item.variant.product)
|
||||
= "(" + item.variant.options_text + ")" unless item.variant.option_values.empty?
|
||||
%td.price{"data-hook" => "order_item_price"}
|
||||
%span= item.single_money.to_html
|
||||
%td{"data-hook" => "order_item_qty"}= item.quantity
|
||||
%td.total{"data-hook" => "order_item_total"}
|
||||
%span= item.display_amount.to_html
|
||||
|
||||
%tfoot#order-total{"data-hook" => "order_details_total"}
|
||||
%tr.total
|
||||
%td{colspan: "4"}
|
||||
%b
|
||||
= t(:order_total)
|
||||
\:
|
||||
%td.total
|
||||
%span#order_total= @order.display_total.to_html
|
||||
|
||||
- if order.price_adjustment_totals.present?
|
||||
%tfoot#price-adjustments{"data-hook" => "order_details_price_adjustments"}
|
||||
- @order.price_adjustment_totals.each do |key, total|
|
||||
%tr.total
|
||||
%td{colspan: "4"}
|
||||
%strong
|
||||
= key
|
||||
\:
|
||||
%td.total
|
||||
%span= total
|
||||
|
||||
%tfoot#subtotal{"data-hook" => "order_details_subtotal"}
|
||||
%tr#subtotal-row.total
|
||||
%td{colspan: "4"}
|
||||
%b
|
||||
Produce:
|
||||
%td.total
|
||||
%span= @order.display_item_total.to_html
|
||||
|
||||
%tfoot#order-charges{"data-hook" => "order_details_adjustments"}
|
||||
- checkout_adjustments_for_summary(@order).reverse_each do |adjustment|
|
||||
%tr.total
|
||||
%td{:colspan => "4"}
|
||||
%strong= adjustment.label + ":"
|
||||
%td.total
|
||||
%span= adjustment.display_amount.to_html
|
||||
@@ -37,3 +37,6 @@ Openfoodnetwork::Application.configure do
|
||||
# Print deprecation notices to the stderr
|
||||
config.active_support.deprecation = :stderr
|
||||
end
|
||||
|
||||
# Allows us to use _url helpers in Rspec
|
||||
Rails.application.routes.default_url_options[:host] = 'test.host'
|
||||
|
||||
@@ -13,6 +13,8 @@ Openfoodnetwork::Application.routes.draw do
|
||||
#end
|
||||
get '/checkout', :to => 'checkout#edit' , :as => :checkout
|
||||
put '/checkout', :to => 'checkout#update' , :as => :update_checkout
|
||||
|
||||
get "/checkout/paypal_payment", to: 'checkout#paypal_payment', as: :paypal_payment
|
||||
end
|
||||
|
||||
resources :enterprises do
|
||||
|
||||
43
doc/outstanding_shopping_tests
Normal file
43
doc/outstanding_shopping_tests
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
|
||||
Checkout:
|
||||
it "displays correct distribution charges on checkout"
|
||||
it "sends a confirmation email on successful checkout"
|
||||
it "copies the addresses from a previous order" (controller test)
|
||||
|
||||
Cart:
|
||||
it "displays correct distribution charges on the cart"
|
||||
|
||||
Shop:
|
||||
it "shows nothing when there is no future order cycle"
|
||||
scenario "order cycle expires mid-order" (see below)
|
||||
|
||||
it "does not allow the user to add a product from a distributor that cannot supply the cart's products"
|
||||
|
||||
|
||||
scenario "order cycle expires mid-order" do
|
||||
d = create(:distributor_enterprise,
|
||||
name: 'Green Grass', email: 'd@example.com', phone: '1029 3847')
|
||||
create_enterprise_group_for d
|
||||
p = create(:simple_product)
|
||||
oc = create(:simple_order_cycle, name: 'oc', distributors: [d], variants: [p.master])
|
||||
|
||||
# When I select an order cycle and add a product to my cart
|
||||
visit spree.root_path
|
||||
click_link 'Green Grass'
|
||||
visit enterprise_path d
|
||||
click_link p.name
|
||||
click_button 'Add To Cart'
|
||||
|
||||
# And the order cycle expires and I load a page
|
||||
Timecop.travel(oc.orders_close_at + 1.day) do
|
||||
|
||||
visit enterprise_path d
|
||||
|
||||
# Then I should see an expiry message
|
||||
page.should have_content "Sorry, orders for this order cycle closed 1 day ago! Please contact your hub directly to see if they can accept late orders."
|
||||
page.should have_content d.email
|
||||
page.should have_content d.phone
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ feature %q{
|
||||
As a consumer
|
||||
I want to select a distributor for collection
|
||||
So that I can pick up orders from the closest possible location
|
||||
} do
|
||||
}, skip: true do
|
||||
include AuthenticationWorkflow
|
||||
include WebHelper
|
||||
|
||||
@@ -92,7 +92,7 @@ feature %q{
|
||||
# When I add some apples and some garlic to my cart
|
||||
click_link 'Fuji apples'
|
||||
click_button 'Add To Cart'
|
||||
click_link 'Continue shopping'
|
||||
visit enterprise_path @distributor1
|
||||
|
||||
click_link 'Garlic'
|
||||
click_button 'Add To Cart'
|
||||
@@ -112,11 +112,12 @@ feature %q{
|
||||
# And I am logged in
|
||||
login_to_consumer_section
|
||||
click_link "FruitAndVeg"
|
||||
visit enterprise_path @distributor1
|
||||
|
||||
# When I add some bananas and zucchini to my cart
|
||||
click_link 'Bananas'
|
||||
click_button 'Add To Cart'
|
||||
click_link 'Continue shopping'
|
||||
visit enterprise_path @distributor1
|
||||
|
||||
click_link 'Zucchini'
|
||||
click_button 'Add To Cart'
|
||||
@@ -355,14 +356,18 @@ feature %q{
|
||||
|
||||
login_to_consumer_section
|
||||
click_link 'FruitAndVeg'
|
||||
visit enterprise_path @distributor1
|
||||
|
||||
click_link 'Bananas'
|
||||
click_button 'Add To Cart'
|
||||
click_link 'Continue shopping'
|
||||
visit enterprise_path @distributor1
|
||||
|
||||
click_link 'Zucchini'
|
||||
click_button 'Add To Cart'
|
||||
find('#checkout-link').click
|
||||
|
||||
# And manually visit the old checkout
|
||||
visit "/checkout"
|
||||
|
||||
# -- Checkout: Address
|
||||
fill_in_fields('order_bill_address_attributes_firstname' => 'Joe',
|
||||
@@ -407,7 +412,7 @@ feature %q{
|
||||
# -- Checkout: Order complete
|
||||
page.should have_content 'Your order has been processed successfully'
|
||||
page.should have_content @payment_method_distributor_oc.description
|
||||
page.should have_selector 'figure#logo h1', text: @distributor_oc.name
|
||||
page.should have_content @distributor_oc.name
|
||||
|
||||
page.should have_selector 'tfoot#order-charges tr.total td', text: 'Distribution'
|
||||
page.should have_selector 'tfoot#order-charges tr.total td', text: '51.00'
|
||||
@@ -433,16 +438,18 @@ feature %q{
|
||||
country: Spree::Country.find_by_name('Australia')))
|
||||
|
||||
click_link 'FruitAndVeg'
|
||||
click_link 'Logout'
|
||||
click_link 'Sign Out'
|
||||
click_link 'FruitAndVeg'
|
||||
visit enterprise_path @distributor1
|
||||
|
||||
click_link 'Bananas'
|
||||
click_button 'Add To Cart'
|
||||
click_link 'Continue shopping'
|
||||
visit enterprise_path @distributor1
|
||||
|
||||
click_link 'Zucchini'
|
||||
click_button 'Add To Cart'
|
||||
find('#checkout-link').click
|
||||
visit "/checkout" # Force to old checkout
|
||||
|
||||
# -- Login
|
||||
# We perform login inline because:
|
||||
@@ -451,6 +458,7 @@ feature %q{
|
||||
fill_in 'spree_user_email', :with => 'someone@ofn.org'
|
||||
fill_in 'spree_user_password', :with => 'passw0rd'
|
||||
click_button 'Login'
|
||||
visit "/checkout" # Force to old checkout
|
||||
|
||||
# -- Checkout: Address
|
||||
page.should have_field 'order_bill_address_attributes_firstname', with: 'Joe'
|
||||
@@ -461,44 +469,6 @@ feature %q{
|
||||
page.should have_field 'order_bill_address_attributes_phone', with: '12999911111'
|
||||
page.should have_select 'order_bill_address_attributes_state_id', selected: 'Victoria'
|
||||
page.should have_select 'order_bill_address_attributes_country_id', selected: 'Australia'
|
||||
|
||||
# Distributor details should be displayed
|
||||
within('fieldset#shipping') do
|
||||
[@distributor_oc.name,
|
||||
@distributor_oc.distributor_info,
|
||||
@distributor_oc.next_collection_at
|
||||
].each do |value|
|
||||
|
||||
page.should have_content value
|
||||
end
|
||||
end
|
||||
|
||||
# Disabled until this form takes order cycles into account
|
||||
# page.should have_selector "select#order_distributor_id option[value='#{@distributor_alternative.id}']"
|
||||
|
||||
click_checkout_continue_button
|
||||
|
||||
# -- Checkout: Delivery
|
||||
order_charges = page.all("tbody#summary-order-charges tr").map {|row| row.all('td').map(&:text)}.take(2)
|
||||
order_charges.should == [["Distribution:", "$51.00"]]
|
||||
click_checkout_continue_button
|
||||
|
||||
# -- Checkout: Payment
|
||||
# Given the distributor I have selected for my order, I should only see payment methods valid for that distributor
|
||||
page.should have_selector 'label', :text => @payment_method_distributor_oc.name
|
||||
page.should_not have_selector 'label', :text => @payment_method_alternative.name
|
||||
click_checkout_continue_button
|
||||
|
||||
# -- Checkout: Order complete
|
||||
page.should have_content 'Your order has been processed successfully'
|
||||
page.should have_content @payment_method_distributor_oc.description
|
||||
|
||||
page.should have_selector 'tfoot#order-charges tr.total td', text: 'Distribution'
|
||||
page.should have_selector 'tfoot#order-charges tr.total td', text: '51.00'
|
||||
|
||||
# -- Checkout: Email
|
||||
email = ActionMailer::Base.deliveries.last
|
||||
email.body.should =~ /Distribution[\s+]\$51.00/
|
||||
end
|
||||
|
||||
|
||||
@@ -529,6 +499,7 @@ feature %q{
|
||||
|
||||
# Distributors
|
||||
distributor1 = FactoryGirl.create(:distributor_enterprise, name: "FruitAndVeg")
|
||||
@distributor1 = distributor1
|
||||
distributor2 = FactoryGirl.create(:distributor_enterprise, name: "MoreFreshStuff")
|
||||
create_enterprise_group_for distributor1
|
||||
distributor_fee1 = create(:enterprise_fee, enterprise: distributor1, fee_type: 'packing', amount: 7)
|
||||
@@ -37,15 +37,63 @@ describe Shop::CheckoutController do
|
||||
response.should be_success
|
||||
end
|
||||
|
||||
it "doesn't copy the previous shipping address from a pickup order" do
|
||||
old_order = create(:order, bill_address: create(:address), ship_address: create(:address))
|
||||
old_order.shipping_method.stub_chain(:andand, :require_ship_address).and_return(false)
|
||||
Spree::Order.stub_chain(:order, :where, :where, :limit, :detect).and_return(old_order)
|
||||
|
||||
controller.send(:find_last_used_addresses, "email").last.should == nil
|
||||
end
|
||||
|
||||
describe "building the order" do
|
||||
before do
|
||||
controller.stub(:current_distributor).and_return(distributor)
|
||||
controller.stub(:current_order_cycle).and_return(order_cycle)
|
||||
controller.stub(:current_order).and_return(order)
|
||||
end
|
||||
it "does not clone the ship address from distributor" do
|
||||
it "does not clone the ship address from distributor when shipping method requires address" do
|
||||
get :edit
|
||||
assigns[:order].ship_address.address1.should be_nil
|
||||
end
|
||||
|
||||
it "clears the ship address when re-rendering edit" do
|
||||
controller.should_receive(:clear_ship_address).and_return true
|
||||
order.stub(:update_attributes).and_return false
|
||||
spree_post :update, order: {}
|
||||
end
|
||||
|
||||
it "clears the ship address when the order state cannot be advanced" do
|
||||
controller.should_receive(:clear_ship_address).and_return true
|
||||
order.stub(:update_attributes).and_return true
|
||||
order.stub(:next).and_return false
|
||||
spree_post :update, order: {}
|
||||
end
|
||||
|
||||
it "only clears the ship address with a pickup shipping method" do
|
||||
order.stub_chain(:shipping_method, :andand, :require_ship_address).and_return false
|
||||
order.should_receive(:ship_address=)
|
||||
controller.send(:clear_ship_address)
|
||||
end
|
||||
end
|
||||
|
||||
describe "Paypal routing" do
|
||||
let(:payment_method) { create(:payment_method, type: "Spree::BillingIntegration::PaypalExpress") }
|
||||
before do
|
||||
controller.stub(:current_distributor).and_return(distributor)
|
||||
controller.stub(:current_order_cycle).and_return(order_cycle)
|
||||
controller.stub(:current_order).and_return(order)
|
||||
end
|
||||
|
||||
it "should check the payment method for Paypalness if we've selected one" do
|
||||
Spree::PaymentMethod.should_receive(:find).with(payment_method.id.to_s).and_return payment_method
|
||||
order.stub(:update_attributes).and_return true
|
||||
order.stub(:state).and_return "payment"
|
||||
spree_post :update, order: {payments_attributes: [{payment_method_id: payment_method.id}]}
|
||||
end
|
||||
|
||||
it "should override the cancel return url" do
|
||||
controller.stub(:params).and_return({payment_method_id: payment_method.id})
|
||||
controller.send(:order_opts, order, payment_method.id, 'payment')[:cancel_return_url].should == shop_checkout_url
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -42,7 +42,7 @@ describe Shop::ShopController do
|
||||
it "should return the order cycle details when the oc is selected" do
|
||||
oc1 = create(:order_cycle, distributors: [d])
|
||||
oc2 = create(:order_cycle, distributors: [d])
|
||||
|
||||
|
||||
spree_post :order_cycle, order_cycle_id: oc2.id
|
||||
response.should be_success
|
||||
response.body.should have_content oc2.id
|
||||
@@ -77,11 +77,6 @@ describe Shop::ShopController do
|
||||
exchange = Exchange.find(order_cycle.exchanges.to_enterprises(d).outgoing.first.id)
|
||||
exchange.variants << product.master
|
||||
end
|
||||
|
||||
it "builds a list of producers/suppliers" do
|
||||
spree_get :show
|
||||
assigns[:producers].should == [supplier]
|
||||
end
|
||||
end
|
||||
|
||||
describe "returning products" do
|
||||
|
||||
@@ -173,12 +173,12 @@ describe Spree::Admin::ReportsController do
|
||||
|
||||
it "builds suppliers for the current user" do
|
||||
spree_get :products_and_inventory
|
||||
assigns(:suppliers).should == [s1, s2, s3]
|
||||
assigns(:suppliers).sort.should == [s1, s2, s3].sort
|
||||
end
|
||||
|
||||
it "builds order cycles for the current user" do
|
||||
spree_get :products_and_inventory
|
||||
assigns(:order_cycles).should == [ocB, ocA]
|
||||
assigns(:order_cycles).sort.should == [ocB, ocA].sort
|
||||
end
|
||||
|
||||
it "assigns report types" do
|
||||
@@ -216,7 +216,7 @@ describe Spree::Admin::ReportsController do
|
||||
|
||||
it "should build distributors for the current user" do
|
||||
spree_get :customers
|
||||
assigns(:distributors).should == [d1, d2, d3]
|
||||
assigns(:distributors).sort.should == [d1, d2, d3].sort
|
||||
end
|
||||
|
||||
it "builds suppliers for the current user" do
|
||||
@@ -226,7 +226,7 @@ describe Spree::Admin::ReportsController do
|
||||
|
||||
it "builds order cycles for the current user" do
|
||||
spree_get :customers
|
||||
assigns(:order_cycles).should == [ocB, ocA]
|
||||
assigns(:order_cycles).sort.should == [ocB, ocA].sort
|
||||
end
|
||||
|
||||
it "assigns report types" do
|
||||
|
||||
@@ -34,7 +34,7 @@ feature %q{
|
||||
page.should have_text "No matching line items found."
|
||||
end
|
||||
|
||||
context "displaying the list of line items " do
|
||||
context "displaying the list of line items" do
|
||||
let!(:o1) { FactoryGirl.create(:order, state: 'complete', completed_at: Time.now ) }
|
||||
let!(:o2) { FactoryGirl.create(:order, state: 'complete', completed_at: Time.now ) }
|
||||
let!(:o3) { FactoryGirl.create(:order, state: 'address', completed_at: nil ) }
|
||||
@@ -559,4 +559,4 @@ feature %q{
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -97,8 +97,8 @@ feature %q{
|
||||
|
||||
visit '/admin/products/bulk_edit'
|
||||
|
||||
page.should have_field "price", with: "22.0"
|
||||
page.should have_field "price", with: "44.0"
|
||||
page.should have_field "price", with: "22.0"
|
||||
page.should have_field "price", with: "44.0"
|
||||
page.should_not have_field "price", with: "66.0", visible: true
|
||||
end
|
||||
|
||||
|
||||
@@ -84,9 +84,6 @@ feature %q{
|
||||
select('Australia', :from => 'enterprise_address_attributes_country_id')
|
||||
select('Victoria', :from => 'enterprise_address_attributes_state_id')
|
||||
|
||||
fill_in 'enterprise_pickup_times', :with => 'Thursday, 22nd Feb, 6 - 9 PM. Friday, 23nd Feb, 6 - 9 PM'
|
||||
fill_in 'enterprise_next_collection_at', :with => 'Thursday, 22nd Feb, 6 - 9 PM'
|
||||
|
||||
click_button 'Create'
|
||||
flash_message.should == 'Enterprise "Eaterprises" has been successfully created!'
|
||||
end
|
||||
@@ -124,9 +121,6 @@ feature %q{
|
||||
select('Australia', :from => 'enterprise_address_attributes_country_id')
|
||||
select('Victoria', :from => 'enterprise_address_attributes_state_id')
|
||||
|
||||
fill_in 'enterprise_pickup_times', :with => 'Thursday, 22nd Feb, 6 - 9 PM. Friday, 23nd Feb, 6 - 9 PM'
|
||||
fill_in 'enterprise_next_collection_at', :with => 'Thursday, 22nd Feb, 6 - 9 PM'
|
||||
|
||||
click_button 'Update'
|
||||
|
||||
flash_message.should == 'Enterprise "Eaterprises" has been successfully updated!'
|
||||
|
||||
@@ -269,7 +269,7 @@ feature %q{
|
||||
click_button 'Add supplier'
|
||||
page.all("table.exchanges tr.supplier td.products input").each { |e| e.click }
|
||||
|
||||
uncheck "order_cycle_incoming_exchange_1_variants_#{initial_variants.last.id}"
|
||||
page.find("#order_cycle_incoming_exchange_1_variants_#{initial_variants.last.id}", visible: true).click # uncheck (with visible:true filter)
|
||||
check "order_cycle_incoming_exchange_2_variants_#{v1.id}"
|
||||
check "order_cycle_incoming_exchange_2_variants_#{v2.id}"
|
||||
|
||||
@@ -391,7 +391,33 @@ feature %q{
|
||||
end
|
||||
|
||||
|
||||
context 'as an Enterprise user' do
|
||||
scenario "removing a master variant from an order cycle when further variants have been added" do
|
||||
# Given a product with a variant, with its master variant included in the order cycle
|
||||
# (this usually happens when a product is added to an order cycle, then variants are added
|
||||
# to the product after the fact)
|
||||
s = create(:supplier_enterprise)
|
||||
p = create(:simple_product, supplier: s)
|
||||
v = create(:variant, product: p)
|
||||
d = create(:distributor_enterprise)
|
||||
oc = create(:simple_order_cycle, suppliers: [s], distributors: [d], variants: [p.master])
|
||||
exchange_ids = oc.exchanges.pluck :id
|
||||
ExchangeVariant.where(exchange_id: exchange_ids, variant_id: p.master.id).should_not be_empty
|
||||
|
||||
# When I go to the order cycle page and remove the obsolete master
|
||||
login_to_admin_section
|
||||
click_link 'Order Cycles'
|
||||
click_link oc.name
|
||||
within("table.exchanges tbody tr.supplier") { page.find('td.products input').click }
|
||||
page.find("#order_cycle_incoming_exchange_0_variants_#{p.master.id}", visible: true).click # uncheck
|
||||
click_button "Update"
|
||||
|
||||
# Then the master variant should have been removed from all exchanges
|
||||
page.should have_content "Your order cycle has been updated."
|
||||
ExchangeVariant.where(exchange_id: exchange_ids, variant_id: p.master.id).should be_empty
|
||||
end
|
||||
|
||||
|
||||
context "as an enterprise user" do
|
||||
|
||||
let(:supplier1) { create(:supplier_enterprise, name: 'First Supplier') }
|
||||
let(:supplier2) { create(:supplier_enterprise, name: 'Another Supplier') }
|
||||
|
||||
@@ -13,7 +13,7 @@ feature %q{
|
||||
@enterprise_fees = (0..2).map { |i| create(:enterprise_fee, enterprise: @distributors[i]) }
|
||||
end
|
||||
|
||||
context "creating a product" do
|
||||
describe "creating a product" do
|
||||
scenario "assigning a supplier, distributors and units to the product" do
|
||||
login_to_admin_section
|
||||
|
||||
@@ -23,9 +23,6 @@ feature %q{
|
||||
fill_in 'product_name', with: 'A new product !!!'
|
||||
fill_in 'product_price', with: '19.99'
|
||||
select 'New supplier', from: 'product_supplier_id'
|
||||
select 'Weight', from: 'product_variant_unit'
|
||||
fill_in 'product_variant_unit_scale', with: 1000
|
||||
fill_in 'product_variant_unit_name', with: ''
|
||||
|
||||
click_button 'Create'
|
||||
|
||||
@@ -34,11 +31,6 @@ feature %q{
|
||||
product.supplier.should == @supplier
|
||||
product.group_buy.should be_false
|
||||
|
||||
product.variant_unit.should == 'weight'
|
||||
product.variant_unit_scale.should == 1000
|
||||
product.variant_unit_name.should == ''
|
||||
product.option_types.first.name.should == 'unit_weight'
|
||||
|
||||
# Distributors
|
||||
within('#sidebar') { click_link 'Product Distributions' }
|
||||
|
||||
@@ -50,8 +42,8 @@ feature %q{
|
||||
click_button 'Update'
|
||||
|
||||
product.reload
|
||||
product.distributors.should == [@distributors[0], @distributors[2]]
|
||||
product.product_distributions.map { |pd| pd.enterprise_fee }.should == [@enterprise_fees[0], @enterprise_fees[2]]
|
||||
product.distributors.sort.should == [@distributors[0], @distributors[2]].sort
|
||||
product.product_distributions.map { |pd| pd.enterprise_fee }.sort.should == [@enterprise_fees[0], @enterprise_fees[2]].sort
|
||||
end
|
||||
|
||||
|
||||
@@ -74,76 +66,109 @@ feature %q{
|
||||
product.group_buy.should be_true
|
||||
product.group_buy_unit_size.should == 10.0
|
||||
end
|
||||
end
|
||||
|
||||
context "as an enterprise user" do
|
||||
|
||||
before(:each) do
|
||||
@new_user = create_enterprise_user
|
||||
@supplier2 = create(:supplier_enterprise, name: 'Another Supplier')
|
||||
@new_user.enterprise_roles.build(enterprise: @supplier2).save
|
||||
@new_user.enterprise_roles.build(enterprise: @distributors[0]).save
|
||||
|
||||
login_to_admin_as @new_user
|
||||
end
|
||||
|
||||
|
||||
context "as an enterprise user" do
|
||||
|
||||
before(:each) do
|
||||
@new_user = create_enterprise_user
|
||||
@supplier2 = create(:supplier_enterprise, name: 'Another Supplier')
|
||||
@new_user.enterprise_roles.build(enterprise: @supplier2).save
|
||||
@new_user.enterprise_roles.build(enterprise: @distributors[0]).save
|
||||
|
||||
login_to_admin_as @new_user
|
||||
end
|
||||
|
||||
|
||||
context "Additional fields" do
|
||||
#let(:product) { create(:simple_product, supplier: @supplier2) }
|
||||
|
||||
it "should have a notes field" do
|
||||
product = create(:simple_product, supplier: @supplier2)
|
||||
click_link 'Products'
|
||||
within('#sub_nav') { click_link 'Products' }
|
||||
click_link product.name
|
||||
page.should have_content "Notes"
|
||||
end
|
||||
end
|
||||
|
||||
scenario "create new product" do
|
||||
click_link 'Products'
|
||||
click_link 'New Product'
|
||||
|
||||
fill_in 'product_name', :with => 'A new product !!!'
|
||||
fill_in 'product_price', :with => '19.99'
|
||||
|
||||
page.should have_selector('#product_supplier_id')
|
||||
select 'Another Supplier', :from => 'product_supplier_id'
|
||||
|
||||
# Should only have suppliers listed which the user can manage
|
||||
within "#product_supplier_id" do
|
||||
page.should_not have_content @supplier.name
|
||||
end
|
||||
|
||||
click_button 'Create'
|
||||
|
||||
flash_message.should == 'Product "A new product !!!" has been successfully created!'
|
||||
product = Spree::Product.find_by_name('A new product !!!')
|
||||
product.supplier.should == @supplier2
|
||||
end
|
||||
|
||||
scenario "editing product distributions" do
|
||||
context "additional fields" do
|
||||
it "should have a notes field" do
|
||||
product = create(:simple_product, supplier: @supplier2)
|
||||
|
||||
click_link 'Products'
|
||||
within('#sub_nav') { click_link 'Products' }
|
||||
click_link product.name
|
||||
within('#sidebar') { click_link 'Product Distributions' }
|
||||
|
||||
check @distributors[0].name
|
||||
select @enterprise_fees[0].name, :from => 'product_product_distributions_attributes_0_enterprise_fee_id'
|
||||
|
||||
# Should only have distributors listed which the user can manage
|
||||
within "#product_product_distributions_field" do
|
||||
page.should_not have_content @distributors[1].name
|
||||
page.should_not have_content @distributors[2].name
|
||||
end
|
||||
|
||||
click_button 'Update'
|
||||
flash_message.should == "Product \"#{product.name}\" has been successfully updated!"
|
||||
|
||||
product.distributors.should == [@distributors[0]]
|
||||
page.should have_content "Notes"
|
||||
end
|
||||
end
|
||||
|
||||
scenario "creating a new product" do
|
||||
click_link 'Products'
|
||||
click_link 'New Product'
|
||||
|
||||
fill_in 'product_name', :with => 'A new product !!!'
|
||||
fill_in 'product_price', :with => '19.99'
|
||||
|
||||
page.should have_selector('#product_supplier_id')
|
||||
select 'Another Supplier', :from => 'product_supplier_id'
|
||||
|
||||
# Should only have suppliers listed which the user can manage
|
||||
within "#product_supplier_id" do
|
||||
page.should_not have_content @supplier.name
|
||||
end
|
||||
|
||||
click_button 'Create'
|
||||
|
||||
flash_message.should == 'Product "A new product !!!" has been successfully created!'
|
||||
product = Spree::Product.find_by_name('A new product !!!')
|
||||
product.supplier.should == @supplier2
|
||||
end
|
||||
|
||||
scenario "editing product distributions" do
|
||||
product = create(:simple_product, supplier: @supplier2)
|
||||
|
||||
click_link 'Products'
|
||||
within('#sub_nav') { click_link 'Products' }
|
||||
click_link product.name
|
||||
within('#sidebar') { click_link 'Product Distributions' }
|
||||
|
||||
check @distributors[0].name
|
||||
select @enterprise_fees[0].name, :from => 'product_product_distributions_attributes_0_enterprise_fee_id'
|
||||
|
||||
# Should only have distributors listed which the user can manage
|
||||
within "#product_product_distributions_field" do
|
||||
page.should_not have_content @distributors[1].name
|
||||
page.should_not have_content @distributors[2].name
|
||||
end
|
||||
|
||||
click_button 'Update'
|
||||
flash_message.should == "Product \"#{product.name}\" has been successfully updated!"
|
||||
|
||||
product.distributors.should == [@distributors[0]]
|
||||
end
|
||||
|
||||
|
||||
scenario "deleting product properties", js: true do
|
||||
# Given a product with a property
|
||||
p = create(:simple_product, supplier: @supplier)
|
||||
p.set_property('fooprop', 'fooval')
|
||||
|
||||
# When I navigate to the product properties page
|
||||
visit spree.admin_product_product_properties_path(p)
|
||||
page.should have_field 'product_product_properties_attributes_0_property_name', with: 'fooprop', visible: true
|
||||
page.should have_field 'product_product_properties_attributes_0_value', with: 'fooval', visible: true
|
||||
|
||||
# And I delete the property
|
||||
page.all('a.remove_fields').first.click
|
||||
wait_until { p.reload.property('fooprop').nil? }
|
||||
|
||||
# Then the property should have been deleted
|
||||
page.should_not have_field 'product_product_properties_attributes_0_property_name', with: 'fooprop', visible: true
|
||||
page.should_not have_field 'product_product_properties_attributes_0_value', with: 'fooval', visible: true
|
||||
end
|
||||
|
||||
|
||||
scenario "deleting product images", js: true do
|
||||
product = create(:simple_product, supplier: @supplier2)
|
||||
image = File.open(File.expand_path('../../../../app/assets/images/logo.jpg', __FILE__))
|
||||
Spree::Image.create({:viewable_id => product.master.id, :viewable_type => 'Spree::Variant', :alt => "position 1", :attachment => image, :position => 1})
|
||||
|
||||
visit spree.admin_product_images_path(product)
|
||||
page.should have_selector "table[data-hook='images_table'] td img", visible: true
|
||||
product.reload.images.count.should == 1
|
||||
|
||||
page.find('a.delete-resource').click
|
||||
wait_until { product.reload.images.count == 0 }
|
||||
|
||||
page.should_not have_selector "table[data-hook='images_table'] td img", visible: true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -83,34 +83,4 @@ feature %q{
|
||||
page.should_not have_field "variant_unit_value"
|
||||
page.should_not have_field "variant_unit_description"
|
||||
end
|
||||
|
||||
|
||||
context "as an enterprise user" do
|
||||
before(:each) do
|
||||
@new_user = create_enterprise_user
|
||||
@supplier = create(:supplier_enterprise)
|
||||
@new_user.enterprise_roles.build(enterprise: @supplier).save
|
||||
|
||||
login_to_admin_as @new_user
|
||||
end
|
||||
|
||||
scenario "deleting product properties", js: true do
|
||||
# Given a product with a property
|
||||
p = create(:simple_product, supplier: @supplier)
|
||||
p.set_property('fooprop', 'fooval')
|
||||
|
||||
# When I navigate to the product properties page
|
||||
visit spree.admin_product_product_properties_path(p)
|
||||
page.should have_field 'product_product_properties_attributes_0_property_name', with: 'fooprop', visible: true
|
||||
page.should have_field 'product_product_properties_attributes_0_value', with: 'fooval', visible: true
|
||||
|
||||
# And I delete the property
|
||||
page.all('a.remove_fields').first.click
|
||||
wait_until { p.reload.property('fooprop').nil? }
|
||||
|
||||
# Then the property should have been deleted
|
||||
page.should_not have_field 'product_product_properties_attributes_0_property_name', with: 'fooprop', visible: true
|
||||
page.should_not have_field 'product_product_properties_attributes_0_value', with: 'fooval', visible: true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user