diff --git a/app/assets/images/noimage/large.png b/app/assets/images/noimage/large.png new file mode 100644 index 0000000000..c9b2af198c Binary files /dev/null and b/app/assets/images/noimage/large.png differ diff --git a/app/assets/images/noimage/mini.png b/app/assets/images/noimage/mini.png new file mode 100644 index 0000000000..dac04c5863 Binary files /dev/null and b/app/assets/images/noimage/mini.png differ diff --git a/app/assets/images/noimage/product.png b/app/assets/images/noimage/product.png new file mode 100644 index 0000000000..44ca117e5f Binary files /dev/null and b/app/assets/images/noimage/product.png differ diff --git a/app/assets/images/noimage/small.png b/app/assets/images/noimage/small.png new file mode 100644 index 0000000000..e8ed5f07d9 Binary files /dev/null and b/app/assets/images/noimage/small.png differ diff --git a/app/assets/javascripts/admin/bulk_product_update.js.coffee b/app/assets/javascripts/admin/bulk_product_update.js.coffee index a1c1e09f7a..7d5ab0a45f 100644 --- a/app/assets/javascripts/admin/bulk_product_update.js.coffee +++ b/app/assets/javascripts/admin/bulk_product_update.js.coffee @@ -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 diff --git a/app/assets/javascripts/darkswarm/all.js.coffee b/app/assets/javascripts/darkswarm/all.js.coffee index 1f2ecf155d..ead3240bf3 100644 --- a/app/assets/javascripts/darkswarm/all.js.coffee +++ b/app/assets/javascripts/darkswarm/all.js.coffee @@ -8,8 +8,9 @@ # #= require ../shared/jquery.timeago #= require foundation -#= require ./shop +#= require ./darkswarm #= require_tree . $ -> $(document).foundation() + $(document).foundation('reveal', {animation: 'fade'}) diff --git a/app/assets/javascripts/darkswarm/cart.js.coffee b/app/assets/javascripts/darkswarm/cart.js.coffee new file mode 100644 index 0000000000..bb68d0d7ec --- /dev/null +++ b/app/assets/javascripts/darkswarm/cart.js.coffee @@ -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('Distribution...') + $('th.cart-adjustment-header a').click -> + $('#cart_adjustments').toggle() + $('th.cart-adjustment-header a').html('Distribution') + false diff --git a/app/assets/javascripts/darkswarm/checkout.js.coffee b/app/assets/javascripts/darkswarm/checkout.js.coffee deleted file mode 100644 index 65bd062d5d..0000000000 --- a/app/assets/javascripts/darkswarm/checkout.js.coffee +++ /dev/null @@ -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') diff --git a/app/assets/javascripts/darkswarm/controllers/checkout_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/checkout_controller.js.coffee index 8349ef1a81..1d0604d76c 100644 --- a/app/assets/javascripts/darkswarm/controllers/checkout_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/checkout_controller.js.coffee @@ -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() + diff --git a/app/assets/javascripts/darkswarm/controllers/login_sidebar_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/login_sidebar_controller.js.coffee new file mode 100644 index 0000000000..5e6d051e93 --- /dev/null +++ b/app/assets/javascripts/darkswarm/controllers/login_sidebar_controller.js.coffee @@ -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 + diff --git a/app/assets/javascripts/darkswarm/controllers/order_cycle_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/order_cycle_controller.js.coffee index d16d31603c..0f7f3cd17f 100644 --- a/app/assets/javascripts/darkswarm/controllers/order_cycle_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/order_cycle_controller.js.coffee @@ -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() diff --git a/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee index 784aed539c..34ec81c5d2 100644 --- a/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee @@ -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) diff --git a/app/assets/javascripts/darkswarm/controllers/sidebar_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/sidebar_controller.js.coffee new file mode 100644 index 0000000000..0aa5f11683 --- /dev/null +++ b/app/assets/javascripts/darkswarm/controllers/sidebar_controller.js.coffee @@ -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 != "" diff --git a/app/assets/javascripts/darkswarm/controllers/signup_sidebar_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/signup_sidebar_controller.js.coffee new file mode 100644 index 0000000000..a577fc6b51 --- /dev/null +++ b/app/assets/javascripts/darkswarm/controllers/signup_sidebar_controller.js.coffee @@ -0,0 +1,3 @@ +window.SignupSidebarCtrl = Darkswarm.controller "SignupSidebarCtrl", ($scope) -> + $scope.active = -> + $scope.active_sidebar == '/signup' diff --git a/app/assets/javascripts/darkswarm/darkswarm.js.coffee b/app/assets/javascripts/darkswarm/darkswarm.js.coffee new file mode 100644 index 0000000000..de8517124f --- /dev/null +++ b/app/assets/javascripts/darkswarm/darkswarm.js.coffee @@ -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, */*" + diff --git a/app/assets/javascripts/darkswarm/services/order_cycle.js.coffee b/app/assets/javascripts/darkswarm/services/order_cycle.js.coffee index 042ea960e4..84d09a9a13 100644 --- a/app/assets/javascripts/darkswarm/services/order_cycle.js.coffee +++ b/app/assets/javascripts/darkswarm/services/order_cycle.js.coffee @@ -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: -> diff --git a/app/assets/javascripts/darkswarm/services/product.js.coffee b/app/assets/javascripts/darkswarm/services/product.js.coffee index f8f139ad32..4140da20fa 100644 --- a/app/assets/javascripts/darkswarm/services/product.js.coffee +++ b/app/assets/javascripts/darkswarm/services/product.js.coffee @@ -1,4 +1,4 @@ -Shop.factory 'Product', ($resource) -> +Darkswarm.factory 'Product', ($resource) -> new class Product data: { products: null diff --git a/app/assets/javascripts/darkswarm/shop.js.coffee b/app/assets/javascripts/darkswarm/shop.js.coffee index 1163859bc9..70917a934d 100644 --- a/app/assets/javascripts/darkswarm/shop.js.coffee +++ b/app/assets/javascripts/darkswarm/shop.js.coffee @@ -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 || "" diff --git a/app/assets/javascripts/store/checkout_adjustments.js.coffee b/app/assets/javascripts/store/checkout_adjustments.js.coffee index c443f7dd5d..35b9d7ff55 100644 --- a/app/assets/javascripts/store/checkout_adjustments.js.coffee +++ b/app/assets/javascripts/store/checkout_adjustments.js.coffee @@ -5,4 +5,4 @@ $(document).ready -> $('th.cart-adjustment-header a').click -> $('#cart_adjustments').toggle() $('th.cart-adjustment-header a').html('Distribution') - false \ No newline at end of file + false diff --git a/app/assets/stylesheets/admin/openfoodnetwork.css.scss b/app/assets/stylesheets/admin/openfoodnetwork.css.scss index 2e03a9e2eb..14feebae0d 100644 --- a/app/assets/stylesheets/admin/openfoodnetwork.css.scss +++ b/app/assets/stylesheets/admin/openfoodnetwork.css.scss @@ -126,3 +126,10 @@ table#listing_enterprise_groups { text-align: left; } } + +.fullwidth_inputs { + input[type=text], select { + width: 100%; + } +} + diff --git a/app/assets/stylesheets/darkswarm/all.scss b/app/assets/stylesheets/darkswarm/all.scss index aaec952184..44e8ea248c 100644 --- a/app/assets/stylesheets/darkswarm/all.scss +++ b/app/assets/stylesheets/darkswarm/all.scss @@ -7,5 +7,3 @@ *= require foundation *= require_tree . */ - - diff --git a/app/assets/stylesheets/darkswarm/checkout.css.sass b/app/assets/stylesheets/darkswarm/checkout.css.sass index c864d4928a..676ab08e43 100644 --- a/app/assets/stylesheets/darkswarm/checkout.css.sass +++ b/app/assets/stylesheets/darkswarm/checkout.css.sass @@ -1,2 +1,6 @@ checkout display: block + + orderdetails + .button, table + width: 100% diff --git a/app/assets/stylesheets/darkswarm/offcanvas.css b/app/assets/stylesheets/darkswarm/offcanvas.css new file mode 100644 index 0000000000..3b823be7a3 --- /dev/null +++ b/app/assets/stylesheets/darkswarm/offcanvas.css @@ -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; } } diff --git a/app/assets/stylesheets/darkswarm/overrides.css.sass b/app/assets/stylesheets/darkswarm/overrides.css.sass index fcec6b455d..917d6dd2e3 100644 --- a/app/assets/stylesheets/darkswarm/overrides.css.sass +++ b/app/assets/stylesheets/darkswarm/overrides.css.sass @@ -1,2 +1,5 @@ .row max-width: 74em + +.reveal-modal + position: fixed diff --git a/app/assets/stylesheets/darkswarm/shop.css.sass b/app/assets/stylesheets/darkswarm/shop.css.sass index 1b9109cfaa..58776a6fd5 100644 --- a/app/assets/stylesheets/darkswarm/shop.css.sass +++ b/app/assets/stylesheets/darkswarm/shop.css.sass @@ -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 diff --git a/app/assets/stylesheets/darkswarm/sidepanel.css.sass b/app/assets/stylesheets/darkswarm/sidepanel.css.sass new file mode 100644 index 0000000000..65b323a2e9 --- /dev/null +++ b/app/assets/stylesheets/darkswarm/sidepanel.css.sass @@ -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) diff --git a/app/assets/stylesheets/darkswarm/tables.css.sass b/app/assets/stylesheets/darkswarm/tables.css.sass index 25c089e22d..885eec815a 100644 --- a/app/assets/stylesheets/darkswarm/tables.css.sass +++ b/app/assets/stylesheets/darkswarm/tables.css.sass @@ -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 diff --git a/app/assets/stylesheets/darkswarm/typography.css.sass b/app/assets/stylesheets/darkswarm/typography.css.sass index a36fbbd828..f4d514b4e4 100644 --- a/app/assets/stylesheets/darkswarm/typography.css.sass +++ b/app/assets/stylesheets/darkswarm/typography.css.sass @@ -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" diff --git a/app/assets/stylesheets/search/temp_landing_page.css.scss b/app/assets/stylesheets/search/temp_landing_page.css.scss index 87f5a969ac..89c5ffd6bb 100644 --- a/app/assets/stylesheets/search/temp_landing_page.css.scss +++ b/app/assets/stylesheets/search/temp_landing_page.css.scss @@ -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; diff --git a/app/controllers/enterprises_controller.rb b/app/controllers/enterprises_controller.rb index d4b6ade04b..d9c285206a 100644 --- a/app/controllers/enterprises_controller.rb +++ b/app/controllers/enterprises_controller.rb @@ -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 diff --git a/app/controllers/shop/checkout_controller.rb b/app/controllers/shop/checkout_controller.rb index 011560e1f5..5a193e392d 100644 --- a/app/controllers/shop/checkout_controller.rb +++ b/app/controllers/shop/checkout_controller.rb @@ -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 diff --git a/app/controllers/shop/shop_controller.rb b/app/controllers/shop/shop_controller.rb index b7f124acfa..1af6ceec87 100644 --- a/app/controllers/shop/shop_controller.rb +++ b/app/controllers/shop/shop_controller.rb @@ -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 } diff --git a/app/controllers/spree/checkout_controller_decorator.rb b/app/controllers/spree/checkout_controller_decorator.rb index 3f83ca10ec..66ca7fb034 100644 --- a/app/controllers/spree/checkout_controller_decorator.rb +++ b/app/controllers/spree/checkout_controller_decorator.rb @@ -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] diff --git a/app/controllers/spree/orders_controller_decorator.rb b/app/controllers/spree/orders_controller_decorator.rb index d080b6bb8e..92211bf6a6 100644 --- a/app/controllers/spree/orders_controller_decorator.rb +++ b/app/controllers/spree/orders_controller_decorator.rb @@ -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 diff --git a/app/helpers/html_helper.rb b/app/helpers/html_helper.rb index c648cf3ace..95b7e5d0db 100644 --- a/app/helpers/html_helper.rb +++ b/app/helpers/html_helper.rb @@ -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(/]*>/, "\\1\n") + end + + def strip_surrounding_whitespace(html) + html.andand.strip end end diff --git a/app/helpers/shared_helper.rb b/app/helpers/shared_helper.rb index 2906a308aa..8ddad2524f 100644 --- a/app/helpers/shared_helper.rb +++ b/app/helpers/shared_helper.rb @@ -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 diff --git a/app/helpers/spree/base_helper_decorator.rb b/app/helpers/spree/base_helper_decorator.rb index 8da5adaeb1..8abdace556 100644 --- a/app/helpers/spree/base_helper_decorator.rb +++ b/app/helpers/spree/base_helper_decorator.rb @@ -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 diff --git a/app/models/exchange.rb b/app/models/exchange.rb index 90db51c36f..66a5894c1e 100644 --- a/app/models/exchange.rb +++ b/app/models/exchange.rb @@ -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) diff --git a/app/models/order_cycle.rb b/app/models/order_cycle.rb index 1f98e8f7c4..a6707d9220 100644 --- a/app/models/order_cycle.rb +++ b/app/models/order_cycle.rb @@ -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 diff --git a/app/models/spree/ability_decorator.rb b/app/models/spree/ability_decorator.rb index 668791f555..83a4e5e0aa 100644 --- a/app/models/spree/ability_decorator.rb +++ b/app/models/spree/ability_decorator.rb @@ -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 diff --git a/app/models/spree/order_decorator.rb b/app/models/spree/order_decorator.rb index e78c5686d5..40c06c3132 100644 --- a/app/models/spree/order_decorator.rb +++ b/app/models/spree/order_decorator.rb @@ -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 diff --git a/app/models/spree/product_decorator.rb b/app/models/spree/product_decorator.rb index 7682720708..7f84913d68 100644 --- a/app/models/spree/product_decorator.rb +++ b/app/models/spree/product_decorator.rb @@ -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 diff --git a/app/models/spree/shipping_method_decorator.rb b/app/models/spree/shipping_method_decorator.rb index bfb4ce2bb6..a9628b3c73 100644 --- a/app/models/spree/shipping_method_decorator.rb +++ b/app/models/spree/shipping_method_decorator.rb @@ -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 diff --git a/app/overrides/admin/enterprises/_form/add_distributor_info.html.haml.deface b/app/overrides/admin/enterprises/_form/add_distributor_info.html.haml.deface deleted file mode 100644 index 83ba814fdb..0000000000 --- a/app/overrides/admin/enterprises/_form/add_distributor_info.html.haml.deface +++ /dev/null @@ -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' diff --git a/app/overrides/admin/enterprises/_form/rename_extended_description.html.haml.deface b/app/overrides/admin/enterprises/_form/rename_extended_description.html.haml.deface deleted file mode 100644 index 43c4db4b84..0000000000 --- a/app/overrides/admin/enterprises/_form/rename_extended_description.html.haml.deface +++ /dev/null @@ -1,3 +0,0 @@ -/ replace_contents "[data-hook='long_description']" -%td Profile Info: -%td= f.text_area :long_description, :class => 'rich_text' diff --git a/app/overrides/rearrange_empty_cart_form.rb b/app/overrides/rearrange_empty_cart_form.rb deleted file mode 100644 index 813173f489..0000000000 --- a/app/overrides/rearrange_empty_cart_form.rb +++ /dev/null @@ -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') \ No newline at end of file diff --git a/app/overrides/rearrange_inside_cart_form.rb b/app/overrides/rearrange_inside_cart_form.rb deleted file mode 100644 index fd4f873ad5..0000000000 --- a/app/overrides/rearrange_inside_cart_form.rb +++ /dev/null @@ -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') diff --git a/app/overrides/spree/admin/products/new/add_unit_form.html.haml.deface b/app/overrides/spree/admin/products/new/add_unit_form.html.haml.deface deleted file mode 100644 index 03021b41d9..0000000000 --- a/app/overrides/spree/admin/products/new/add_unit_form.html.haml.deface +++ /dev/null @@ -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 diff --git a/app/overrides/spree/orders/edit/list_view.html.haml.deface b/app/overrides/spree/orders/edit/list_view.html.haml.deface deleted file mode 100644 index 68416cf87d..0000000000 --- a/app/overrides/spree/orders/edit/list_view.html.haml.deface +++ /dev/null @@ -1,4 +0,0 @@ -/ insert_bottom "[id='clear_cart_link']" - -%div - = link_to "Shop in List View", main_app.shop_path diff --git a/app/overrides/spree/orders/edit/quick_checkout.html.haml.deface b/app/overrides/spree/orders/edit/quick_checkout.html.haml.deface deleted file mode 100644 index c0dd485877..0000000000 --- a/app/overrides/spree/orders/edit/quick_checkout.html.haml.deface +++ /dev/null @@ -1,4 +0,0 @@ -/ insert_bottom "[data-hook='cart_buttons']" - -%div - = link_to "Quick Checkout", main_app.shop_checkout_path diff --git a/app/overrides/spree/shared/_order_details/summarise_distribution_charges.html.haml.deface b/app/overrides/spree/shared/_order_details/summarise_distribution_charges.html.haml.deface deleted file mode 100644 index c4e7ed5dfd..0000000000 --- a/app/overrides/spree/shared/_order_details/summarise_distribution_charges.html.haml.deface +++ /dev/null @@ -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 diff --git a/app/views/admin/enterprises/_form.html.haml b/app/views/admin/enterprises/_form.html.haml index 46e7494355..2d3c728bf0 100644 --- a/app/views/admin/enterprises/_form.html.haml +++ b/app/views/admin/enterprises/_form.html.haml @@ -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 diff --git a/app/views/admin/enterprises/new.html.erb b/app/views/admin/enterprises/new.html.erb index 92682f64d8..890c6009cd 100644 --- a/app/views/admin/enterprises/new.html.erb +++ b/app/views/admin/enterprises/new.html.erb @@ -2,5 +2,6 @@ <%= form_for [main_app, :admin, @enterprise] do |f| %> <%= render :partial => 'form', :locals => { :f => f } %> + <%= render :partial => 'spree/admin/shared/new_resource_links' %> <% end %> diff --git a/app/views/admin/order_cycles/_exchange_supplied_products_form.html.haml b/app/views/admin/order_cycles/_exchange_supplied_products_form.html.haml index 092dfc6033..4523bd8337 100644 --- a/app/views/admin/order_cycles/_exchange_supplied_products_form.html.haml +++ b/app/views/admin/order_cycles/_exchange_supplied_products_form.html.haml @@ -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 }} diff --git a/app/views/admin/order_cycles/_form.html.haml b/app/views/admin/order_cycles/_form.html.haml index f43f4e5a62..e2c0dd3ea9 100644 --- a/app/views/admin/order_cycles/_form.html.haml +++ b/app/views/admin/order_cycles/_form.html.haml @@ -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 diff --git a/app/views/home/temp_landing_page.html.haml b/app/views/home/temp_landing_page.html.haml index d8cc87dc11..3ce57de4bc 100644 --- a/app/views/home/temp_landing_page.html.haml +++ b/app/views/home/temp_landing_page.html.haml @@ -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" : "")} diff --git a/app/views/layouts/darkswarm.html.haml b/app/views/layouts/darkswarm.html.haml index 150ffaac52..5ceb406a58 100644 --- a/app/views/layouts/darkswarm.html.haml +++ b/app/views/layouts/darkswarm.html.haml @@ -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 diff --git a/app/views/shared/_login.html.haml b/app/views/shared/_login.html.haml index 67249aeb26..c46d0f424f 100644 --- a/app/views/shared/_login.html.haml +++ b/app/views/shared/_login.html.haml @@ -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" diff --git a/app/views/shared/_login_panel.html.haml b/app/views/shared/_login_panel.html.haml index 8266eaf0b5..e2b3d561a8 100644 --- a/app/views/shared/_login_panel.html.haml +++ b/app/views/shared/_login_panel.html.haml @@ -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" diff --git a/app/views/shared/_menu.html.haml b/app/views/shared/_menu.html.haml index 65973942b3..1250158386 100644 --- a/app/views/shared/_menu.html.haml +++ b/app/views/shared/_menu.html.haml @@ -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' diff --git a/app/views/shared/_signed_in.html.haml b/app/views/shared/_signed_in.html.haml new file mode 100644 index 0000000000..a0137015b7 --- /dev/null +++ b/app/views/shared/_signed_in.html.haml @@ -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" diff --git a/app/views/shared/_signed_out.html.haml b/app/views/shared/_signed_out.html.haml new file mode 100644 index 0000000000..6c7c4e9d21 --- /dev/null +++ b/app/views/shared/_signed_out.html.haml @@ -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" diff --git a/app/views/shop/_details.html.haml b/app/views/shop/_details.html.haml index 6b77e45a27..73a83fec5a 100644 --- a/app/views/shop/_details.html.haml +++ b/app/views/shop/_details.html.haml @@ -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" diff --git a/app/views/shop/_modals.html.haml b/app/views/shop/_modals.html.haml new file mode 100644 index 0000000000..ea21914397 --- /dev/null +++ b/app/views/shop/_modals.html.haml @@ -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 × + diff --git a/app/views/shop/_tabs.html.haml b/app/views/shop/_tabs.html.haml new file mode 100644 index 0000000000..f5acad4208 --- /dev/null +++ b/app/views/shop/_tabs.html.haml @@ -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' diff --git a/app/views/shop/checkout/_form.html.haml b/app/views/shop/checkout/_form.html.haml index 6213cbf3ac..0445e28eed 100644 --- a/app/views/shop/checkout/_form.html.haml +++ b/app/views/shop/checkout/_form.html.haml @@ -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 } diff --git a/app/views/shop/checkout/_order.rabl b/app/views/shop/checkout/_order.rabl index 237a782d85..09451830fb 100644 --- a/app/views/shop/checkout/_order.rabl +++ b/app/views/shop/checkout/_order.rabl @@ -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 diff --git a/app/views/shop/checkout/_summary.html.haml b/app/views/shop/checkout/_summary.html.haml index edda8bc43a..8acd254d69 100644 --- a/app/views/shop/checkout/_summary.html.haml +++ b/app/views/shop/checkout/_summary.html.haml @@ -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 diff --git a/app/views/shop/checkout/edit.html.haml b/app/views/shop/checkout/edit.html.haml index 5eb6c2bcd4..98cead9b9f 100644 --- a/app/views/shop/checkout/edit.html.haml +++ b/app/views/shop/checkout/edit.html.haml @@ -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" + diff --git a/app/views/shop/shop/_about_us.html.haml b/app/views/shop/shop/_about_us.html.haml index 74ef2eaa47..920a4a8236 100644 --- a/app/views/shop/shop/_about_us.html.haml +++ b/app/views/shop/shop/_about_us.html.haml @@ -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 diff --git a/app/views/shop/shop/_contact.html.haml b/app/views/shop/shop/_contact.html.haml new file mode 100644 index 0000000000..bc5497c173 --- /dev/null +++ b/app/views/shop/shop/_contact.html.haml @@ -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 diff --git a/app/views/shop/shop/_contact_us.html.haml b/app/views/shop/shop/_contact_us.html.haml deleted file mode 100644 index 58a69ed38f..0000000000 --- a/app/views/shop/shop/_contact_us.html.haml +++ /dev/null @@ -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 diff --git a/app/views/shop/shop/_groups.html.haml b/app/views/shop/shop/_groups.html.haml new file mode 100644 index 0000000000..c3837bf635 --- /dev/null +++ b/app/views/shop/shop/_groups.html.haml @@ -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 diff --git a/app/views/shop/shop/_order_cycles.html.haml b/app/views/shop/shop/_order_cycles.html.haml index aff1a3259d..d121bb5fb8 100644 --- a/app/views/shop/shop/_order_cycles.html.haml +++ b/app/views/shop/shop/_order_cycles.html.haml @@ -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 diff --git a/app/views/shop/shop/_producers.html.haml b/app/views/shop/shop/_producers.html.haml new file mode 100644 index 0000000000..834d15d53f --- /dev/null +++ b/app/views/shop/shop/_producers.html.haml @@ -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 diff --git a/app/views/shop/shop/_products.html.haml b/app/views/shop/shop/_products.html.haml index 26ab4d17b6..36193467e0 100644 --- a/app/views/shop/shop/_products.html.haml +++ b/app/views/shop/shop/_products.html.haml @@ -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"} + + diff --git a/app/views/shop/shop/_variant.html.haml b/app/views/shop/shop/_variant.html.haml index 73b8b80f1e..3dade13410 100644 --- a/app/views/shop/shop/_variant.html.haml +++ b/app/views/shop/shop/_variant.html.haml @@ -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 }} diff --git a/app/views/shop/shop/products.rabl b/app/views/shop/shop/products.rabl index 662196953e..c92a1afaa0 100644 --- a/app/views/shop/shop/products.rabl +++ b/app/views/shop/shop/products.rabl @@ -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), diff --git a/app/views/shop/shop/show.html.haml b/app/views/shop/shop/show.html.haml index 5072576f6f..250942357c 100644 --- a/app/views/shop/shop/show.html.haml +++ b/app/views/shop/shop/show.html.haml @@ -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" diff --git a/app/views/spree/orders/_adjustments.html.haml b/app/views/spree/orders/_adjustments.html.haml new file mode 100644 index 0000000000..21e971832a --- /dev/null +++ b/app/views/spree/orders/_adjustments.html.haml @@ -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 diff --git a/app/views/spree/orders/_empty_cart_form.html.haml b/app/views/spree/orders/_empty_cart_form.html.haml deleted file mode 100644 index 1e9a792eec..0000000000 --- a/app/views/spree/orders/_empty_cart_form.html.haml +++ /dev/null @@ -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' diff --git a/app/views/spree/orders/_form.html.haml b/app/views/spree/orders/_form.html.haml new file mode 100644 index 0000000000..9366e0025d --- /dev/null +++ b/app/views/spree/orders/_form.html.haml @@ -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? diff --git a/app/views/spree/orders/_inside_cart_form.html.haml b/app/views/spree/orders/_inside_cart_form.html.haml deleted file mode 100644 index 502546113f..0000000000 --- a/app/views/spree/orders/_inside_cart_form.html.haml +++ /dev/null @@ -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' diff --git a/app/views/spree/orders/_line_item.html.haml b/app/views/spree/orders/_line_item.html.haml new file mode 100644 index 0000000000..bb7054655f --- /dev/null +++ b/app/views/spree/orders/_line_item.html.haml @@ -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)}" diff --git a/app/views/spree/orders/edit.html.haml b/app/views/spree/orders/edit.html.haml new file mode 100644 index 0000000000..3ac65a197b --- /dev/null +++ b/app/views/spree/orders/edit.html.haml @@ -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" + diff --git a/app/views/spree/orders/show.html.haml b/app/views/spree/orders/show.html.haml new file mode 100644 index 0000000000..32177157e7 --- /dev/null +++ b/app/views/spree/orders/show.html.haml @@ -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" diff --git a/app/views/spree/shared/_order_details.html.haml b/app/views/spree/shared/_order_details.html.haml new file mode 100644 index 0000000000..559a0227f1 --- /dev/null +++ b/app/views/spree/shared/_order_details.html.haml @@ -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 diff --git a/config/environments/test.rb b/config/environments/test.rb index 483ed4960c..e1291ab4b4 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -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' diff --git a/config/routes.rb b/config/routes.rb index 4fa61e8754..14519b4b13 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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 diff --git a/doc/outstanding_shopping_tests b/doc/outstanding_shopping_tests new file mode 100644 index 0000000000..4bfcc0c2aa --- /dev/null +++ b/doc/outstanding_shopping_tests @@ -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 + diff --git a/spec/features/consumer/checkout_spec.rb b/spec/archive/features/consumer/checkout_spec.rb similarity index 92% rename from spec/features/consumer/checkout_spec.rb rename to spec/archive/features/consumer/checkout_spec.rb index b55cc7821a..2c42a023e7 100644 --- a/spec/features/consumer/checkout_spec.rb +++ b/spec/archive/features/consumer/checkout_spec.rb @@ -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) diff --git a/spec/controllers/shop/checkout_controller_spec.rb b/spec/controllers/shop/checkout_controller_spec.rb index fd33e84b88..ed91818fbd 100644 --- a/spec/controllers/shop/checkout_controller_spec.rb +++ b/spec/controllers/shop/checkout_controller_spec.rb @@ -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 diff --git a/spec/controllers/shop/shop_controller_spec.rb b/spec/controllers/shop/shop_controller_spec.rb index f440da9805..b7c86fbc0e 100644 --- a/spec/controllers/shop/shop_controller_spec.rb +++ b/spec/controllers/shop/shop_controller_spec.rb @@ -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 diff --git a/spec/controllers/spree/admin/reports_controller_spec.rb b/spec/controllers/spree/admin/reports_controller_spec.rb index 87d9676308..8b4d80fcab 100644 --- a/spec/controllers/spree/admin/reports_controller_spec.rb +++ b/spec/controllers/spree/admin/reports_controller_spec.rb @@ -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 diff --git a/spec/features/admin/bulk_order_management_spec.rb b/spec/features/admin/bulk_order_management_spec.rb index afb81095a6..6ab5043ae7 100644 --- a/spec/features/admin/bulk_order_management_spec.rb +++ b/spec/features/admin/bulk_order_management_spec.rb @@ -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 \ No newline at end of file +end diff --git a/spec/features/admin/bulk_product_update_spec.rb b/spec/features/admin/bulk_product_update_spec.rb index 336792a3ae..73cad12f3c 100644 --- a/spec/features/admin/bulk_product_update_spec.rb +++ b/spec/features/admin/bulk_product_update_spec.rb @@ -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 diff --git a/spec/features/admin/enterprises_spec.rb b/spec/features/admin/enterprises_spec.rb index e593166236..88c6dc8cb4 100644 --- a/spec/features/admin/enterprises_spec.rb +++ b/spec/features/admin/enterprises_spec.rb @@ -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!' diff --git a/spec/features/admin/order_cycles_spec.rb b/spec/features/admin/order_cycles_spec.rb index 5cadd11a29..3708e03930 100644 --- a/spec/features/admin/order_cycles_spec.rb +++ b/spec/features/admin/order_cycles_spec.rb @@ -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') } diff --git a/spec/features/admin/products_spec.rb b/spec/features/admin/products_spec.rb index 092d5239d4..b9f9d7a206 100644 --- a/spec/features/admin/products_spec.rb +++ b/spec/features/admin/products_spec.rb @@ -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 diff --git a/spec/features/admin/variants_spec.rb b/spec/features/admin/variants_spec.rb index 51aefd9e69..d05aa75ef8 100644 --- a/spec/features/admin/variants_spec.rb +++ b/spec/features/admin/variants_spec.rb @@ -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 diff --git a/spec/features/chili/enterprises_distributor_info_rich_text_feature_spec.rb b/spec/features/chili/enterprises_distributor_info_rich_text_feature_spec.rb index 4482246878..3855b80bee 100644 --- a/spec/features/chili/enterprises_distributor_info_rich_text_feature_spec.rb +++ b/spec/features/chili/enterprises_distributor_info_rich_text_feature_spec.rb @@ -32,8 +32,8 @@ feature "enterprises distributor info as rich text" do click_link 'New Enterprise' # Then I should see fields 'Profile Info' and 'Distributor Info' - page.should have_selector 'td', text: 'Profile Info:' - page.should have_selector 'td', text: 'Distributor Info:' + page.should have_content 'About Us' + page.should have_content 'How does it work' # When I fill out the form and create the enterprise fill_in 'enterprise_name', :with => 'Eaterprises' @@ -78,6 +78,7 @@ feature "enterprises distributor info as rich text" do # -- Checkout click_button 'Add To Cart' find('#checkout-link').click + visit "/checkout" within 'fieldset#shipping' do page.should have_content 'Chu ge sai yubi dan bisento tobi ashi yubi ge omote.' page.should have_content 'Thursday 2nd May' @@ -85,7 +86,7 @@ feature "enterprises distributor info as rich text" do # -- Confirmation complete_purchase_from_checkout_address_page - page.should have_content 'Thursday 2nd May' + #page.should have_content 'Thursday 2nd May' # -- Purchase email wait_until { ActionMailer::Base.deliveries.length == 1 } @@ -111,6 +112,7 @@ feature "enterprises distributor info as rich text" do login_to_consumer_section click_link 'Green Grass' + visit enterprise_path d # -- Product details page click_link p.name @@ -122,6 +124,7 @@ feature "enterprises distributor info as rich text" do # -- Checkout click_button 'Add To Cart' find('#checkout-link').click + visit "/checkout" within 'fieldset#shipping' do page.should have_content 'Chu ge sai yubi dan bisento tobi ashi yubi ge omote.' page.should have_content 'Friday 4th May' diff --git a/spec/features/consumer/add_to_cart_spec.rb b/spec/features/consumer/add_to_cart_spec.rb deleted file mode 100644 index 7e7650a9b9..0000000000 --- a/spec/features/consumer/add_to_cart_spec.rb +++ /dev/null @@ -1,206 +0,0 @@ -require 'spec_helper' - -feature %q{ - As a consumer - I want to choose a distributor when adding products to my cart - So that I can avoid making an order from many different distributors -} do - include AuthenticationWorkflow - include WebHelper - - context "with product distribution" do - scenario "adding a product to the cart with no distributor chosen" do - # Given a product and some distributors - d1 = create(:distributor_enterprise) - d2 = create(:distributor_enterprise) - p = create(:product, :distributors => [d1]) - create(:product, :distributors => [d2]) - - # When I add an item to my cart without choosing a distributor - visit spree.product_path p - click_button 'Add To Cart' - - # Then I should see an error message - page.should have_content "That product is not available from the chosen distributor or order cycle" - - # And the product should not have been added to my cart - Spree::Order.last.line_items.should be_empty - end - - context "adding a subsequent product to the cart" do - it "does not allow the user to add a product from a distributor that cannot supply the cart's products" do - # Given two products, each at a different distributor - d1 = create(:distributor_enterprise) - d2 = create(:distributor_enterprise) - p1 = create(:product, :distributors => [d1]) - p2 = create(:product, :distributors => [d2]) - - # When I add one of them to my cart - select_distribution d1 - visit spree.product_path p1 - click_button 'Add To Cart' - - # And I attempt to add the other - visit spree.product_path p2 - - # Then I should not be allowed to add the product - page.should_not have_selector "button#add-to-cart-button" - page.should have_content "Please complete your order at #{d1.name} before shopping with another distributor." - end - end - - describe 'with order cycles disabled' do - before(:each) do - OrderCyclesHelper.class_eval do - def order_cycles_enabled? - false - end - end - end - - scenario "should not show order cycle details when adding to cart" do - # Given a product and a distributor - d = create(:distributor_enterprise) - p = create(:product, :price => 12.34) - - # When I add an item to my cart - visit spree.product_path p - - page.should_not have_selector '#order_cycle_id option' - end - - end - end - - context "with order cycle distribution" do - before(:each) do - OrderCyclesHelper.class_eval do - def order_cycles_enabled? - true - end - end - end - - scenario "adding a product to the cart with no distribution chosen" do - # Given a product and some distributors - d1 = create(:distributor_enterprise) - d2 = create(:distributor_enterprise) - p1 = create(:product) - p2 = create(:product) - create(:simple_order_cycle, :distributors => [d1], :variants => [p1.master]) - create(:simple_order_cycle, :distributors => [d2], :variants => [p2.master]) - - # When I add an item to my cart without choosing a distributor or order cycle - visit spree.product_path p1 - click_button 'Add To Cart' - - # Then I should see an error message - page.should have_content "Please choose an order cycle for this order." - - # And the product should not have been added to my cart - Spree::Order.last.line_items.should be_empty - end - - scenario "adding the first product to the cart" do - # Given a product and a distributor - d = create(:distributor_enterprise) - p = create(:product, :price => 12.34) - oc = create(:simple_order_cycle, :distributors => [d], :variants => [p.master]) - - # When I add an item to my cart - select_distribution d, oc - visit spree.product_path p - click_button 'Add To Cart' - - # Then the correct totals should be displayed - page.should have_selector 'span.item-total', :text => '$12.34' - - # TODO: Test these when order cycle fees is implemented - # page.should have_selector 'span.distribution-total', :text => '$1.23' - # page.should have_selector 'span.grand-total', :text => '$13.57' - - # And the item should be in my cart - order = Spree::Order.last - line_item = order.line_items.first - line_item.product.should == p - - # And my order should have its distributor and order cycle set to the chosen ones - order.distributor.should == d - order.order_cycle.should == oc - end - end - - context "group buys" do - scenario "adding a product to the cart for a group buy" do - # Given a group buy product and a distributor - d = create(:distributor_enterprise) - p = create(:product, :distributors => [d], :group_buy => true) - - # When I add the item to my cart - select_distribution d - visit spree.product_path p - fill_in "variants_#{p.master.id}", :with => 2 - fill_in "variant_attributes_#{p.master.id}_max_quantity", :with => 3 - click_button 'Add To Cart' - - # Then the item should be in my cart with correct quantities - order = Spree::Order.last - li = order.line_items.first - li.product.should == p - li.quantity.should == 2 - li.max_quantity.should == 3 - end - - scenario "adding a product with variants to the cart for a group buy" do - # Given a group buy product with variants and a distributor - d = create(:distributor_enterprise) - p = create(:product, :distributors => [d], :group_buy => true) - create(:variant, :product => p) - - # When I add the item to my cart - select_distribution d - visit spree.product_path p - fill_in "quantity", :with => 2 - fill_in "max_quantity", :with => 3 - click_button 'Add To Cart' - - # Then the item should be in my cart with correct quantities - order = Spree::Order.last - li = order.line_items.first - li.product.should == p - li.quantity.should == 2 - li.max_quantity.should == 3 - end - - scenario "adding a product to cart that is not a group buy does not show max quantity field" do - # Given a group buy product and a distributor - d = create(:distributor_enterprise) - p = create(:product, :distributors => [d], :group_buy => false) - - # When I view the add to cart form, there should not be a max quantity field - visit spree.product_path p - - page.should_not have_selector "#variant_attributes_#{p.master.id}_max_quantity" - end - - scenario "adding a product with a max quantity less than quantity results in max_quantity==quantity" do - # Given a group buy product and a distributor - d = create(:distributor_enterprise) - p = create(:product, :distributors => [d], :group_buy => true) - - # When I add the item to my cart - select_distribution d - visit spree.product_path p - fill_in "variants_#{p.master.id}", :with => 2 - fill_in "variant_attributes_#{p.master.id}_max_quantity", :with => 1 - click_button 'Add To Cart' - - # Then the item should be in my cart with correct quantities - order = Spree::Order.last - li = order.line_items.first - li.product.should == p - li.quantity.should == 2 - li.max_quantity.should == 2 - end - end -end diff --git a/spec/features/consumer/browse_products_spec.rb b/spec/features/consumer/browse_products_spec.rb deleted file mode 100644 index a12899d4bc..0000000000 --- a/spec/features/consumer/browse_products_spec.rb +++ /dev/null @@ -1,94 +0,0 @@ -require 'spec_helper' - -feature %q{ - As a consumer - I want to browse products by distributor and order cycle - So that I can buy products that are available soon and close to me -} do - include AuthenticationWorkflow - include WebHelper - - describe "selecting a distributor" do - it "displays the distributor's details" do - # Given a distributor with a product - d = create(:distributor_enterprise, :name => 'Melb Uni Co-op', :description => '

