diff --git a/app/assets/javascripts/admin/bulk_product_update.js.coffee b/app/assets/javascripts/admin/bulk_product_update.js.coffee index 751734a899..7a9d2677b9 100644 --- a/app/assets/javascripts/admin/bulk_product_update.js.coffee +++ b/app/assets/javascripts/admin/bulk_product_update.js.coffee @@ -1,4 +1,4 @@ -angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $http, BulkProducts, DisplayProperties, dataFetcher, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, SpreeApiAuth, Columns, tax_categories) -> +angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $http, $window, BulkProducts, DisplayProperties, dataFetcher, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, SpreeApiAuth, Columns, tax_categories) -> $scope.loading = true $scope.StatusMessage = StatusMessage @@ -206,6 +206,8 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout else $scope.displayFailure t("products_update_error_data") + status + $scope.cancel = (destination) -> + $window.location = destination $scope.packProduct = (product) -> if product.variant_unit_with_scale @@ -247,6 +249,7 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout $scope.displaySuccess = -> StatusMessage.display 'success',t("products_changes_saved") + $scope.bulk_product_form.$setPristine() $scope.displayFailure = (failMessage) -> diff --git a/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee b/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee index aefcab9f90..50f8301cfc 100644 --- a/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee +++ b/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee @@ -18,6 +18,20 @@ angular.module("admin.customers").controller "customersCtrl", ($scope, $q, $filt $scope.customers_form.$setPristine() $scope.customers = data + $scope.checkForDuplicateCodes = -> + delete this.customer.code unless this.customer.code + this.duplicate = $scope.isDuplicateCode(this.customer.code) + + $scope.isDuplicateCode = (code) -> + return false unless code + customers = $scope.findByCode(code) + customers.length > 1 + + $scope.findByCode = (code) -> + if $scope.customers + $scope.customers.filter (customer) -> + customer.code == code + $scope.findTags = (query) -> defer = $q.defer() params = diff --git a/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee b/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee index a806691465..f21c96a27e 100644 --- a/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee +++ b/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee @@ -1,5 +1,5 @@ angular.module("admin.enterprises") - .controller "enterpriseCtrl", ($scope, NavigationCheck, enterprise, EnterprisePaymentMethods, EnterpriseShippingMethods, SideMenu) -> + .controller "enterpriseCtrl", ($scope, $window, NavigationCheck, enterprise, EnterprisePaymentMethods, EnterpriseShippingMethods, SideMenu, StatusMessage) -> $scope.Enterprise = enterprise $scope.PaymentMethods = EnterprisePaymentMethods.paymentMethods $scope.ShippingMethods = EnterpriseShippingMethods.shippingMethods @@ -8,6 +8,23 @@ angular.module("admin.enterprises") $scope.menu = SideMenu $scope.newManager = { id: '', email: (t('add_manager')) } + $scope.StatusMessage = StatusMessage + + $scope.$watch 'enterprise_form.$dirty', (newValue) -> + StatusMessage.display 'notice', 'You have unsaved changes' if newValue + + $scope.setFormDirty = -> + $scope.$apply -> + $scope.enterprise_form.$setDirty() + + $scope.cancel = (destination) -> + $window.location = destination + + $scope.submit = -> + $scope.navClear() + enterprise_form.submit() + + # Provide a callback for generating warning messages displayed before leaving the page. This is passed in # from a directive "nav-check" in the page - if we pass it here it will be called in the test suite, # and on all new uses of this contoller, and we might not want that . diff --git a/app/assets/javascripts/admin/order_cycles/controllers/create.js.coffee b/app/assets/javascripts/admin/order_cycles/controllers/create.js.coffee index 3f28b27f9f..e0f7cf96b6 100644 --- a/app/assets/javascripts/admin/order_cycles/controllers/create.js.coffee +++ b/app/assets/javascripts/admin/order_cycles/controllers/create.js.coffee @@ -1,5 +1,5 @@ angular.module('admin.orderCycles') - .controller 'AdminCreateOrderCycleCtrl', ($scope, $filter, OrderCycle, Enterprise, EnterpriseFee, ocInstance, StatusMessage) -> + .controller 'AdminCreateOrderCycleCtrl', ($scope, $filter, $window, OrderCycle, Enterprise, EnterpriseFee, ocInstance, StatusMessage) -> $scope.enterprises = Enterprise.index(coordinator_id: ocInstance.coordinator_id) $scope.supplier_enterprises = Enterprise.producer_enterprises $scope.distributor_enterprises = Enterprise.hub_enterprises @@ -11,6 +11,9 @@ angular.module('admin.orderCycles') $scope.StatusMessage = StatusMessage + $scope.$watch 'order_cycle_form.$dirty', (newValue) -> + StatusMessage.display 'notice', 'You have unsaved changes' if newValue + $scope.loaded = -> Enterprise.loaded && EnterpriseFee.loaded && OrderCycle.loaded @@ -55,6 +58,7 @@ angular.module('admin.orderCycles') $scope.removeExchange = ($event, exchange) -> $event.preventDefault() OrderCycle.removeExchange(exchange) + $scope.order_cycle_form.$dirty = true $scope.addCoordinatorFee = ($event) -> $event.preventDefault() @@ -77,4 +81,9 @@ angular.module('admin.orderCycles') $scope.submit = ($event, destination) -> $event.preventDefault() + StatusMessage.display 'progress', "Saving..." OrderCycle.create(destination) + + $scope.cancel = (destination) -> + $window.location = destination + diff --git a/app/assets/javascripts/admin/order_cycles/controllers/simple_create.js.coffee b/app/assets/javascripts/admin/order_cycles/controllers/simple_create.js.coffee index dfa8011167..7a0a03f2bf 100644 --- a/app/assets/javascripts/admin/order_cycles/controllers/simple_create.js.coffee +++ b/app/assets/javascripts/admin/order_cycles/controllers/simple_create.js.coffee @@ -1,4 +1,4 @@ -angular.module('admin.orderCycles').controller "AdminSimpleCreateOrderCycleCtrl", ($scope, OrderCycle, Enterprise, EnterpriseFee, StatusMessage, ocInstance) -> +angular.module('admin.orderCycles').controller "AdminSimpleCreateOrderCycleCtrl", ($scope, $window, OrderCycle, Enterprise, EnterpriseFee, StatusMessage, ocInstance) -> $scope.StatusMessage = StatusMessage $scope.OrderCycle = OrderCycle $scope.order_cycle = OrderCycle.new {coordinator_id: ocInstance.coordinator_id}, => @@ -7,6 +7,9 @@ angular.module('admin.orderCycles').controller "AdminSimpleCreateOrderCycleCtrl" $scope.init(enterprises) $scope.enterprise_fees = EnterpriseFee.index(coordinator_id: ocInstance.coordinator_id) + $scope.$watch 'order_cycle_form.$dirty', (newValue) -> + StatusMessage.display 'notice', 'You have unsaved changes' if newValue + $scope.init = (enterprises) -> enterprise = enterprises[Object.keys(enterprises)[0]] OrderCycle.addSupplier enterprise.id @@ -43,5 +46,9 @@ angular.module('admin.orderCycles').controller "AdminSimpleCreateOrderCycleCtrl" $scope.submit = ($event, destination) -> $event.preventDefault() + StatusMessage.display 'progress', "Saving..." OrderCycle.mirrorIncomingToOutgoingProducts() OrderCycle.create(destination) + + $scope.cancel = (destination) -> + $window.location = destination diff --git a/app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee b/app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee index f5bae5a4d8..7df7ddff34 100644 --- a/app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee +++ b/app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee @@ -1,4 +1,4 @@ -angular.module('admin.orderCycles').controller "AdminSimpleEditOrderCycleCtrl", ($scope, $location, OrderCycle, Enterprise, EnterpriseFee, StatusMessage) -> +angular.module('admin.orderCycles').controller "AdminSimpleEditOrderCycleCtrl", ($scope, $location, $window, OrderCycle, Enterprise, EnterpriseFee, StatusMessage) -> $scope.orderCycleId = -> $location.absUrl().match(/\/admin\/order_cycles\/(\d+)/)[1] @@ -42,3 +42,6 @@ angular.module('admin.orderCycles').controller "AdminSimpleEditOrderCycleCtrl", StatusMessage.display 'progress', "Saving..." OrderCycle.mirrorIncomingToOutgoingProducts() OrderCycle.update(destination, $scope.order_cycle_form) + + $scope.cancel = (destination) -> + $window.location = destination diff --git a/app/assets/javascripts/admin/tag_rules/controllers/tag_rules_controller.js.coffee b/app/assets/javascripts/admin/tag_rules/controllers/tag_rules_controller.js.coffee index 45f98a2b57..460d8565eb 100644 --- a/app/assets/javascripts/admin/tag_rules/controllers/tag_rules_controller.js.coffee +++ b/app/assets/javascripts/admin/tag_rules/controllers/tag_rules_controller.js.coffee @@ -38,6 +38,7 @@ angular.module("admin.tagRules").controller "TagRulesCtrl", ($scope, $http, $fil newRule.peferred_exchange_tags = [] newRule.preferred_matched_order_cycles_visibility = "visible" tagGroup.rules.push(newRule) + $scope.enterprise_form.$setDirty() $scope.updateRuleCounts() $scope.addNewTag = -> diff --git a/app/assets/javascripts/admin/utils/directives/sortable.js.coffee b/app/assets/javascripts/admin/utils/directives/sortable.js.coffee index 2f2f100e31..19f527bc0f 100644 --- a/app/assets/javascripts/admin/utils/directives/sortable.js.coffee +++ b/app/assets/javascripts/admin/utils/directives/sortable.js.coffee @@ -20,17 +20,18 @@ angular.module("admin.utils").directive "ofnSortable", ($timeout, $parse) -> items: scope.items appendTo: element update: (event, ui) -> - sortableSiblings = ($(ss) for ss in ui.item.siblings(scope.items)) - offset = Math.min(ui.item.index(), sortableSiblings[0].index()) - newPos = ui.item.index() - offset + 1 - oldPos = getScopePos(ui.item.scope()) - if newPos < oldPos - for sibScope in sortableSiblings.map((ss) -> ss.scope()) - pos = getScopePos(sibScope) - setScopePos(sibScope, pos + 1) if pos >= newPos && pos < oldPos - else if newPos > oldPos - for sibScope in sortableSiblings.map((ss) -> ss.scope()) - pos = getScopePos(sibScope) - setScopePos(sibScope, pos - 1) if pos > oldPos && pos <= newPos - setScopePos(ui.item.scope(), newPos) - scope.afterSort() + scope.$apply -> + sortableSiblings = ($(ss) for ss in ui.item.siblings(scope.items)) + offset = Math.min(ui.item.index(), sortableSiblings[0].index()) + newPos = ui.item.index() - offset + 1 + oldPos = getScopePos(ui.item.scope()) + if newPos < oldPos + for sibScope in sortableSiblings.map((ss) -> ss.scope()) + pos = getScopePos(sibScope) + setScopePos(sibScope, pos + 1) if pos >= newPos && pos < oldPos + else if newPos > oldPos + for sibScope in sortableSiblings.map((ss) -> ss.scope()) + pos = getScopePos(sibScope) + setScopePos(sibScope, pos - 1) if pos > oldPos && pos <= newPos + setScopePos(ui.item.scope(), newPos) + scope.afterSort() diff --git a/app/models/customer.rb b/app/models/customer.rb index 34f62a6aa6..b2141df9ec 100644 --- a/app/models/customer.rb +++ b/app/models/customer.rb @@ -5,8 +5,9 @@ class Customer < ActiveRecord::Base belongs_to :user, class_name: Spree.user_class before_validation :downcase_email + before_validation :empty_code - validates :code, uniqueness: { scope: :enterprise_id, allow_blank: true, allow_nil: true } + validates :code, uniqueness: { scope: :enterprise_id, allow_nil: true } validates :email, presence: true, uniqueness: { scope: :enterprise_id, message: I18n.t('validation_msg_is_associated_with_an_exising_customer') } validates :enterprise_id, presence: true @@ -20,6 +21,10 @@ class Customer < ActiveRecord::Base email.andand.downcase! end + def empty_code + self.code = nil if code.blank? + end + def associate_user self.user = user || Spree::User.find_by_email(email) end diff --git a/app/views/admin/customers/index.html.haml b/app/views/admin/customers/index.html.haml index 65523cda57..98e8b3c414 100644 --- a/app/views/admin/customers/index.html.haml +++ b/app/views/admin/customers/index.html.haml @@ -68,7 +68,9 @@ -# %input{ :type => "checkbox", :name => 'bulk', 'ng-model' => 'customer.checked' } %td.email{ 'ng-show' => 'columns.email.visible', "ng-bind" => '::customer.email' } %td.code{ 'ng-show' => 'columns.code.visible' } - %input{ :type => 'text', :name => 'code', :id => 'code', 'ng-model' => 'customer.code', 'obj-for-update' => "customer", "attr-for-update" => "code" } + %input{ type: 'text', name: 'code', ng: {model: 'customer.code', change: 'checkForDuplicateCodes()'}, "obj-for-update" => "customer", "attr-for-update" => "code" } + %i.icon-warning-sign{ ng: {if: 'duplicate'} } + = t('.duplicate_code') %td.tags{ 'ng-show' => 'columns.tags.visible' } .tag_watcher{ 'obj-for-update' => "customer", "attr-for-update" => "tag_list"} %tags_with_translation{ object: 'customer', 'find-tags' => 'findTags(query)' } diff --git a/app/views/admin/enterprises/_ng_form.html.haml b/app/views/admin/enterprises/_ng_form.html.haml index a19bc43314..ca38b7eca4 100644 --- a/app/views/admin/enterprises/_ng_form.html.haml +++ b/app/views/admin/enterprises/_ng_form.html.haml @@ -1,12 +1,18 @@ -# Not all inputs are ng inputs, they don't make the ng-form dirty on change. -# ng-change is only valid for inputs, not for a form. -# So we use onchange and have to get the scope to access the ng controller -= form_for [main_app, :admin, @enterprise], html: { name: "enterprise", += form_for [main_app, :admin, @enterprise], html: { name: "enterprise_form", "ng-app" => 'admin.enterprises', - "ng-submit" => "navClear()", "ng-controller" => 'enterpriseCtrl', - 'onchange' => 'angular.element(enterprise).scope().enterprise.$setDirty()', + 'onchange' => 'angular.element(enterprise_form).scope().setFormDirty()', } do |f| + + %save-bar{ dirty: "enterprise_form.$dirty", persist: "true" } + %input.red{ type: "button", value: "Update", ng: { click: "submit()", disabled: "!enterprise_form.$dirty" } } + %input{ type: "button", ng: { value: "enterprise_form.$dirty ? 'Cancel' : 'Close'", click: "cancel('#{main_app.admin_enterprises_path}')" } } + + + .row .sixteen.columns.alpha .four.columns.alpha @@ -14,8 +20,3 @@ .one.column   .eleven.columns.omega.fullwidth_inputs = render 'form', f: f - .row - .five.columns.alpha -   - .eleven.columns.alpha - = render partial: "spree/admin/shared/#{action}_resource_links" diff --git a/app/views/admin/order_cycles/_form.html.haml b/app/views/admin/order_cycles/_form.html.haml index a0f0a178c8..ebe9e45905 100644 --- a/app/views/admin/order_cycles/_form.html.haml +++ b/app/views/admin/order_cycles/_form.html.haml @@ -46,9 +46,6 @@ = render 'add_exchange_form', f: f, type: 'distributor' .actions - - if @order_cycle.new_record? - = f.submit 'Create', 'ng-click' => "submit($event, '#{main_app.admin_order_cycles_path}')", 'ng-disabled' => '!loaded()' - %span{'ng-hide' => 'loaded()'} Loading... diff --git a/app/views/admin/order_cycles/_simple_form.html.haml b/app/views/admin/order_cycles/_simple_form.html.haml index 6bb0034c73..a7a0363cd3 100644 --- a/app/views/admin/order_cycles/_simple_form.html.haml +++ b/app/views/admin/order_cycles/_simple_form.html.haml @@ -21,7 +21,4 @@ = render 'coordinator_fees', f: f .actions - - if @order_cycle.new_record? - = f.submit 'Create', 'ng-click' => "submit($event, '#{main_app.admin_order_cycles_path}')", 'ng-disabled' => '!loaded()' - %span{'ng-hide' => 'loaded()'} Loading... diff --git a/app/views/admin/order_cycles/new.html.haml b/app/views/admin/order_cycles/new.html.haml index a257bf3c0b..4e5a95544c 100644 --- a/app/views/admin/order_cycles/new.html.haml +++ b/app/views/admin/order_cycles/new.html.haml @@ -4,7 +4,12 @@ - ng_controller = order_cycles_simple_form ? 'AdminSimpleCreateOrderCycleCtrl' : 'AdminCreateOrderCycleCtrl' = admin_inject_order_cycle_instance -= form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'admin.orderCycles', 'ng-controller' => ng_controller} do |f| += form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'admin.orderCycles', 'ng-controller' => ng_controller, name: 'order_cycle_form'} do |f| + + %save-bar{ dirty: "order_cycle_form.$dirty", persist: "true" } + %input.red{ type: "button", value: "Create", ng: { click: "submit($event, '#{main_app.admin_order_cycles_path}')", disabled: "!order_cycle_form.$dirty" } } + %input{ type: "button", ng: { value: "order_cycle_form.$dirty ? 'Cancel' : 'Close'", click: "cancel('#{main_app.admin_order_cycles_path}')" } } + - if order_cycles_simple_form = render 'simple_form', f: f - else diff --git a/app/views/spree/admin/overview/_order_cycles.html.haml b/app/views/spree/admin/overview/_order_cycles.html.haml index 8628837a47..1a00bd5102 100644 --- a/app/views/spree/admin/overview/_order_cycles.html.haml +++ b/app/views/spree/admin/overview/_order_cycles.html.haml @@ -6,9 +6,8 @@ %a.three.columns.omega.icon-plus.button.blue{ href: "#{main_app.new_admin_order_cycle_path}" } = t "spree_admin_enterprises_create_new" - else - %a.with-tip{ title: t(:spree_admin_order_cycles_tip) } + %a{ "ofn-with-tip" => t(:spree_admin_order_cycles_tip) } = t "admin.whats_this" - %a{ "ofn-with-tip" => "Order cycles determine when and where your products are available to customers." } What's this? %div.seven.columns.alpha.list - if @order_cycle_count > 0 %div.seven.columns.alpha.list-item diff --git a/app/views/spree/admin/products/bulk_edit.html.haml b/app/views/spree/admin/products/bulk_edit.html.haml index 235544cb8a..4e6cf8c704 100644 --- a/app/views/spree/admin/products/bulk_edit.html.haml +++ b/app/views/spree/admin/products/bulk_edit.html.haml @@ -8,4 +8,3 @@ = render 'spree/admin/products/bulk_edit/actions' = render 'spree/admin/products/bulk_edit/indicators' = render 'spree/admin/products/bulk_edit/products' - = render 'spree/admin/products/bulk_edit/save_button_row' diff --git a/app/views/spree/admin/products/bulk_edit/_actions.html.haml b/app/views/spree/admin/products/bulk_edit/_actions.html.haml index 40f135d62e..4a0878bd5c 100644 --- a/app/views/spree/admin/products/bulk_edit/_actions.html.haml +++ b/app/views/spree/admin/products/bulk_edit/_actions.html.haml @@ -1,6 +1,3 @@ .controls.sixteen.columns.alpha{ 'ng-hide' => 'loading || products.length == 0' } - .four.columns.alpha - %input.four.columns.alpha{ :type => 'button', :value => 'Save Changes', 'ng-click' => 'submitProducts()'} - .nine.columns - = render 'spree/admin/shared/status_message' + .thirteen.columns %columns-dropdown{ action: "#{controller_name}_#{action_name}" } diff --git a/app/views/spree/admin/products/bulk_edit/_products.html.haml b/app/views/spree/admin/products/bulk_edit/_products.html.haml index 81fb31573b..b8c580af41 100644 --- a/app/views/spree/admin/products/bulk_edit/_products.html.haml +++ b/app/views/spree/admin/products/bulk_edit/_products.html.haml @@ -1,9 +1,14 @@ %div.sixteen.columns.alpha{ 'ng-hide' => 'loading || filteredProducts.length == 0' } - %table.index#listing_products.bulk{ "infinite-scroll" => "incrementLimit()", "infinite-scroll-distance" => "1" } + %form{ name: 'bulk_product_form' } + %save-bar{ dirty: "bulk_product_form.$dirty", persist: "false" } + %input.red{ type: "button", value: "Save Changes", ng: { click: "submitProducts()", disabled: "!bulk_product_form.$dirty" } } + %input{ type: "button", value: "Close", 'ng-click' => "cancel('#{bulk_edit_admin_products_path}')" } - = render 'spree/admin/products/bulk_edit/products_head' + %table.index#listing_products.bulk{ "infinite-scroll" => "incrementLimit()", "infinite-scroll-distance" => "1" } - %tbody{ 'ng-repeat' => 'product in filteredProducts = ( products | filter:query | producer: producerFilter | category: categoryFilter | limitTo:limit )', 'ng-class-even' => "'even'", 'ng-class-odd' => "'odd'" } + = render 'spree/admin/products/bulk_edit/products_head' - = render 'spree/admin/products/bulk_edit/products_product' - = render 'spree/admin/products/bulk_edit/products_variant' + %tbody{ 'ng-repeat' => 'product in filteredProducts = ( products | filter:query | producer: producerFilter | category: categoryFilter | limitTo:limit )', 'ng-class-even' => "'even'", 'ng-class-odd' => "'odd'" } + + = render 'spree/admin/products/bulk_edit/products_product' + = render 'spree/admin/products/bulk_edit/products_variant' diff --git a/config/environments/production.rb b/config/environments/production.rb index a55540883d..819bb98306 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -31,7 +31,7 @@ Openfoodnetwork::Application.configure do config.force_ssl = true # See everything in the log (default is :info) - # config.log_level = :debug + config.log_level = :warn # Use a different logger for distributed setups # config.logger = SyslogLogger.new diff --git a/config/locales/en.yml b/config/locales/en.yml index 7fd49fc2fe..e103001337 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -113,6 +113,7 @@ en: valid_email_error: Please enter a valid email address add_a_new_customer_for: Add a new customer for %{shop_name} code: Code + duplicate_code: "This code is used already." products: bulk_edit: diff --git a/spec/features/admin/bulk_product_update_spec.rb b/spec/features/admin/bulk_product_update_spec.rb index f7f32f6523..062735ccff 100644 --- a/spec/features/admin/bulk_product_update_spec.rb +++ b/spec/features/admin/bulk_product_update_spec.rb @@ -367,7 +367,10 @@ feature %q{ fill_in "variant_price", with: "10.0" end - click_button 'Save Changes', match: :first + within "#save-bar" do + click_button 'Save Changes' + end + expect(page.find("#status-message")).to have_content "Changes saved." v.reload @@ -384,7 +387,10 @@ feature %q{ fill_in "product_name", with: "new name 1" - click_button 'Save Changes', match: :first + within "#save-bar" do + click_button 'Save Changes' + end + expect(page.find("#status-message")).to have_content "Changes saved." p.reload expect(p.name).to eq "new name 1" @@ -415,24 +421,15 @@ feature %q{ fill_in "product_name", :with => "new product name" - click_button 'Save Changes', match: :first + within "#save-bar" do + click_button 'Save Changes' + end + expect(page.find("#status-message")).to have_content "Changes saved." p.reload expect(p.name).to eq "new product name" end - scenario "updating when no changes have been made" do - Capybara.using_wait_time(2) do - FactoryGirl.create(:product, :name => "product 1") - login_to_admin_section - - visit '/admin/products/bulk_edit' - - click_button 'Save Changes', match: :first - expect(page.find("#status-message")).to have_content "No changes to save." - end - end - scenario "updating when a filter has been applied" do s1 = create(:supplier_enterprise) s2 = create(:supplier_enterprise) @@ -447,7 +444,10 @@ feature %q{ expect(page).to have_no_field "product_name", with: p2.name fill_in "product_name", :with => "new product1" - click_button 'Save Changes', match: :first + within "#save-bar" do + click_button 'Save Changes' + end + expect(page.find("#status-message")).to have_content "Changes saved." p1.reload expect(p1.name).to eq "new product1" diff --git a/spec/features/admin/customers_spec.rb b/spec/features/admin/customers_spec.rb index 3a17c06e32..e0e88af063 100644 --- a/spec/features/admin/customers_spec.rb +++ b/spec/features/admin/customers_spec.rb @@ -62,7 +62,7 @@ feature 'Customers' do within "tr#c_#{customer1.id}" do fill_in "code", with: "new-customer-code" - expect(page).to have_css "input#code.update-pending" + expect(page).to have_css "input[name=code].update-pending" end within "tr#c_#{customer1.id}" do find(:css, "tags-input .tags input").set "awesome\n" @@ -71,7 +71,7 @@ feature 'Customers' do click_button "Save Changes" # Every says it updated - expect(page).to have_css "input#code.update-success" + expect(page).to have_css "input[name=code].update-success" expect(page).to have_css ".tag_watcher.update-success" # And it actually did diff --git a/spec/features/admin/enterprises_spec.rb b/spec/features/admin/enterprises_spec.rb index 3579421b84..4d09007584 100644 --- a/spec/features/admin/enterprises_spec.rb +++ b/spec/features/admin/enterprises_spec.rb @@ -61,6 +61,9 @@ feature %q{ end scenario "editing an existing enterprise", js: true do + # Make the page long enough to avoid the save bar overlaying the form + page.driver.resize(1280, 1000) + @enterprise = create(:enterprise) e2 = create(:enterprise) eg1 = create(:enterprise_group, name: 'eg1') @@ -355,6 +358,10 @@ feature %q{ within("tbody#e_#{distributor1.id}") { click_link 'Manage' } fill_in 'enterprise_name', :with => 'Eaterprises' + + # Because poltergist does not support form onchange event + # We need trigger the change manually + page.evaluate_script("angular.element(enterprise_form).scope().setFormDirty()") click_button 'Update' flash_message.should == 'Enterprise "Eaterprises" has been successfully updated!' @@ -367,6 +374,10 @@ feature %q{ within("tbody#e_#{distributor3.id}") { click_link 'Manage' } fill_in 'enterprise_name', :with => 'Eaterprises' + + # Because poltergist does not support form onchange event + # We need trigger the change manually + page.evaluate_script("angular.element(enterprise_form).scope().setFormDirty()") click_button 'Update' flash_message.should == 'Enterprise "Eaterprises" has been successfully updated!' @@ -407,8 +418,14 @@ feature %q{ # -- Update only select2_select "Certified Organic", from: 'enterprise_producer_properties_attributes_0_property_name' + fill_in 'enterprise_producer_properties_attributes_0_value', with: "NASAA 12345" + + # Because poltergist does not support form onchange event + # We need trigger the change manually + page.evaluate_script("angular.element(enterprise_form).scope().setFormDirty()") click_button 'Update' + supplier1.producer_properties(true).count.should == 1 # -- Destroy diff --git a/spec/features/admin/order_cycles_spec.rb b/spec/features/admin/order_cycles_spec.rb index 1fa85f06e7..74b2e88453 100644 --- a/spec/features/admin/order_cycles_spec.rb +++ b/spec/features/admin/order_cycles_spec.rb @@ -59,6 +59,8 @@ feature %q{ end scenario "creating an order cycle", js: true do + page.driver.resize(1280, 2000) + # Given coordinating, supplying and distributing enterprises with some products with variants coordinator = create(:distributor_enterprise, name: 'My coordinator') supplier = create(:supplier_enterprise, name: 'My supplier') @@ -567,6 +569,9 @@ feature %q{ end scenario "creating a new order cycle" do + # Make the page long enough to avoid the save bar overlaying the form + page.driver.resize(1280, 2000) + click_link "Order Cycles" click_link 'New Order Cycle' @@ -839,6 +844,9 @@ feature %q{ end it "creates order cycles", js: true do + # Make the page long enough to avoid the save bar overlaying the form + page.driver.resize(1280, 2000) + # When I go to the new order cycle page visit admin_order_cycles_path click_link 'New Order Cycle' diff --git a/spec/features/admin/tag_rules_spec.rb b/spec/features/admin/tag_rules_spec.rb index d956ff94b6..f8f25ec181 100644 --- a/spec/features/admin/tag_rules_spec.rb +++ b/spec/features/admin/tag_rules_spec.rb @@ -13,6 +13,9 @@ feature 'Tag Rules', js: true do end it "allows creation of rules of each type" do + # Make the whole page visible + page.driver.resize(1280, 2000) + click_link "Tag Rules" # Creating a new tag @@ -120,6 +123,9 @@ feature 'Tag Rules', js: true do end it "saves changes to rules of each type" do + # Make the whole page visible + page.driver.resize(1280, 2000) + click_link "Tag Rules" # Tag groups exist @@ -228,6 +234,9 @@ feature 'Tag Rules', js: true do end it "deletes both default and customer rules from the database" do + # Make the whole page visible + page.driver.resize(1280, 2000) + click_link "Tag Rules" expect do diff --git a/spec/features/consumer/shopping/shopping_spec.rb b/spec/features/consumer/shopping/shopping_spec.rb index 1e69e97b1c..7dc9f474da 100644 --- a/spec/features/consumer/shopping/shopping_spec.rb +++ b/spec/features/consumer/shopping/shopping_spec.rb @@ -251,6 +251,8 @@ feature "As a consumer I want to shop with a distributor", js: true do describe "when a product goes out of stock just before it's added to the cart" do it "stops the attempt, shows an error message and refreshes the products asynchronously" do + expect(page).to have_content "Product" + variant.update_attributes! on_hand: 0 # -- Messaging diff --git a/spec/features/consumer/shopping/variant_overrides_spec.rb b/spec/features/consumer/shopping/variant_overrides_spec.rb index 92945a60be..b59cb6a613 100644 --- a/spec/features/consumer/shopping/variant_overrides_spec.rb +++ b/spec/features/consumer/shopping/variant_overrides_spec.rb @@ -193,7 +193,7 @@ feature "shopping with variant overrides defined", js: true do end place_order - page.should have_content "Your order has been processed successfully" + expect(page).to have_content "Your order has been processed successfully" end def click_checkout diff --git a/spec/javascripts/unit/admin/customers/controllers/customers_controller_spec.js.coffee b/spec/javascripts/unit/admin/customers/controllers/customers_controller_spec.js.coffee index fca4c6744f..5f190b9382 100644 --- a/spec/javascripts/unit/admin/customers/controllers/customers_controller_spec.js.coffee +++ b/spec/javascripts/unit/admin/customers/controllers/customers_controller_spec.js.coffee @@ -29,7 +29,7 @@ describe "CustomersCtrl", -> expect(CurrentShop.shop).toEqual {} describe "setting the shop on scope", -> - customer = { id: 5, email: 'someone@email.com'} + customer = { id: 5, email: 'someone@email.com', code: 'a'} customers = [customer] beforeEach inject (pendingChanges) -> @@ -52,6 +52,12 @@ describe "CustomersCtrl", -> it "retrievs the list of customers", -> expect(scope.customers).toDeepEqual customers + it "finds customers by code", -> + as = scope.findByCode('a') + expect(as).toDeepEqual customers + as = scope.findByCode('b') + expect(as).toDeepEqual [] + describe "scope.add", -> it "creates a new customer", -> email = "customer@example.org" diff --git a/spec/javascripts/unit/admin/order_cycles/controllers/simple_create.js.coffee b/spec/javascripts/unit/admin/order_cycles/controllers/simple_create.js.coffee index 7404bbead2..70508bc519 100644 --- a/spec/javascripts/unit/admin/order_cycles/controllers/simple_create.js.coffee +++ b/spec/javascripts/unit/admin/order_cycles/controllers/simple_create.js.coffee @@ -8,7 +8,8 @@ describe "AdminSimpleCreateOrderCycleCtrl", -> outgoing_exchange = {} beforeEach -> - scope = {} + scope = + $watch: jasmine.createSpy('$watch') order_cycle = coordinator_id: 123 incoming_exchanges: [incoming_exchange] diff --git a/spec/javascripts/unit/admin/tag_rules/controllers/tag_rules_controller_spec.js.coffee b/spec/javascripts/unit/admin/tag_rules/controllers/tag_rules_controller_spec.js.coffee index 2526016d3d..7ac5cc8fbc 100644 --- a/spec/javascripts/unit/admin/tag_rules/controllers/tag_rules_controller_spec.js.coffee +++ b/spec/javascripts/unit/admin/tag_rules/controllers/tag_rules_controller_spec.js.coffee @@ -15,6 +15,7 @@ describe "TagRulesCtrl", -> inject ($rootScope, $controller) -> scope = $rootScope + scope.enterprise_form = jasmine.createSpyObj('enterprise_form', ['$setDirty']) ctrl = $controller 'TagRulesCtrl', {$scope: scope, enterprise: enterprise} describe "tagGroup start indices", -> @@ -27,6 +28,8 @@ describe "TagRulesCtrl", -> scope.addNewRuleTo(scope.tagGroups[0], "DiscountOrder") it "adds a new rule of the specified type to the rules array for the tagGroup", -> + expect(scope.enterprise_form.$setDirty).toHaveBeenCalled() + expect(scope.tagGroups[0].rules.length).toEqual 3 expect(scope.tagGroups[0].rules[2].type).toEqual "TagRule::DiscountOrder" diff --git a/spec/javascripts/unit/bulk_product_update_spec.js.coffee b/spec/javascripts/unit/bulk_product_update_spec.js.coffee index cc0b574f47..c1c34cbe6b 100644 --- a/spec/javascripts/unit/bulk_product_update_spec.js.coffee +++ b/spec/javascripts/unit/bulk_product_update_spec.js.coffee @@ -668,6 +668,9 @@ describe "AdminProductEditCtrl", -> spyOn $scope, "displaySuccess" spyOn BulkProducts, "updateVariantLists" spyOn DirtyProducts, "clear" + + $scope.bulk_product_form = jasmine.createSpyObj('bulk_product_form', ['$setPristine']) + $scope.products = [ { id: 1 @@ -692,6 +695,7 @@ describe "AdminProductEditCtrl", -> $httpBackend.flush() $timeout.flush() expect($scope.displaySuccess).toHaveBeenCalled() + expect($scope.bulk_product_form.$setPristine).toHaveBeenCalled expect(DirtyProducts.clear).toHaveBeenCalled() expect(BulkProducts.updateVariantLists).toHaveBeenCalled() diff --git a/spec/javascripts/unit/order_cycle_spec.js.coffee b/spec/javascripts/unit/order_cycle_spec.js.coffee index 4a924917c8..5fec8b93f5 100644 --- a/spec/javascripts/unit/order_cycle_spec.js.coffee +++ b/spec/javascripts/unit/order_cycle_spec.js.coffee @@ -9,7 +9,9 @@ describe 'OrderCycle controllers', -> EnterpriseFee = null beforeEach -> - scope = {} + scope = + order_cycle_form: jasmine.createSpyObj('order_cycle_form', ['$dirty']) + $watch: jasmine.createSpy('$watch') event = preventDefault: jasmine.createSpy('preventDefault') OrderCycle = diff --git a/spec/models/customer_spec.rb b/spec/models/customer_spec.rb index f2ac14e9b2..32e380f4d3 100644 --- a/spec/models/customer_spec.rb +++ b/spec/models/customer_spec.rb @@ -1,6 +1,23 @@ require 'spec_helper' describe Customer, type: :model do + describe 'an existing customer' do + let(:customer) { create(:customer) } + + it "saves its code" do + code = "code one" + customer.code = code + customer.save + expect(customer.code).to eq code + end + + it "can remove its code" do + customer.code = "" + customer.save + expect(customer.code).to be nil + end + end + describe 'creation callbacks' do let!(:user1) { create(:user) } let!(:user2) { create(:user) } diff --git a/spec/support/request/checkout_workflow.rb b/spec/support/request/checkout_workflow.rb index e08fb031da..4a0f37c0ea 100644 --- a/spec/support/request/checkout_workflow.rb +++ b/spec/support/request/checkout_workflow.rb @@ -8,7 +8,7 @@ module CheckoutWorkflow end def place_order - click_button "Place order now" + find("button", text: "Place order now").trigger "click" end def toggle_accordion(id)