Merge branch 'master' of github.com:openfoodfoundation/openfoodnetwork into prod-log-warn
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 317 B |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 619 B |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 313 B |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 1003 KiB After Width: | Height: | Size: 138 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 105 KiB |
|
Before Width: | Height: | Size: 662 KiB After Width: | Height: | Size: 570 KiB |
|
Before Width: | Height: | Size: 300 KiB After Width: | Height: | Size: 283 KiB |
|
Before Width: | Height: | Size: 215 KiB After Width: | Height: | Size: 206 KiB |
|
Before Width: | Height: | Size: 256 KiB After Width: | Height: | Size: 244 KiB |
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 195 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 125 KiB After Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 784 B |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 840 B |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 535 B |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 971 B After Width: | Height: | Size: 957 B |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 39 KiB |
BIN
app/assets/images/select2.png
Executable file → Normal file
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 881 B |
BIN
app/assets/images/select2x2.png
Executable file → Normal file
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 928 B |
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 54 KiB |
@@ -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) ->
|
||||
|
||||
@@ -13,6 +13,20 @@ angular.module("admin.customers").controller "customersCtrl", ($scope, $q, Custo
|
||||
Customers.index({enterprise_id: $scope.CurrentShop.shop.id}).then (data) ->
|
||||
$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 =
|
||||
|
||||
@@ -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 .
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = ->
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -33,7 +33,7 @@ class ProducerMailer < Spree::BaseMailer
|
||||
joins(:order => :order_cycle, :variant => :product).
|
||||
where('order_cycles.id = ?', order_cycle).
|
||||
merge(Spree::Product.in_supplier(producer)).
|
||||
merge(Spree::Order.complete)
|
||||
merge(Spree::Order.by_state('complete'))
|
||||
end
|
||||
|
||||
def total_from_line_items(line_items)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -64,7 +64,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)' }
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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...
|
||||
|
||||
|
||||
|
||||
@@ -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...
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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}" }
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -50,7 +50,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"
|
||||
@@ -59,7 +59,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -22,7 +22,8 @@ feature "Registration", js: true do
|
||||
expect(URI.parse(current_url).path).to eq registration_path
|
||||
|
||||
# Done reading introduction
|
||||
click_button_and_ensure_content "Let's get started!", "Woot! First we need to know a little bit about your enterprise:"
|
||||
page.has_content?
|
||||
click_and_ensure(:button, "Let's get started!", lambda { page.has_content? 'Woot!' })
|
||||
|
||||
# Filling in details
|
||||
fill_in 'enterprise_name', with: "My Awesome Enterprise"
|
||||
@@ -33,23 +34,20 @@ feature "Registration", js: true do
|
||||
fill_in 'enterprise_zipcode', with: '3070'
|
||||
select 'Australia', from: 'enterprise_country'
|
||||
select 'VIC', from: 'enterprise_state'
|
||||
click_button 'Continue'
|
||||
click_and_ensure(:button, "Continue", lambda { page.has_content? 'Who is responsible for managing My Awesome Enterprise?' })
|
||||
|
||||
|
||||
# Filling in Contact Details
|
||||
expect(page).to have_content 'Who is responsible for managing My Awesome Enterprise?'
|
||||
fill_in 'enterprise_contact', with: 'Saskia Munroe'
|
||||
page.should have_field 'enterprise_email_address', with: user.email
|
||||
fill_in 'enterprise_phone', with: '12 3456 7890'
|
||||
click_button 'Continue'
|
||||
click_and_ensure(:button, "Continue", lambda { page.has_content? 'Last step to add My Awesome Enterprise!' })
|
||||
|
||||
# Choosing a type
|
||||
expect(page).to have_content 'Last step to add My Awesome Enterprise!'
|
||||
click_link_and_ensure('producer-panel', lambda { page.has_content? '#producer-panel.selected' } )
|
||||
click_button 'Create Profile'
|
||||
click_and_ensure(:link, 'producer-panel', lambda { page.has_content? '#producer-panel.selected' } )
|
||||
click_and_ensure(:button, "Create Profile", lambda { page.has_content? 'Nice one!' })
|
||||
|
||||
# Enterprise should be created
|
||||
# save_screenshot '/Users/rob/Desktop/ss.png' unless page.has_content? "Nice one!"
|
||||
expect(page).to have_content 'Nice one!'
|
||||
e = Enterprise.find_by_name('My Awesome Enterprise')
|
||||
expect(e.address.address1).to eq "123 Abc Street"
|
||||
expect(e.sells).to eq "unspecified"
|
||||
@@ -62,10 +60,9 @@ feature "Registration", js: true do
|
||||
fill_in 'enterprise_abn', with: '12345'
|
||||
fill_in 'enterprise_acn', with: '54321'
|
||||
choose 'Yes' # enterprise_charges_sales_tax
|
||||
click_button 'Continue'
|
||||
click_and_ensure(:button, "Continue", lambda { page.has_content? 'Step 1. Select Logo Image' })
|
||||
|
||||
# Enterprise should be updated
|
||||
expect(page).to have_content "Let's upload some pretty pictures so your profile looks great!"
|
||||
e.reload
|
||||
expect(e.description).to eq "Short description"
|
||||
expect(e.long_description).to eq "Long description"
|
||||
@@ -75,21 +72,20 @@ feature "Registration", js: true do
|
||||
|
||||
# Images
|
||||
# Move from logo page
|
||||
click_button 'Continue'
|
||||
click_and_ensure(:button, "Continue", lambda { page.has_content? 'Step 3. Select Promo Image' })
|
||||
|
||||
# Move from promo page
|
||||
click_button 'Continue'
|
||||
click_and_ensure(:button, "Continue", lambda { page.has_content? 'How can people find My Awesome Enterprise online?' })
|
||||
|
||||
# Filling in social
|
||||
expect(page).to have_content 'How can people find My Awesome Enterprise online?'
|
||||
fill_in 'enterprise_website', with: 'www.shop.com'
|
||||
fill_in 'enterprise_facebook', with: 'FaCeBoOk'
|
||||
fill_in 'enterprise_linkedin', with: 'LiNkEdIn'
|
||||
fill_in 'enterprise_twitter', with: '@TwItTeR'
|
||||
fill_in 'enterprise_instagram', with: '@InStAgRaM'
|
||||
click_button 'Continue'
|
||||
click_and_ensure(:button, "Continue", lambda { page.has_content? 'Finished!' })
|
||||
|
||||
# Done
|
||||
expect(page).to have_content "Finished!"
|
||||
expect(page).to have_content "We've sent a confirmation email to #{user.email} if it hasn't been activated before."
|
||||
e.reload
|
||||
expect(e.website).to eq "www.shop.com"
|
||||
@@ -121,21 +117,11 @@ feature "Registration", js: true do
|
||||
expect(page).to have_content content
|
||||
end
|
||||
|
||||
def click_button_and_ensure_content(button_text, content)
|
||||
def click_and_ensure(type, text, check)
|
||||
# Buttons appear to be unresponsive for a while, so keep clicking them until content appears
|
||||
using_wait_time 0.5 do
|
||||
10.times do
|
||||
click_button button_text
|
||||
break if page.has_content? content
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def click_link_and_ensure(link_text, check)
|
||||
# Buttons appear to be unresponsive for a while, so keep clicking them until content appears
|
||||
using_wait_time 0.5 do
|
||||
10.times do
|
||||
click_link link_text
|
||||
send("click_#{type}", text)
|
||||
break if check.call
|
||||
end
|
||||
end
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -21,7 +21,7 @@ describe "CustomersCtrl", ->
|
||||
expect(scope.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 ->
|
||||
@@ -33,6 +33,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"
|
||||
|
||||
@@ -8,7 +8,8 @@ describe "AdminSimpleCreateOrderCycleCtrl", ->
|
||||
outgoing_exchange = {}
|
||||
|
||||
beforeEach ->
|
||||
scope = {}
|
||||
scope =
|
||||
$watch: jasmine.createSpy('$watch')
|
||||
order_cycle =
|
||||
coordinator_id: 123
|
||||
incoming_exchanges: [incoming_exchange]
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -14,6 +14,7 @@ describe ProducerMailer do
|
||||
let(:p2) { create(:product, price: 23.45, supplier: s2) }
|
||||
let(:p3) { create(:product, price: 34.56, supplier: s1) }
|
||||
let(:p4) { create(:product, price: 45.67, supplier: s1) }
|
||||
let(:p5) { create(:product, price: 56.78, supplier: s1) }
|
||||
let(:order_cycle) { create(:simple_order_cycle) }
|
||||
let!(:incoming_exchange) { order_cycle.exchanges.create! sender: s1, receiver: d1, incoming: true, receival_instructions: 'Outside shed.' }
|
||||
|
||||
@@ -33,6 +34,14 @@ describe ProducerMailer do
|
||||
order.save
|
||||
order
|
||||
end
|
||||
let!(:order_canceled) do
|
||||
order = create(:order, distributor: d1, order_cycle: order_cycle, state: 'complete')
|
||||
order.line_items << create(:line_item, variant: p5.variants.first)
|
||||
order.finalize!
|
||||
order.cancel
|
||||
order.save
|
||||
order
|
||||
end
|
||||
let(:mail) { ActionMailer::Base.deliveries.last }
|
||||
|
||||
before do
|
||||
@@ -75,8 +84,11 @@ describe ProducerMailer do
|
||||
mail.body.encoded.should_not include p3.name
|
||||
end
|
||||
|
||||
it "does not include canceled orders" do
|
||||
mail.body.encoded.should_not include p5.name
|
||||
end
|
||||
|
||||
it "includes the total" do
|
||||
# puts mail.text_part.body.encoded
|
||||
mail.body.encoded.should include 'Total: $50.00'
|
||||
body_as_html(mail).find("tr.total-row")
|
||||
.should have_selector("td", text: "$50.00")
|
||||
|
||||
@@ -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) }
|
||||
|
||||
@@ -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)
|
||||
|
||||