Hello, world!

') - create(:product, :distributors => [d]) - - # When I select the distributor - visit spree.select_distributor_order_path(d) - - # Then I should see the name of the distributor that I've selected - page.should have_selector 'h1', :text => 'Melb Uni Co-op' - - # And I should see the distributor's long description - page.should have_selector 'div.enterprise-description', :text => 'Hello, world!' - end - - it "displays the distributor's name on the home page" do - # Given a distributor with a product - d = create(:distributor_enterprise, :name => 'Melb Uni Co-op', :description => '

Hello, world!

') - create_enterprise_group_for d - p1 = create(:product, :distributors => [d]) - - # When I select the distributor - visit spree.select_distributor_order_path(d) - visit spree.root_path - click_on "Melb Uni Co-op" - - # Then I should see the name of the distributor that I've selected - page.should have_content 'Melb Uni Co-op' - page.should_not have_selector 'div.distributor-description' - end - - it "splits the product listing by local/remote distributor", :future => true do - # Given two distributors, with a product under each, and each product under a taxon - taxonomy = Spree::Taxonomy.find_by_name('Products') || create(:taxonomy, :name => 'Products') - taxonomy_root = taxonomy.root - taxon = create(:taxon, :name => 'Taxon one', :parent_id => taxonomy_root.id) - d1 = create(:distributor_enterprise, :name => 'Green Grass') - d2 = create(:distributor_enterprise) - p1 = create(:product, :distributors => [d1], :taxons => [taxon]) - p2 = create(:product, :distributors => [d2], :taxons => [taxon]) - - # When I select the first distributor - visit spree.select_distributor_order_path(d1) - visit spree.root_path - - # Then I should see products split by local/remote distributor - # on the home page, the products page, the search results page and the taxon page - [spree.products_path, - spree.products_path(:keywords => 'Product'), - spree.nested_taxons_path(taxon.permalink) - ].each do |path| - - visit path - page.should have_selector '#products' - end - end - - describe "variant listing" do - it "shows only variants that are in the distributor and order cycle", js: true do - # Given a product with two variants - s = create(:supplier_enterprise) - d = create(:distributor_enterprise, name: 'Green Grass') - create_enterprise_group_for d - p = create(:simple_product, supplier: s) - v1 = create(:variant, product: p, is_master: false) - v2 = create(:variant, product: p, is_master: false) - - # And only one of those is distributed by an order cycle - oc = create(:simple_order_cycle, suppliers: [s], distributors: [d], variants: [v1]) - - # When I am in that order cycle - visit root_path - click_link d.name - - # And I view the product - click_link p.name - - # Then I should see only the relevant variant - page.all('#product-variants li input').count.should == 1 - end - end - end -end diff --git a/spec/features/consumer/cms_spec.rb b/spec/features/consumer/cms_spec.rb index 36653bea01..0f25bc549c 100644 --- a/spec/features/consumer/cms_spec.rb +++ b/spec/features/consumer/cms_spec.rb @@ -4,12 +4,12 @@ feature %q{ In order to learn about food As a user of the site I want to see static content pages -} do +}, skip: true do include AuthenticationWorkflow include WebHelper + let(:d) { create(:distributor_enterprise, :name => 'Edible garden') } background do - d = create(:distributor_enterprise, :name => 'Edible garden') create_enterprise_group_for d end @@ -22,6 +22,7 @@ feature %q{ # and proceed to the shop front click_on 'Edible garden' + visit enterprise_path d # Then I should not see the home page content page.should_not have_content 'Home page content' @@ -36,9 +37,10 @@ feature %q{ # When I visit the home page visit spree.root_path - # and proceed to the shop front click_on "Edible garden" + visit enterprise_path d + # Then I should see a menu with these pages page.should have_selector 'ul#main-nav-bar li', :text => 'One' @@ -56,6 +58,7 @@ feature %q{ # When I go to one of the pages visit spree.root_path click_on "Edible garden" + visit enterprise_path d click_link 'Two' # Then I should see the page diff --git a/spec/features/consumer/distributors_spec.rb b/spec/features/consumer/distributors_spec.rb deleted file mode 100644 index f4652ac5b9..0000000000 --- a/spec/features/consumer/distributors_spec.rb +++ /dev/null @@ -1,111 +0,0 @@ -require 'spec_helper' - -feature %q{ - As a consumer - I want to see a list of distributors - So that I can shop by a particular distributor -} do - include AuthenticationWorkflow - include WebHelper - - scenario "viewing a list of distributors in the sidebar", :future => true do - # Given some distributors - d1 = create(:distributor_enterprise, :name => "Edible garden") - d2 = create(:distributor_enterprise) - d3 = create(:distributor_enterprise) - - # And some of those distributors have a product - create(:product, :distributors => [d1, d2]) - - # When I go to the home page - visit spree.root_path - - # and proceed to the shop front - click_on "Edible garden" - - # Then I should see a list containing the distributors that have products - page.should have_selector 'a', :text => d1.name - page.should have_selector 'a', :text => d2.name - page.should_not have_selector 'a', :text => d3.name - end - - scenario "viewing a list of distributors (with active products) in the sidebar when there's some inactive distributors", :future => true do - # Given some distributors - d1 = create(:distributor_enterprise, :name => "Edible garden") - d2 = create(:distributor_enterprise) - d3 = create(:distributor_enterprise) - d4 = create(:distributor_enterprise) - d5 = create(:distributor_enterprise) - d6 = create(:distributor_enterprise) - - # And some of those distributors have a product - create(:product, :distributors => [d1]) - create(:product, :distributors => [d3], :on_hand => 0) - - # And no limit set for the sidebar - sidebar_distributors_limit = false - - # When I go to the home page - visit spree.root_path - - # and proceed to the shop front - click_on "Edible garden" - - # Then I should see a list containing all the distributors that have active products in stock - page.should have_selector 'a', :text => d1.name - page.should_not have_selector 'a', :text => d2.name #has no products - page.should_not have_selector 'a', :text => d3.name #has no products on hand - - # And I should see '5 more' - distributors_more = Enterprise.is_distributor.distinct_count - Enterprise.is_distributor.with_distributed_active_products_on_hand.by_name.limit(sidebar_distributors_limit).length - page.should have_selector '#distributor_filter span.filter_more', :text => "#{distributors_more} more" - - # And I should (always) see a browse distributors button - page.should have_selector "#distributor_filter input[value='Browse All Distributors']" - end - - scenario "viewing a list of all distributors", :future => true do - # Given some distributors - d1 = create(:distributor_enterprise, :name => "Edible garden") - d2 = create(:distributor_enterprise) - d3 = create(:distributor_enterprise) - - # And some of those distributors have a product - create(:product, :distributors => [d1]) - create(:product, :distributors => [d3]) - - # When I go to the distributors listing page - visit spree.root_path - click_on "Edible garden" - click_button 'Browse All Distributors' - - # Then I should see a list containing all the distributors - page.should have_selector '#content a', :text => d1.name - page.should have_selector '#content a', :text => d2.name - page.should have_selector '#content a', :text => d3.name - end - - - scenario "viewing a distributor", :js => true do - # Given some distributors with products - d1 = create(:distributor_enterprise, :name => "Edible garden", :long_description => "

