Merge branch 'master' into bom

This commit is contained in:
Rob H
2014-03-21 13:47:50 +11:00
129 changed files with 1603 additions and 1629 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -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

View File

@@ -8,8 +8,9 @@
#
#= require ../shared/jquery.timeago
#= require foundation
#= require ./shop
#= require ./darkswarm
#= require_tree .
$ ->
$(document).foundation()
$(document).foundation('reveal', {animation: 'fade'})

View 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

View File

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

View File

@@ -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()

View File

@@ -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

View File

@@ -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()

View File

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

View File

@@ -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 != ""

View File

@@ -0,0 +1,3 @@
window.SignupSidebarCtrl = Darkswarm.controller "SignupSidebarCtrl", ($scope) ->
$scope.active = ->
$scope.active_sidebar == '/signup'

View 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, */*"

View File

@@ -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: ->

View File

@@ -1,4 +1,4 @@
Shop.factory 'Product', ($resource) ->
Darkswarm.factory 'Product', ($resource) ->
new class Product
data: {
products: null

View File

@@ -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 || ""

View File

@@ -5,4 +5,4 @@ $(document).ready ->
$('th.cart-adjustment-header a').click ->
$('#cart_adjustments').toggle()
$('th.cart-adjustment-header a').html('Distribution')
false
false

View File

@@ -126,3 +126,10 @@ table#listing_enterprise_groups {
text-align: left;
}
}
.fullwidth_inputs {
input[type=text], select {
width: 100%;
}
}

View File

@@ -7,5 +7,3 @@
*= require foundation
*= require_tree .
*/

View File

@@ -1,2 +1,6 @@
checkout
display: block
orderdetails
.button, table
width: 100%

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

View File

@@ -1,2 +1,5 @@
.row
max-width: 74em
.reveal-modal
position: fixed

View File

@@ -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

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

View File

@@ -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

View File

@@ -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"

View File

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

View File

@@ -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

View File

@@ -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

View File

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

View File

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

View File

@@ -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

View File

@@ -1,5 +1,21 @@
module HtmlHelper
def strip_html(html)
strip_tags(html).andand.gsub(/&nbsp;/i, ' ').andand.gsub(/&amp;/i, '&')
strip_surrounding_whitespace substitute_entities strip_tags add_linebreaks html
end
def substitute_entities(html)
html.andand.gsub(/&nbsp;/i, ' ').andand.gsub(/&amp;/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

View File

@@ -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

View File

@@ -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

View File

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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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'

View File

@@ -1,3 +0,0 @@
/ replace_contents "[data-hook='long_description']"
%td Profile Info:
%td= f.text_area :long_description, :class => 'rich_text'

View File

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

View File

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

View File

@@ -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

View File

@@ -1,4 +0,0 @@
/ insert_bottom "[id='clear_cart_link']"
%div
= link_to "Shop in List View", main_app.shop_path

View File

@@ -1,4 +0,0 @@
/ insert_bottom "[data-hook='cart_buttons']"
%div
= link_to "Quick Checkout", main_app.shop_checkout_path

View File

@@ -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

View File

@@ -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 &nbsp;
.omega.ten.columns
= f.check_box :is_primary_producer
= f.label :is_primary_producer, 'Producer'
&nbsp;
= 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 &nbsp;
.omega.three.columns
= af.collection_select(:state_id, af.object.country.states, :id, :name)
.row
.alpha.two.columns &nbsp;
.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

View File

@@ -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 %>

View File

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

View File

@@ -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

View File

@@ -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" : "")}

View File

@@ -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

View File

@@ -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"

View File

@@ -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"

View File

@@ -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'

View 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"

View 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"

View File

@@ -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"

View 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 &#215;
- 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 &#215;

View 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'

View File

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

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View 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

View File

@@ -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

View 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

View File

@@ -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

View 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

View File

@@ -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"}

View File

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

View File

@@ -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),

View File

@@ -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"

View 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

View File

@@ -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'

View 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?

View File

@@ -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'

View 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)}"

View 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"

View 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"

View 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

View File

@@ -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'

View File

@@ -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

View 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

View File

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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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!'

View File

@@ -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') }

View File

@@ -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

View File

@@ -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