Hello, world!

") - d2 = create(:distributor_enterprise) - create_enterprise_group_for d1 - p1 = create(:product, :distributors => [d1]) - p2 = create(:product, :distributors => [d2]) - supplier = create(:supplier_enterprise) - order_cycle = create(:simple_order_cycle, suppliers: [supplier], distributors: [d1], variants: [p1.master]) - - # When I go to the first distributor page - visit spree.root_path - click_link d1.name - - # Then I should see the distributor details - page.should have_selector 'h1', :text => d1.name - page.should have_selector 'div.enterprise-description', :text => 'Hello, world!' - - # And I should see the first, but not the second product - page.should have_content p1.name - page.should_not have_content p2.name - end -end diff --git a/spec/features/consumer/order_cycles_spec.rb b/spec/features/consumer/order_cycles_spec.rb deleted file mode 100644 index 591b7af002..0000000000 --- a/spec/features/consumer/order_cycles_spec.rb +++ /dev/null @@ -1,306 +0,0 @@ -require 'spec_helper' - -feature %q{ - As a consumer - I want to see a choice of order cycles and distributors - So that I can shop for a particular distributor and pickup date -} do - include AuthenticationWorkflow - include WebHelper - - background do - # Given some hubs and order cycles - create(:distributor_enterprise) - @d1 = create(:distributor_enterprise) - @d2 = create(:distributor_enterprise) - create(:product, distributors: [@d1, @d2]) - - @oc1 = create(:simple_order_cycle, orders_close_at: Time.zone.now + 1.week) - @oc2 = create(:simple_order_cycle, orders_close_at: Time.zone.now + 2.days) - create(:exchange, order_cycle: @oc1, sender: @oc1.coordinator, receiver: @d1) - create(:exchange, order_cycle: @oc2, sender: @oc2.coordinator, receiver: @d2) - end - - describe 'when order cycles is enabled' do - - background do - OrderCyclesHelper.class_eval do - def order_cycles_enabled? - true - end - end - end - - - scenario "selecting order cycle when multiple options are available", js: true do - d = create(:distributor_enterprise, name: 'Green Grass') - create_enterprise_group_for d - oc1 = create(:simple_order_cycle, name: 'oc 1', distributors: [d]) - oc2 = create(:simple_order_cycle, name: 'oc 2', distributors: [d]) - - # We find by ID because the scope returns read-only models - exchange = Exchange.find(oc1.exchanges.to_enterprises(d).outgoing.first.id) - exchange.update_attribute :pickup_time, "turtles" - - visit spree.root_path - click_link d.name - - page.should have_select 'order_order_cycle_id' - select_by_value oc1.id, from: 'order_order_cycle_id' - page.should have_content 'Your order will be ready on turtles' - end - - context "when there are no available order cycles" do - let(:d1) { create(:distributor_enterprise, name: 'Green Grass') } - let(:d2) { create(:distributor_enterprise, name: 'Blue Grass') } - before do - create_enterprise_group_for d1 - visit spree.root_path - end - - it "indicates there are no current order cycles" do - Timecop.freeze do - oc1 = create(:simple_order_cycle, name: 'oc 1', distributors: [d1], orders_close_at: 5.minutes.ago) - oc2 = create(:simple_order_cycle, name: 'oc 1', distributors: [d2], orders_close_at: 3.minutes.ago) - click_link d1.name - - page.should have_content "Orders are currently closed for this hub" - page.should have_content "The last cycle closed 5 minutes ago." - page.should have_content "Please contact your hub directly to see if they accept late orders, or wait until the next cycle opens." - page.should have_content d1.email - page.should have_content d1.phone - end - end - - context "displaying future order cycles" do - it "should show the time until the next order cycle opens" do - create(:simple_order_cycle, name: 'oc 1', distributors: [d1], orders_open_at: 10.days.from_now, orders_close_at: 11.days.from_now) - - click_link d1.name - page.should have_content "The next order cycle opens in 10 days" - end - - it "should show nothing when there is no next order cycle" do - click_link d1.name - page.should_not have_content "The next order cycle opens" - page.should_not have_content "No products found" - end - end - end - - scenario "changing order cycle", js: true do - s = create(:supplier_enterprise) - d = create(:distributor_enterprise, name: 'Green Grass') - create_enterprise_group_for d - p = create(:simple_product, supplier: s) - oc = create(:simple_order_cycle, suppliers: [s], distributors: [d], variants: [p.master]) - - visit spree.root_path - click_link d.name - - click_link p.name - click_button 'Add To Cart' - - click_link 'Continue shopping' - click_link 'Change Collection Date' - - - # Then we should be back at the landing page with a reset cart - page.should have_content 'Green Grass' - page.should have_content 'When do you want your order?' - # When we get taken back to select order cycle, there is no selected order cycle - # Therefore we should not see the no products info - page.should_not have_content "No products found" - - cart = Spree::Order.last - cart.distributor.should == d - cart.order_cycle.should be_nil - cart.line_items.should be_empty - end - - scenario "viewing order cycle and distributor choices", :future => true do - # When I go to the product listing page - visit spree.products_path - - # Then I should see a choice of hubs - page.should have_selector "#distribution-selection option[value='#{@d1.id}']", text: @d1.name - page.should have_selector "#distribution-selection option[value='#{@d2.id}']", text: @d2.name - - # And I should see a choice of order cycles with closing times - [{oc: @oc1, closing: '7 days'}, {oc: @oc2, closing: '2 days'}].each do |data| - within "tr.order-cycle-#{data[:oc].id}" do - page.should have_content data[:oc].name - page.should have_content data[:closing] - end - end - - # And I should see an indication of my current choices - page.should have_selector "#distribution-choice", text: 'You have not yet picked where you will get your order from.' - end - - 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' - 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 - click_link 'Continue shopping' - - # 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 - - # And my cart should have been cleared - page.should have_content "Cart: (Empty)" - page.should have_content 'Green Grass' - end - end - - - context "without javascript", :future => true do - scenario "selecting a distributor highlights valid order cycle choices" do - # When I go to the product listing page - visit spree.products_path - - # And I choose a distributor - select @d1.name, from: 'order_distributor_id' - click_button 'Choose Hub' - - # Then associated order cycles should be highlighted - page.should have_content "Your hub has been selected." - page.should have_selector '#distribution-choice', text: "Hub: #{@d1.name}" - within "#distribution-selection" do - page.should have_selector "tr.order-cycle-#{@oc1.id}.local" - page.should have_selector "tr.order-cycle-#{@oc2.id}.remote" - end - - # When I choose the other distributor - select @d2.name, from: 'order_distributor_id' - click_button 'Choose Hub' - - # Then associated order cycles should be highlighted - page.should have_content "Your hub has been selected." - page.should have_selector '#distribution-choice', text: "Hub: #{@d2.name}" - within '#distribution-selection' do - page.should have_selector "tr.order-cycle-#{@oc1.id}.remote" - page.should have_selector "tr.order-cycle-#{@oc2.id}.local" - end - end - - scenario "selecting an order cycle highlights valid distributor choices", :future => true do - # When I go to the product listing page - visit spree.products_path - - # And I choose an order cycle - choose @oc1.name - click_button 'Choose Order Cycle' - - # Then the associated distributor should be highlighted - page.should have_content "Your order cycle has been selected." - page.should have_selector '#distribution-choice', text: "Order Cycle: #{@oc1.name}" - within '#distribution-selection' do - page.should have_selector "option.local[value='#{@d1.id}']" - page.should have_selector "option.remote[value='#{@d2.id}']" - end - - # When I choose the other order cycle - choose @oc2.name - click_button 'Choose Order Cycle' - - # Then the associated distributor should be highlighted - page.should have_content "Your order cycle has been selected." - page.should have_selector '#distribution-choice', text: "Order Cycle: #{@oc2.name}" - within '#distribution-selection' do - page.should have_selector "option.remote[value='#{@d1.id}']" - page.should have_selector "option.local[value='#{@d2.id}']" - end - end - - scenario "selecing a remote order cycle clears the distributor" do - # When I go to the products listing page - visit spree.products_path - - # And I choose a distributor - select @d1.name, from: 'order_distributor_id' - click_button 'Choose Hub' - - # And I choose a remote order cycle - choose @oc2.name - click_button 'Choose Order Cycle' - - # Then my distributor should be cleared - page.should_not have_selector "option[value='#{@d1.id}'][selected='selected']" - end - - scenario "selecing a remote distributor clears the order cycle" do - # When I go to the products listing page - visit spree.products_path - - # And I choose an order cycle - choose @oc1.name - click_button 'Choose Order Cycle' - - # And I choose a remote distributor - select @d2.name, from: 'order_distributor_id' - click_button 'Choose Hub' - - # Then my order cycle should be cleared - page.should_not have_selector "input[value='#{@oc1.id}'][checked='checked']" - end - - scenario "selecting both an order cycle and distributor", :future => true do - # When I go to the products listing page - visit spree.products_path - - # And I choose an order cycle - choose @oc1.name - click_button 'Choose Order Cycle' - - # And I choose a distributor - select @d1.name, from: 'order_distributor_id' - click_button 'Choose Hub' - - # Then my order cycle and distributor should be set - within '#distribution-choice' do - page.should have_content "Hub: #{@d1.name}" - page.should have_content "Order Cycle: #{@oc1.name}" - end - - page.should have_selector "input[value='#{@oc1.id}'][checked='checked']" - page.should have_selector "option[value='#{@d1.id}'][selected='selected']" - end - end - end - - describe 'when order cycles is disabled' do - - background do - OrderCyclesHelper.class_eval do - def order_cycles_enabled? - false - end - end - end - - scenario "should not show order cycles in the product listing" do - # When I go to the product listing page - visit spree.products_path - - # Then I should not see any hubs - page.should_not have_selector "#distribution-selection" - - # And I should not display extra distribution details - page.should_not have_selector "#distribution-choice" - end - end -end diff --git a/spec/features/consumer/product_spec.rb b/spec/features/consumer/product_spec.rb deleted file mode 100644 index 9b45b21ef1..0000000000 --- a/spec/features/consumer/product_spec.rb +++ /dev/null @@ -1,55 +0,0 @@ -require 'spec_helper' - -feature %q{ - As a consumer - I want to see products - So that I can shop -} do - include AuthenticationWorkflow - include WebHelper - - scenario "viewing a product shows its supplier" do - # Given a product with a supplier and distributor - s = create(:supplier_enterprise) - d1 = create(:distributor_enterprise) - d2 = create(:distributor_enterprise) - p = create(:product, :supplier => s, :distributors => [d1]) - oc = create(:simple_order_cycle, :distributors => [d2], :variants => [p.master]) - - # When I view the product - visit spree.product_path p - - # Then I should see the product's supplier - page.should have_selector 'td', :text => s.name - end - - describe "viewing distributor details" do - context "without Javascript" do - it "displays a holding message when no distributor is selected" do - p = create(:product) - - visit spree.product_path p - - page.should have_selector '#product-distributor-details', :text => 'When you select a distributor for your order, their address and pickup times will be displayed here.' - end - - it "displays distributor details when one is selected" do - d = create(:distributor_enterprise) - p = create(:product, :distributors => [d]) - - visit spree.select_distributor_order_path(d) - visit spree.product_path p - - within '#product-distributor-details' do - [d.name, - d.distributor_info, - d.next_collection_at - ].each do |value| - - page.should have_content value - end - end - end - end - end -end diff --git a/spec/features/consumer/shopping/checkout_auth_spec.rb b/spec/features/consumer/shopping/checkout_auth_spec.rb new file mode 100644 index 0000000000..de14f121e7 --- /dev/null +++ b/spec/features/consumer/shopping/checkout_auth_spec.rb @@ -0,0 +1,84 @@ +require 'spec_helper' + +feature "As a consumer I want to check out my cart", js: true do + include AuthenticationWorkflow + include WebHelper + + let(:distributor) { create(:distributor_enterprise) } + let(:supplier) { create(:supplier_enterprise) } + let(:order_cycle) { create(:order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise)) } + let(:product) { create(:simple_product, supplier: supplier) } + + before do + create_enterprise_group_for distributor + exchange = Exchange.find(order_cycle.exchanges.to_enterprises(distributor).outgoing.first.id) + exchange.variants << product.master + end + + describe "Login behaviour" do + let(:user) { create_enterprise_user } + before do + select_distributor + select_order_cycle + add_product_to_cart + end + + it "renders the login form if user is logged out" do + visit "/shop/checkout" + within "section[role='main']" do + page.should have_content "I HAVE AN OFN ACCOUNT" + end + end + + it "does not not render the login form if user is logged in" do + login_to_consumer_section + visit "/shop/checkout" + within "section[role='main']" do + page.should_not have_content "I HAVE AN OFN ACCOUNT" + end + end + + it "renders the signup link if user is logged out" do + visit "/shop/checkout" + within "section[role='main']" do + page.should have_content "NEW TO OFN" + end + end + + it "does not not render the signup form if user is logged in" do + login_to_consumer_section + visit "/shop/checkout" + within "section[role='main']" do + page.should_not have_content "NEW TO OFN" + end + end + + it "redirects to the checkout page when logging in from the checkout page" do + visit "/shop/checkout" + within "#checkout_login" do + fill_in "spree_user[email]", with: user.email + fill_in "spree_user[password]", with: user.password + click_button "Login" + end + + current_path.should == "/shop/checkout" + within "section[role='main']" do + page.should_not have_content "I have an OFN Account" + end + end + + it "redirects to the checkout page when signing up from the checkout page" do + visit "/shop/checkout" + within "#checkout_signup" do + fill_in "spree_user[email]", with: "test@gmail.com" + fill_in "spree_user[password]", with: "password" + fill_in "spree_user[password_confirmation]", with: "password" + click_button "Sign Up" + end + current_path.should == "/shop/checkout" + within "section[role='main']" do + page.should_not have_content "Sign Up" + end + end + end +end diff --git a/spec/features/consumer/shopping/checkout_plumbing_spec.rb b/spec/features/consumer/shopping/checkout_plumbing_spec.rb new file mode 100644 index 0000000000..b972667ca9 --- /dev/null +++ b/spec/features/consumer/shopping/checkout_plumbing_spec.rb @@ -0,0 +1,45 @@ +require 'spec_helper' + + +feature "As a consumer I want to check out my cart", js: true do + include AuthenticationWorkflow + include WebHelper + + let(:distributor) { create(:distributor_enterprise) } + let(:supplier) { create(:supplier_enterprise) } + let(:order_cycle) { create(:order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise)) } + let(:product) { create(:simple_product, supplier: supplier) } + + before do + create_enterprise_group_for distributor + exchange = Exchange.find(order_cycle.exchanges.to_enterprises(distributor).outgoing.first.id) + exchange.variants << product.master + end + describe "Attempting to access checkout without meeting the preconditions" do + it "redirects to the homepage if no distributor is selected" do + visit "/shop/checkout" + current_path.should == root_path + end + + it "redirects to the shop page if we have a distributor but no order cycle selected" do + select_distributor + visit "/shop/checkout" + current_path.should == shop_path + end + + it "redirects to the shop page if the current order is empty" do + select_distributor + select_order_cycle + visit "/shop/checkout" + current_path.should == shop_path + end + + it "renders checkout if we have distributor and order cycle selected" do + select_distributor + select_order_cycle + add_product_to_cart + visit "/shop/checkout" + current_path.should == "/shop/checkout" + end + end +end diff --git a/spec/features/consumer/shopping/checkout_spec.rb b/spec/features/consumer/shopping/checkout_spec.rb index ed2fb84a59..553f53dd21 100644 --- a/spec/features/consumer/shopping/checkout_spec.rb +++ b/spec/features/consumer/shopping/checkout_spec.rb @@ -16,101 +16,6 @@ feature "As a consumer I want to check out my cart", js: true do exchange.variants << product.master end - describe "Attempting to access checkout without meeting the preconditions" do - it "redirects to the homepage if no distributor is selected" do - visit "/shop/checkout" - current_path.should == root_path - end - - it "redirects to the shop page if we have a distributor but no order cycle selected" do - select_distributor - visit "/shop/checkout" - current_path.should == shop_path - end - - it "redirects to the shop page if the current order is empty" do - select_distributor - select_order_cycle - visit "/shop/checkout" - current_path.should == shop_path - end - - it "renders checkout if we have distributor and order cycle selected" do - select_distributor - select_order_cycle - add_product_to_cart - visit "/shop/checkout" - current_path.should == "/shop/checkout" - end - end - - describe "Login behaviour" do - let(:user) { create_enterprise_user } - before do - select_distributor - select_order_cycle - add_product_to_cart - end - - it "renders the login form if user is logged out" do - visit "/shop/checkout" - within "section[role='main']" do - page.should have_content "I HAVE AN OFN ACCOUNT" - end - end - - it "does not not render the login form if user is logged in" do - login_to_consumer_section - visit "/shop/checkout" - within "section[role='main']" do - page.should_not have_content "I HAVE AN OFN ACCOUNT" - end - end - - it "renders the signup link if user is logged out" do - visit "/shop/checkout" - within "section[role='main']" do - page.should have_content "NEW TO OFN" - end - end - - it "does not not render the signup form if user is logged in" do - login_to_consumer_section - visit "/shop/checkout" - within "section[role='main']" do - page.should_not have_content "NEW TO OFN" - end - end - - it "redirects to the checkout page when logging in from the checkout page" do - visit "/shop/checkout" - within "#checkout_login" do - fill_in "spree_user[email]", with: user.email - fill_in "spree_user[password]", with: user.password - click_button "Login" - end - - current_path.should == "/shop/checkout" - within "section[role='main']" do - page.should_not have_content "I have an OFN Account" - end - end - - it "redirects to the checkout page when signing up from the checkout page" do - visit "/shop/checkout" - within "#checkout_signup" do - fill_in "spree_user[email]", with: "test@gmail.com" - fill_in "spree_user[password]", with: "password" - fill_in "spree_user[password_confirmation]", with: "password" - click_button "Sign Up" - end - current_path.should == "/shop/checkout" - within "section[role='main']" do - page.should_not have_content "Sign Up" - end - end - end - # Run these tests both logged in and logged out! [:in, :out].each do |auth_state| describe "logged #{auth_state.to_s}, distributor selected, order cycle selected, product in cart" do @@ -179,6 +84,7 @@ feature "As a consumer I want to check out my cart", js: true do describe "with payment methods" do let(:pm1) { create(:payment_method, distributors: [distributor], name: "Roger rabbit", type: "Spree::PaymentMethod::Check") } let(:pm2) { create(:payment_method, distributors: [distributor]) } + let(:pm3) { create(:payment_method, distributors: [distributor], name: "Paypal", type: "Spree::BillingIntegration::PaypalExpress") } before do pm1 # Lazy evaluation of ze create()s @@ -213,7 +119,7 @@ feature "As a consumer I want to check out my cart", js: true do fill_in "Customer E-Mail", with: "test@test.com" fill_in "Phone", with: "0468363090" fill_in "City", with: "Melbourne" - fill_in "Zip Code", with: "3066" + fill_in "Postcode", with: "3066" end click_button "Purchase" page.should have_content "Your order has been processed successfully" @@ -231,7 +137,7 @@ feature "As a consumer I want to check out my cart", js: true do fill_in "Customer E-Mail", with: "test@test.com" fill_in "Phone", with: "0468363090" fill_in "City", with: "Melbourne" - fill_in "Zip Code", with: "3066" + fill_in "Postcode", with: "3066" end check "Shipping address same as billing address?" click_button "Purchase" diff --git a/spec/features/consumer/shopping/shopping_spec.rb b/spec/features/consumer/shopping/shopping_spec.rb index 467ef2365f..67150f3f62 100644 --- a/spec/features/consumer/shopping/shopping_spec.rb +++ b/spec/features/consumer/shopping/shopping_spec.rb @@ -134,13 +134,11 @@ feature "As a consumer I want to shop with a distributor", js: true do page.should_not have_selector("#variants_#{product.master.id}", visible: true) end - it "collapses variants by default" do - page.should_not have_text variant1.options_text + it "expands variants by default" do + page.should have_text variant1.options_text end it "expands variants" do - find(".expand").trigger "click" - page.should have_text variant1.options_text find(".collapse").trigger "click" page.should_not have_text variant1.options_text end @@ -161,7 +159,6 @@ feature "As a consumer I want to shop with a distributor", js: true do page.should_not have_selector 'tr.product > td', text: "from $33.00" # Page should have variant prices (with fee) - find(".expand").trigger 'click' page.should have_selector 'tr.variant > td.price', text: "$43.00" page.should have_selector 'tr.variant > td.price', text: "$53.00" @@ -223,7 +220,6 @@ feature "As a consumer I want to shop with a distributor", js: true do page.should_not have_content p3.name # It shows on demand variants - within(".product-#{p4.id}") { find(".expand", visible: true).trigger "click" } page.should have_content v3.options_text # It does not show variants that are neither on hand or on demand @@ -237,6 +233,7 @@ feature "As a consumer I want to shop with a distributor", js: true do describe "group buy products" do let(:oc) { create(:simple_order_cycle, distributors: [distributor]) } let(:product) { create(:simple_product, group_buy: true, on_hand: 15) } + let(:product2) { create(:simple_product, group_buy: false) } describe "without variants" do before do @@ -245,6 +242,7 @@ feature "As a consumer I want to shop with a distributor", js: true do it "should show group buy input" do page.should have_field "variant_attributes[#{product.master.id}][max_quantity]", :visible => true + page.should_not have_field "variant_attributes[#{product2.master.id}][max_quantity]", :visible => true end it "should save group buy data to ze cart" do @@ -256,13 +254,22 @@ feature "As a consumer I want to shop with a distributor", js: true do li.max_quantity.should == 9 li.quantity.should == 5 end + + scenario "adding a product with a max quantity less than quantity results in max_quantity==quantity" do + fill_in "variants[#{product.master.id}]", with: 5 + fill_in "variant_attributes[#{product.master.id}][max_quantity]", with: 1 + first("form.custom > input.button.right").click + page.should have_content product.name + li = Spree::Order.order(:created_at).last.line_items.order(:created_at).last + li.max_quantity.should == 5 + li.quantity.should == 5 + end end describe "with variants on the product" do let(:variant) { create(:variant, product: product, on_hand: 10 ) } before do build_and_select_order_cycle_with_variants - find(".expand").trigger "click" end it "should show group buy input" do @@ -289,7 +296,6 @@ feature "As a consumer I want to shop with a distributor", js: true do build_and_select_order_cycle_with_variants end it "should let us add products to our cart" do - find(".expand").trigger "click" fill_in "variants[#{variant.id}]", with: "1" first("form.custom > input.button.right").click current_path.should == "/cart" @@ -312,6 +318,8 @@ feature "As a consumer I want to shop with a distributor", js: true do visit shop_path page.should have_content "The next cycle opens in 10 days" end + + it "shows nothing when there is no future order cycle" end end end diff --git a/spec/features/consumer/suppliers_spec.rb b/spec/features/consumer/suppliers_spec.rb index ca5430e93f..2252b8e8c5 100644 --- a/spec/features/consumer/suppliers_spec.rb +++ b/spec/features/consumer/suppliers_spec.rb @@ -12,7 +12,6 @@ feature %q{ create(:distributor_enterprise, :name => "Edible garden") end - scenario "entering the site via a supplier's page" do # Given a supplier with some distributed products s = create(:supplier_enterprise) @@ -30,88 +29,6 @@ feature %q{ click_link d.name # Then that hub should be selected - page.should have_selector 'h1', text: d.name - - # And I should be on the hub page - within('#products') { page.should have_content p.name } - end - - scenario "viewing a list of suppliers (with active products) in the sidebar when there's 5 or fewer", :future => true do - # Given some suppliers - s1 = create(:supplier_enterprise) - s2 = create(:supplier_enterprise) - s3 = create(:supplier_enterprise) - s4 = create(:supplier_enterprise) - s5 = create(:supplier_enterprise) - s6 = create(:supplier_enterprise) - - # And some of those suppliers have a product - create(:product, :supplier => s1) - create(:product, :supplier => s3, :on_hand => 0) - - # And no limit set for the sidebar - sidebar_suppliers_limit = false - - # When I go to the home page - visit spree.root_path - - # and proceed to the shop front - click_on "Edible garden" - - # Then I should see a list containing all the suppliers that have active products in stock - page.should have_selector 'a', :text => s1.name - page.should_not have_selector 'a', :text => s2.name #has no products - page.should_not have_selector 'a', :text => s3.name #has no products on hand - - # And I should see '5 more' - suppliers_more = Enterprise.is_primary_producer.distinct_count - Enterprise.is_primary_producer.with_supplied_active_products_on_hand.limit(sidebar_suppliers_limit).length - page.should have_selector '#supplier_filter span.filter_more', :text => "#{suppliers_more} more" - - # And I should (always) see a browse suppliers button - page.should have_selector "#supplier_filter input[value='Browse All Suppliers']" - end - - scenario "viewing a list of all suppliers", :future => true do - # Given some suppliers - s1 = create(:supplier_enterprise) - s2 = create(:supplier_enterprise) - s3 = create(:supplier_enterprise) - - # And some of those suppliers have a product - create(:product, :supplier => s1) - create(:product, :supplier => s3) - - # When I go to the suppliers listing page - visit spree.root_path - click_on "Edible garden" - click_button 'Browse All Suppliers' - - # Then I should see a list containing all the suppliers - page.should have_selector '#content a', :text => s1.name - page.should have_selector '#content a', :text => s2.name - page.should have_selector '#content a', :text => s3.name - end - - scenario "viewing products provided by a supplier", :future => true do - # Given a supplier with a product - s1 = create(:supplier_enterprise, :name => 'Murrnong', :long_description => "

Hello, world!

") - p1 = create(:product, :supplier => s1) - - # And a different supplier with another product - s2 = create(:supplier_enterprise, :name => 'Red Herring') - p2 = create(:product, :supplier => s2) - - # When I select the first supplier - visit spree.root_path - click_on "Edible garden" - click_link s1.name - - # Then I should see the supplier details - page.should have_selector 'h2', :text => s1.name - page.should have_selector 'div.enterprise-description', :text => 'Hello, world!' - - # And I should see the first, but not the second product - page.should have_content p1.name - page.should_not have_content p2.name + page.should have_content d.name end end diff --git a/spec/features/consumer/taxonomy_spec.rb b/spec/features/consumer/taxonomy_spec.rb deleted file mode 100644 index 8b0667ec45..0000000000 --- a/spec/features/consumer/taxonomy_spec.rb +++ /dev/null @@ -1,167 +0,0 @@ -require 'spec_helper' - -feature %q{ - As a consumer - I want to see product counts (for my chosen distributor) next to each taxon - So that I can locate products (at my chosen distributor) -} do - include AuthenticationWorkflow - include WebHelper - - background do - create(:distributor_enterprise, :name => "Edible garden") - end - - # How should this work with distributors/order cycles? - # - No distributor or OC selected - all shown - # - Distributor selected - any from that distributor in any OC - # - OC selected - any in that OC from any distributor - # - Both selected - filter for both - - # Also keep specs for distributors outside order cycles. - - scenario "viewing product counts when no distributor or order cycle is selected", :future => true do - # Given some taxons and some products - taxonomy = Spree::Taxonomy.find_by_name('Products') || create(:taxonomy, :name => 'Products') - taxonomy_root = taxonomy.root - - taxon_one = create(:taxon, :name => 'Taxon one', :parent_id => taxonomy_root.id) - taxon_two = create(:taxon, :name => 'Taxon two', :parent_id => taxonomy_root.id) - taxon_three = create(:taxon, :name => 'Taxon three', :parent_id => taxonomy_root.id) - - 1.times { create(:product, :taxons => [taxon_one]) } - 2.times { create(:product, :taxons => [taxon_two]) } - 3.times { create(:product, :taxons => [taxon_three]) } - - # When I visit the home page - visit spree.root_path - - # and proceed to the shop front - click_on "Edible garden" - - # Then I should see product counts next to the taxons - page.should have_selector 'nav#taxonomies li', :text => 'Taxon one (1)' - page.should have_selector 'nav#taxonomies li', :text => 'Taxon two (2)' - page.should have_selector 'nav#taxonomies li', :text => 'Taxon three (3)' - end - - - scenario "viewing product counts when a distributor is selected", :future => true do - # Given some taxons and some products under distributors - taxonomy = Spree::Taxonomy.find_by_name('Products') || create(:taxonomy, :name => 'Products') - taxonomy_root = taxonomy.root - - taxon_one = create(:taxon, :name => 'Taxon one', :parent_id => taxonomy_root.id) - taxon_two = create(:taxon, :name => 'Taxon two', :parent_id => taxonomy_root.id) - taxon_three = create(:taxon, :name => 'Taxon three', :parent_id => taxonomy_root.id) - - my_distributor = create(:distributor_enterprise, :name => 'My Distributor') - other_distributor = create(:distributor_enterprise, :name => 'Other Distributor') - - 1.times { create(:product, :taxons => [taxon_one], :distributors => [other_distributor]) } - 2.times { create(:product, :taxons => [taxon_two], :distributors => [other_distributor]) } - 2.times { create(:product, :taxons => [taxon_three], :distributors => [other_distributor]) } - 2.times { create(:product, :taxons => [taxon_three], :distributors => [my_distributor]) } - - p = create(:product, :taxons => [taxon_one]) - oc = create(:simple_order_cycle, distributors: [my_distributor], variants: [p.master]) - - # When I visit the home page and select my distributor - visit spree.select_distributor_order_path(my_distributor) - within('nav#filters') { click_link my_distributor.name } - page.should have_content 'You are shopping at My Distributor' - - # Then I should see distributor-scoped product counts next to the taxons - page.should have_selector 'nav#taxonomies li', :text => 'Taxon one (1)' - page.should have_selector 'nav#taxonomies li', :text => 'Taxon two (0)' - page.should have_selector 'nav#taxonomies li', :text => 'Taxon three (2)' - end - - - describe "selecting an order cycle" do - - before(:each) do - OrderCyclesHelper.class_eval do - def order_cycles_enabled? - true - end - end - end - - scenario "viewing product counts when an order cycle is selected", :future => true do - # Given some taxons and some products and some order cycles - taxonomy = Spree::Taxonomy.find_by_name('Products') || create(:taxonomy, :name => 'Products') - taxonomy_root = taxonomy.root - - taxon_one = create(:taxon, :name => 'Taxon one', :parent_id => taxonomy_root.id) - taxon_two = create(:taxon, :name => 'Taxon two', :parent_id => taxonomy_root.id) - taxon_three = create(:taxon, :name => 'Taxon three', :parent_id => taxonomy_root.id) - - supplier = create(:supplier_enterprise, :name => 'My Supplier') - distributor = create(:distributor_enterprise, :name => 'My Distributor') - - t1p1 = create(:product, :taxons => [taxon_one], :distributors => [distributor]) - t2p1 = create(:product, :taxons => [taxon_two], :distributors => [distributor]) - t2p2 = create(:product, :taxons => [taxon_two], :distributors => [distributor]) - t3p1 = create(:product, :taxons => [taxon_three], :distributors => [distributor]) - t3p2 = create(:product, :taxons => [taxon_three], :distributors => [distributor]) - - oc1 = create(:simple_order_cycle, suppliers: [supplier], distributors: [distributor], variants: [t1p1.master, t2p1.master, t2p2.master]) - oc2 = create(:simple_order_cycle, suppliers: [supplier], distributors: [distributor], variants: [t3p1.master, t3p2.master]) - - # When I visit the home page and select my order cycle - visit root_path - click_on "Edible garden" - choose oc2.name - click_button 'Choose Order Cycle' - page.should have_content 'Your order cycle has been selected.' - - # Then I should see order cycle-scoped product counts next to the taxons - page.should have_selector 'nav#taxonomies li', :text => 'Taxon one (0)' - page.should have_selector 'nav#taxonomies li', :text => 'Taxon two (0)' - page.should have_selector 'nav#taxonomies li', :text => 'Taxon three (2)' - end - - scenario "viewing product counts when both a distributor and an order cycle are selected", :future => true do - # Given some taxons and some products under distributors - taxonomy = Spree::Taxonomy.find_by_name('Products') || create(:taxonomy, :name => 'Products') - taxonomy_root = taxonomy.root - - taxon_one = create(:taxon, :name => 'Taxon one', :parent_id => taxonomy_root.id) - taxon_two = create(:taxon, :name => 'Taxon two', :parent_id => taxonomy_root.id) - taxon_three = create(:taxon, :name => 'Taxon three', :parent_id => taxonomy_root.id) - - supplier = create(:supplier_enterprise, :name => 'My Supplier') - my_distributor = create(:distributor_enterprise, :name => 'My Distributor') - other_distributor = create(:distributor_enterprise, :name => 'Other Distributor') - - p1 = create(:product, :taxons => [taxon_one]) - p2 = create(:product, :taxons => [taxon_two]) - p3 = create(:product, :taxons => [taxon_three]) - p4 = create(:product, :taxons => [taxon_one]) - p5 = create(:product, :taxons => [taxon_two]) - - oc1 = create(:simple_order_cycle, suppliers: [supplier]) - oc2 = create(:simple_order_cycle, suppliers: [supplier]) - create(:exchange, order_cycle: oc1, sender: oc1.coordinator, receiver: my_distributor, variants: [p1.master]) - create(:exchange, order_cycle: oc2, sender: oc2.coordinator, receiver: my_distributor, variants: [p2.master]) - create(:exchange, order_cycle: oc1, sender: oc1.coordinator, receiver: other_distributor, variants: [p3.master]) - create(:exchange, order_cycle: oc2, sender: oc2.coordinator, receiver: other_distributor, variants: [p4.master, p5.master]) - - # When I visit the home page and select my distributor and order cycle - visit spree.select_distributor_order_path(my_distributor) - within('nav#filters') { click_link my_distributor.name } - page.should have_content 'You are shopping at My Distributor' - visit root_path - click_on "Edible garden" - choose oc2.name - click_button 'Choose Order Cycle' - page.should have_content 'Your order cycle has been selected.' - - # Then I should see distributor- and order-cycle-scoped product counts next to the taxons - page.should have_selector 'nav#taxonomies li', :text => 'Taxon one (0)' - page.should have_selector 'nav#taxonomies li', :text => 'Taxon two (1)' - page.should have_selector 'nav#taxonomies li', :text => 'Taxon three (0)' - end - end -end diff --git a/spec/features/consumer/temp_landing_page_spec.rb b/spec/features/consumer/temp_landing_page_spec.rb index b0cc4adab2..183284514f 100644 --- a/spec/features/consumer/temp_landing_page_spec.rb +++ b/spec/features/consumer/temp_landing_page_spec.rb @@ -61,21 +61,20 @@ feature %q{ end it "should grey out hubs that are not in an order cycle" do - create(:simple_order_cycle, distributors: [d1, d3]) create(:simple_product, distributors: [d1, d2]) visit root_path page.should have_selector 'a.shop-distributor.active', text: 'Murandaka' - page.should have_selector 'a.shop-distributor.inactive', text: 'Ballantyne' + page.should have_selector 'a.shop-distributor.inactive', text: 'Ballantyne' page.should have_selector 'a.shop-distributor.active', text: "O'Hea Street" page.should have_selector 'a.shop-distributor.inactive', text: 'PepperTree Place' end it "should link to the hub page" do click_on 'Murandaka' - page.should have_content 'CART' + current_path.should == "/shop" end end diff --git a/spec/helpers/html_helper_spec.rb b/spec/helpers/html_helper_spec.rb index 729da60d48..3a19ddfce0 100644 --- a/spec/helpers/html_helper_spec.rb +++ b/spec/helpers/html_helper_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe HtmlHelper do describe "stripping html from a string" do it "strips tags" do - helper.strip_html('

Hello world!

').should == 'Hello world!' + helper.strip_html('

Hello world!

').should == "Hello world!" end it "removes nbsp and amp entities" do @@ -13,5 +13,30 @@ describe HtmlHelper do it "returns nil for nil input" do helper.strip_html(nil).should be_nil end + + describe "line breaks" do + it "adds two line breaks after heading tags" do + helper.strip_html("

foo

bar").should == "foo\n\nbar"; + helper.strip_html("

foo

bar").should == "foo\n\nbar"; + end + + it "adds two line breaks after p tags" do + helper.strip_html("

foo

bar").should == "foo\n\nbar"; + end + + it "adds two line breaks after div tags" do + helper.strip_html("
foo
bar").should == "foo\n\nbar"; + end + + it "adds a line break after br tags" do + helper.strip_html("foo
bar").should == "foo\nbar"; + helper.strip_html("foo
bar").should == "foo\nbar"; + helper.strip_html("foo
bar").should == "foo\nbar"; + end + + it "strips line breaks at the end of the string" do + helper.strip_html("
foo

").should == "foo"; + end + end end end diff --git a/spec/javascripts/unit/bulk_product_update_spec.js.coffee b/spec/javascripts/unit/bulk_product_update_spec.js.coffee index bd85419ac9..58a5ce1941 100644 --- a/spec/javascripts/unit/bulk_product_update_spec.js.coffee +++ b/spec/javascripts/unit/bulk_product_update_spec.js.coffee @@ -690,6 +690,21 @@ describe "AdminProductEditCtrl", -> variant_unit_scale: 1000 variant_unit_with_scale: 'volume_1000' + it "extracts a null value into null variant_unit and variant_unit_scale", -> + testProduct = + id: 1 + variant_unit: 'weight' + variant_unit_scale: 1 + variant_unit_with_scale: null + + scope.packProduct(testProduct) + + expect(testProduct).toEqual + id: 1 + variant_unit: null + variant_unit_scale: null + variant_unit_with_scale: null + it "extracts when variant_unit_with_scale is 'items'", -> testProduct = id: 1 diff --git a/spec/javascripts/unit/darkswarm/controllers/checkout_controller_spec.js.coffee b/spec/javascripts/unit/darkswarm/controllers/checkout_controller_spec.js.coffee new file mode 100644 index 0000000000..fae814e4e8 --- /dev/null +++ b/spec/javascripts/unit/darkswarm/controllers/checkout_controller_spec.js.coffee @@ -0,0 +1,34 @@ +describe "CheckoutCtrl", -> + ctrl = null + scope = null + order = null + + beforeEach -> + module("Darkswarm") + order = + id: 3102 + shipping_method_id: "7" + ship_address_same_as_billing: true + payment_method_id: null + shipping_methods: + 7: + require_ship_address: true + price: 0.0 + + 25: + require_ship_address: false + price: 13 + inject ($controller) -> + scope = {} + ctrl = $controller 'CheckoutCtrl', {$scope: scope, order: order} + + + it 'Gets the ship address automatically', -> + expect(scope.require_ship_address).toEqual true + + it 'Gets the current shipping price', -> + expect(scope.shippingPrice()).toEqual 0.0 + scope.order.shipping_method_id = 25 + expect(scope.shippingPrice()).toEqual 13 + + diff --git a/spec/javascripts/unit/darkswarm/controllers/ordercycle_controller_spec.js.coffee b/spec/javascripts/unit/darkswarm/controllers/ordercycle_controller_spec.js.coffee new file mode 100644 index 0000000000..260f51982a --- /dev/null +++ b/spec/javascripts/unit/darkswarm/controllers/ordercycle_controller_spec.js.coffee @@ -0,0 +1,18 @@ +describe 'OrderCycleCtrl', -> + ctrl = null + scope = null + event = null + product_ctrl = null + OrderCycle = null + + beforeEach -> + module 'Darkswarm' + scope = {} + OrderCycle = + order_cycle: "test" + inject ($controller) -> + scope = {} + ctrl = $controller 'OrderCycleCtrl', {$scope: scope, OrderCycle: OrderCycle} + + it "puts the order cycle in scope", -> + expect(scope.order_cycle).toEqual "test" diff --git a/spec/javascripts/unit/darkswarm/controllers_spec.js.coffee b/spec/javascripts/unit/darkswarm/controllers/products_controller_spec.js.coffee similarity index 96% rename from spec/javascripts/unit/darkswarm/controllers_spec.js.coffee rename to spec/javascripts/unit/darkswarm/controllers/products_controller_spec.js.coffee index f7717b6737..269c8385b8 100644 --- a/spec/javascripts/unit/darkswarm/controllers_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/controllers/products_controller_spec.js.coffee @@ -6,7 +6,7 @@ describe 'All controllers', -> Product = null beforeEach -> - module('Shop') + module('Darkswarm') Product = all: -> update: -> @@ -40,9 +40,8 @@ describe 'All controllers', -> OrderCycle = null beforeEach -> - module 'Shop' + module 'Darkswarm' scope = {} inject ($controller) -> scope = {} ctrl = $controller 'OrderCycleCtrl', {$scope: scope} - diff --git a/spec/javascripts/unit/darkswarm/controllers/sidebar_controller_spec.js.coffee b/spec/javascripts/unit/darkswarm/controllers/sidebar_controller_spec.js.coffee new file mode 100644 index 0000000000..d9348021d7 --- /dev/null +++ b/spec/javascripts/unit/darkswarm/controllers/sidebar_controller_spec.js.coffee @@ -0,0 +1,24 @@ +describe "SidebarCtrl", -> + ctrl = null + scope = null + location = null + + beforeEach -> + module("Darkswarm") + location = + path: -> + "/test" + inject ($controller, $rootScope) -> + scope = $rootScope + ctrl = $controller 'SidebarCtrl', {$scope: scope, $location: location} + scope.$apply() + + it 'tracks the active sidebar from the $location', -> + expect(scope.active_sidebar).toEqual "/test" + + it 'is active when a location is set', -> + expect(scope.active()).toEqual "active" + + it 'is inactive no location is set', -> + scope.active_sidebar = null + expect(scope.active()).toEqual null diff --git a/spec/javascripts/unit/darkswarm/order_cycle_spec.js.coffee b/spec/javascripts/unit/darkswarm/order_cycle_spec.js.coffee index e7ef7f60b1..395b51512e 100644 --- a/spec/javascripts/unit/darkswarm/order_cycle_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/order_cycle_spec.js.coffee @@ -6,8 +6,8 @@ describe 'OrderCycle service', -> } beforeEach -> - angular.module('Shop').value('orderCycleData', {}) - module 'Shop', ($provide)-> + angular.module('Darkswarm').value('orderCycleData', {}) + module 'Darkswarm', ($provide)-> $provide.value "Product", mockProduct null # IMPORTANT # You must return null because module() is a bit dumb diff --git a/spec/javascripts/unit/darkswarm/product_spec.js.coffee b/spec/javascripts/unit/darkswarm/product_spec.js.coffee index fd2a8f4edb..7108d819af 100644 --- a/spec/javascripts/unit/darkswarm/product_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/product_spec.js.coffee @@ -3,7 +3,7 @@ describe 'Product service', -> Product = null beforeEach -> - module 'Shop' + module 'Darkswarm' inject ($injector, _$httpBackend_)-> Product = $injector.get("Product") $httpBackend = _$httpBackend_ diff --git a/spec/lib/open_food_network/products_and_inventory_report_spec.rb b/spec/lib/open_food_network/products_and_inventory_report_spec.rb index c65d7bcae0..33b507faab 100644 --- a/spec/lib/open_food_network/products_and_inventory_report_spec.rb +++ b/spec/lib/open_food_network/products_and_inventory_report_spec.rb @@ -110,7 +110,7 @@ module OpenFoodNetwork it "should return unfiltered variants sans-params" do product1 = create(:simple_product, supplier: supplier) product2 = create(:simple_product, supplier: supplier) - subject.filter(Spree::Variant.scoped).should == [product1.master, product2.master] + subject.filter(Spree::Variant.scoped).sort.should == [product1.master, product2.master].sort end describe "based on report type" do it "returns only variants on hand" do diff --git a/spec/models/exchange_spec.rb b/spec/models/exchange_spec.rb index 7095dd03f9..675f7d475a 100644 --- a/spec/models/exchange_spec.rb +++ b/spec/models/exchange_spec.rb @@ -111,19 +111,22 @@ describe Exchange do Exchange.with_variant(v).should == [ex] end - it "finds exchanges with any of a number of variants" do + it "finds exchanges with any of a number of variants, without returning duplicates" do v1 = create(:variant) v2 = create(:variant) + v3 = create(:variant) ex = create(:exchange) ex.variants << v1 + ex.variants << v2 - Exchange.any_variant([v1, v2]).should == [ex] + Exchange.with_any_variant([v1, v2, v3]).should == [ex] end it "finds exchanges with a particular product's master variant" do p = create(:simple_product) ex = create(:exchange) ex.variants << p.master + p.reload Exchange.with_product(p).should == [ex] end @@ -133,6 +136,7 @@ describe Exchange do v = create(:variant, product: p) ex = create(:exchange) ex.variants << v + p.reload Exchange.with_product(p).should == [ex] end diff --git a/spec/models/order_cycle_spec.rb b/spec/models/order_cycle_spec.rb index 47e49a73e3..784d778682 100644 --- a/spec/models/order_cycle_spec.rb +++ b/spec/models/order_cycle_spec.rb @@ -63,6 +63,8 @@ describe OrderCycle do p = create(:product) d = create(:distributor_enterprise) oc = create(:simple_order_cycle, distributors: [d], variants: [p.master]) + p.reload + OrderCycle.distributing_product(p).should == [oc] end @@ -71,6 +73,8 @@ describe OrderCycle do v = create(:variant, product: p) d = create(:distributor_enterprise) oc = create(:simple_order_cycle, distributors: [d], variants: [v]) + p.reload + OrderCycle.distributing_product(p).should == [oc] end @@ -80,6 +84,7 @@ describe OrderCycle do oc = create(:simple_order_cycle) ex = create(:exchange, order_cycle: oc, sender: s, receiver: oc.coordinator) ex.variants << p.master + p.reload OrderCycle.distributing_product(p).should == [] end @@ -217,6 +222,58 @@ describe OrderCycle do end end + describe "finding valid products distributed by a particular distributor" do + it "returns valid products but not invalid products" do + p_valid = create(:product) + p_invalid = create(:product) + v = create(:variant, product: p_invalid) + + d = create(:distributor_enterprise) + oc = create(:simple_order_cycle, distributors: [d], variants: [p_valid.master, p_invalid.master]) + oc.valid_products_distributed_by(d).should == [p_valid] + end + + describe "checking if a product has only an obsolete master variant in a distributution" do + it "returns true when so" do + master = double(:master) + unassociated_variant = double(:variant) + product = double(:product, :has_variants? => true, :master => master, :variants => []) + distributed_variants = [master, unassociated_variant] + + oc = OrderCycle.new + oc.send(:product_has_only_obsolete_master_in_distribution?, product, distributed_variants).should be_true + end + + it "returns false when the product doesn't have variants" do + master = double(:master) + product = double(:product, :has_variants? => false, :master => master, :variants => []) + distributed_variants = [master] + + oc = OrderCycle.new + oc.send(:product_has_only_obsolete_master_in_distribution?, product, distributed_variants).should be_false + end + + it "returns false when the master isn't distributed" do + master = double(:master) + product = double(:product, :has_variants? => true, :master => master, :variants => []) + distributed_variants = [] + + oc = OrderCycle.new + oc.send(:product_has_only_obsolete_master_in_distribution?, product, distributed_variants).should be_false + end + + it "returns false when the product has other variants distributed" do + master = double(:master) + variant = double(:variant) + product = double(:product, :has_variants? => true, :master => master, :variants => [variant]) + distributed_variants = [master, variant] + + oc = OrderCycle.new + oc.send(:product_has_only_obsolete_master_in_distribution?, product, distributed_variants).should be_false + end + end + end + describe "exchanges" do before(:each) do @oc = create(:simple_order_cycle) diff --git a/spec/models/spree/ability_spec.rb b/spec/models/spree/ability_spec.rb index 193a6c0fd5..71160c7f87 100644 --- a/spec/models/spree/ability_spec.rb +++ b/spec/models/spree/ability_spec.rb @@ -48,11 +48,11 @@ module Spree end it "should be able to read/write their enterprises' product properties" do - should have_ability([:admin, :index, :read, :create, :edit, :destroy], for: Spree::ProductProperty) + should have_ability([:admin, :index, :read, :create, :edit, :update_positions, :destroy], for: Spree::ProductProperty) end it "should be able to read/write their enterprises' product images" do - should have_ability([:admin, :index, :read, :create, :edit], for: Spree::Image) + should have_ability([:admin, :index, :read, :create, :edit, :update, :destroy], for: Spree::Image) end it "should be able to read Taxons (in order to create classifications)" do diff --git a/spec/models/spree/order_spec.rb b/spec/models/spree/order_spec.rb index ff17188998..80a65b79cc 100644 --- a/spec/models/spree/order_spec.rb +++ b/spec/models/spree/order_spec.rb @@ -22,6 +22,19 @@ describe Spree::Order do end end + describe "Payment methods" do + let(:order) { build(:order, distributor: create(:distributor_enterprise)) } + let(:pm1) { create(:payment_method, distributors: [order.distributor])} + let(:pm2) { create(:payment_method, distributors: [])} + + it "finds the correct payment methods" do + Spree::PaymentMethod.stub(:available).and_return [pm1, pm2] + order.available_payment_methods.include?(pm2).should == false + order.available_payment_methods.include?(pm1).should == true + end + + end + describe "updating the distribution charge" do let(:order) { build(:order) } diff --git a/spec/models/spree/product_spec.rb b/spec/models/spree/product_spec.rb index d42f811422..813a57558f 100644 --- a/spec/models/spree/product_spec.rb +++ b/spec/models/spree/product_spec.rb @@ -429,6 +429,16 @@ module Spree p.update_attributes!(variant_unit: 'volume', variant_unit_scale: 0.001) }.to change(v.option_values(true), :count).by(-1) end + + it "removes the related option values from its master variant" do + ot = Spree::OptionType.find_by_name 'unit_weight' + p.master.update_attributes!(unit_value: 1) + p.reload + + expect { + p.update_attributes!(variant_unit: 'volume', variant_unit_scale: 0.001) + }.to change(p.master.option_values(true), :count).by(-1) + end end describe "returning the variant unit option type" do diff --git a/spec/models/spree/variant_spec.rb b/spec/models/spree/variant_spec.rb index fee4dc1edd..d51a34e254 100644 --- a/spec/models/spree/variant_spec.rb +++ b/spec/models/spree/variant_spec.rb @@ -16,7 +16,7 @@ module Spree end it "returns variants in stock or on demand, but not those that are neither" do - Variant.where(is_master: false).in_stock.should == [@v_in_stock, @v_on_demand] + Variant.where(is_master: false).in_stock.sort.should == [@v_in_stock, @v_on_demand].sort end end end