mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-13 18:46:49 +00:00
Compare commits
341 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
387021929e | ||
|
|
30af5d4278 | ||
|
|
92082ce95c | ||
|
|
1558ddb1eb | ||
|
|
0038ebaa1f | ||
|
|
943c702e88 | ||
|
|
fb19feb357 | ||
|
|
e09431fa20 | ||
|
|
fb11c93943 | ||
|
|
727e8a81d6 | ||
|
|
0e96a23a52 | ||
|
|
80bf6e61ad | ||
|
|
c6d01055d6 | ||
|
|
82d31b908f | ||
|
|
066c8876ff | ||
|
|
de1971072e | ||
|
|
f44ac5b27b | ||
|
|
d717c38f6d | ||
|
|
61effc03c1 | ||
|
|
f2bc98e812 | ||
|
|
795b2700b4 | ||
|
|
6ab5efbe02 | ||
|
|
59d5ebe9d4 | ||
|
|
1fb1733644 | ||
|
|
775718c776 | ||
|
|
2b763271a7 | ||
|
|
d61073f08d | ||
|
|
2fb8f9f8a3 | ||
|
|
4f311543ae | ||
|
|
eed27ceb31 | ||
|
|
77432ffc41 | ||
|
|
5d2b36c667 | ||
|
|
61beb38e9c | ||
|
|
efca4dde10 | ||
|
|
d0b7550629 | ||
|
|
6f975593fe | ||
|
|
64ed80f845 | ||
|
|
f80a5fe558 | ||
|
|
1b52564d58 | ||
|
|
1cd6866879 | ||
|
|
1c1f82f4ee | ||
|
|
95073f6fe7 | ||
|
|
e575b0e490 | ||
|
|
5a08344812 | ||
|
|
e3d7c00c8e | ||
|
|
8aa55088ab | ||
|
|
a90cd0f8e0 | ||
|
|
6b35e993bd | ||
|
|
a586a52c23 | ||
|
|
b84f5a26a1 | ||
|
|
451ba1c01b | ||
|
|
c441c8c6cb | ||
|
|
0c36738472 | ||
|
|
ff3d9e27ec | ||
|
|
d5f9b40707 | ||
|
|
02d3d34826 | ||
|
|
5215623864 | ||
|
|
ed7a53968c | ||
|
|
c311bcdca7 | ||
|
|
ecbf3c8fa7 | ||
|
|
bfeb63c8d7 | ||
|
|
6dea3fa19d | ||
|
|
075e9edbf6 | ||
|
|
a8b6f2942a | ||
|
|
604360034b | ||
|
|
a0fd91dc57 | ||
|
|
d79129880e | ||
|
|
7412e92665 | ||
|
|
ee01113fe1 | ||
|
|
5a7231579c | ||
|
|
3c38c8e504 | ||
|
|
6c0238deac | ||
|
|
f88f42283a | ||
|
|
88872b4b49 | ||
|
|
153360d17b | ||
|
|
80834a0c27 | ||
|
|
d6c630dad9 | ||
|
|
7461009c3b | ||
|
|
252e9be016 | ||
|
|
f324471495 | ||
|
|
f438a44f26 | ||
|
|
1b91082c1c | ||
|
|
ffa960b02e | ||
|
|
41dafce0db | ||
|
|
e35b39c7cf | ||
|
|
552bbf221c | ||
|
|
f09fad464e | ||
|
|
fc7e33d706 | ||
|
|
ef3155a16a | ||
|
|
3846d16822 | ||
|
|
6051c81959 | ||
|
|
486c2f9b42 | ||
|
|
27bc28ffa4 | ||
|
|
cf0031d9a5 | ||
|
|
85d1d67dac | ||
|
|
a1425c5e07 | ||
|
|
5d77a48ef3 | ||
|
|
e93736b123 | ||
|
|
aea6277b77 | ||
|
|
3855ae1337 | ||
|
|
359328a96e | ||
|
|
dbd81e60a1 | ||
|
|
7c9b4dbc3e | ||
|
|
09160c8ea6 | ||
|
|
439d122e93 | ||
|
|
f1019e9221 | ||
|
|
2c0da5e350 | ||
|
|
d2a61dc096 | ||
|
|
0569ef0505 | ||
|
|
17d123db63 | ||
|
|
4d789b70ed | ||
|
|
7302963605 | ||
|
|
ad4e17b77a | ||
|
|
cd8084ae3f | ||
|
|
41b348f594 | ||
|
|
2b3689fd93 | ||
|
|
db47c01784 | ||
|
|
769a04d2e0 | ||
|
|
36dc0d5ccd | ||
|
|
b3878b126b | ||
|
|
c6f6c11a43 | ||
|
|
473322c7e6 | ||
|
|
8afffdae9a | ||
|
|
4b6222bbe2 | ||
|
|
96177b7cd7 | ||
|
|
cb2adea59f | ||
|
|
22230294ab | ||
|
|
2853885f26 | ||
|
|
a22da1ae51 | ||
|
|
159b33e2db | ||
|
|
0d3cdb9c69 | ||
|
|
5c3a59acab | ||
|
|
50ae331d94 | ||
|
|
fe27b1d446 | ||
|
|
bf935623dc | ||
|
|
678b591c18 | ||
|
|
503b687ed1 | ||
|
|
952353da8c | ||
|
|
e5b3736e86 | ||
|
|
c14de4e97f | ||
|
|
d478cc1f69 | ||
|
|
dccc9fb479 | ||
|
|
3f4f8afacd | ||
|
|
69c54e1d70 | ||
|
|
cdbf02ca20 | ||
|
|
4ce9ea05f0 | ||
|
|
835b56b222 | ||
|
|
7486daa2a3 | ||
|
|
bf9addfa42 | ||
|
|
ff2eed7760 | ||
|
|
e4f93863fd | ||
|
|
aef128f2c9 | ||
|
|
19448a182e | ||
|
|
a01a53caea | ||
|
|
7f43dbf9bb | ||
|
|
97e49c2bdb | ||
|
|
ccf1e2951c | ||
|
|
3ab7df88e6 | ||
|
|
75f1f673ad | ||
|
|
e74390a013 | ||
|
|
41bc67e2d8 | ||
|
|
e1b4c3b1e4 | ||
|
|
31b726613d | ||
|
|
dd761719ee | ||
|
|
1a887df412 | ||
|
|
2c92b5a751 | ||
|
|
3afd636577 | ||
|
|
cf79b90044 | ||
|
|
4a59c85b3e | ||
|
|
704955a185 | ||
|
|
ee8db23fd9 | ||
|
|
f0e909c92b | ||
|
|
f940984ca3 | ||
|
|
769edbe9d5 | ||
|
|
c5f00d87bd | ||
|
|
99cb09c6f7 | ||
|
|
5377af9cf9 | ||
|
|
a5482c269f | ||
|
|
5a43ed2046 | ||
|
|
28dae3c6c6 | ||
|
|
5d47dc2fdb | ||
|
|
5b65f67737 | ||
|
|
e931f4b31f | ||
|
|
63f3ede766 | ||
|
|
d43df86201 | ||
|
|
9c137ccf0f | ||
|
|
7e4751cb3a | ||
|
|
e6b6303f5e | ||
|
|
9c884b31a3 | ||
|
|
f017197221 | ||
|
|
cd44d43b3e | ||
|
|
903ed7e507 | ||
|
|
79a59e2e81 | ||
|
|
73884d4f01 | ||
|
|
2ed519ef50 | ||
|
|
1936767084 | ||
|
|
0b28771364 | ||
|
|
1aca4657d9 | ||
|
|
3431c687b8 | ||
|
|
65a6329132 | ||
|
|
8132f07d88 | ||
|
|
1e26466d11 | ||
|
|
6953f61939 | ||
|
|
01d4cf6ecf | ||
|
|
05131de1ad | ||
|
|
0a0bb67277 | ||
|
|
8d73b2f532 | ||
|
|
c56efabfbe | ||
|
|
0ad2978926 | ||
|
|
fc55a000b8 | ||
|
|
823adf3272 | ||
|
|
7f80c02c0e | ||
|
|
828456118b | ||
|
|
fa87c53777 | ||
|
|
6b956a8a38 | ||
|
|
0c46f963ce | ||
|
|
f1899a7558 | ||
|
|
70b5ac4785 | ||
|
|
f7642b2a1b | ||
|
|
a467d3c379 | ||
|
|
3d4a0f8407 | ||
|
|
3640a71ab8 | ||
|
|
ca37efdd26 | ||
|
|
dc8270ed72 | ||
|
|
0dcd8eb8cc | ||
|
|
ca1d88d8b1 | ||
|
|
5660e3737e | ||
|
|
c5b618b1f4 | ||
|
|
0737ac8da0 | ||
|
|
0a2f2e0fba | ||
|
|
38e1bd4139 | ||
|
|
c8502747be | ||
|
|
78fc3e376b | ||
|
|
50d0d04994 | ||
|
|
640c02570d | ||
|
|
3849b39d3e | ||
|
|
ffac0e4ceb | ||
|
|
a473d0ed11 | ||
|
|
34f5cfb6b5 | ||
|
|
1559b4e30a | ||
|
|
ed941e211d | ||
|
|
dd9c192d48 | ||
|
|
b364994cc8 | ||
|
|
3bc69242ce | ||
|
|
d2e8b23dd4 | ||
|
|
5b3c9842e4 | ||
|
|
a03c7a5f22 | ||
|
|
a60fd3d388 | ||
|
|
4c5e75c3f9 | ||
|
|
5b49e64bf2 | ||
|
|
9add073b17 | ||
|
|
734ad21e82 | ||
|
|
dcde2d88ad | ||
|
|
4545e0ff95 | ||
|
|
3890ba9a11 | ||
|
|
8f94390363 | ||
|
|
a873278881 | ||
|
|
2afd501af3 | ||
|
|
8f35ccf007 | ||
|
|
79d50a64ae | ||
|
|
3e7d331892 | ||
|
|
3b7ab086c9 | ||
|
|
69ba8540c1 | ||
|
|
5bd842fe1a | ||
|
|
f5c0ae0f41 | ||
|
|
1c03e27686 | ||
|
|
7a4f0e214c | ||
|
|
307302038a | ||
|
|
c00c93816c | ||
|
|
b3d314cfdb | ||
|
|
b6d63d40c6 | ||
|
|
220f42fcf2 | ||
|
|
37ff61d663 | ||
|
|
57dbc33a7b | ||
|
|
b16fa9cdc1 | ||
|
|
30bb948d35 | ||
|
|
e801d6199a | ||
|
|
62ae38372e | ||
|
|
b7c1a43125 | ||
|
|
98c1a95bd1 | ||
|
|
9c3ec950fc | ||
|
|
3e2117134f | ||
|
|
90dd1ea4a2 | ||
|
|
26ee5c49b2 | ||
|
|
3179887842 | ||
|
|
4d025ee7a9 | ||
|
|
521834bd76 | ||
|
|
662c7fe368 | ||
|
|
54da7ae241 | ||
|
|
2a991ad130 | ||
|
|
2f463474fb | ||
|
|
f7ade48e86 | ||
|
|
df14c10608 | ||
|
|
1531c476e3 | ||
|
|
2edf5aeccd | ||
|
|
993183f2f5 | ||
|
|
baabb5c07f | ||
|
|
66f847f673 | ||
|
|
295da25dd2 | ||
|
|
992fb2347d | ||
|
|
a253b88525 | ||
|
|
d344c3dec8 | ||
|
|
6045283549 | ||
|
|
162a565140 | ||
|
|
ad2df56bf1 | ||
|
|
ed7b763ecf | ||
|
|
05c350b5ff | ||
|
|
57be445bd4 | ||
|
|
f70bfee481 | ||
|
|
76d6345ab5 | ||
|
|
699a28e14c | ||
|
|
a75a76840d | ||
|
|
ff2e6d9ca4 | ||
|
|
893b743973 | ||
|
|
03fd148f41 | ||
|
|
72d553ef0c | ||
|
|
63353ebace | ||
|
|
b9f19d5777 | ||
|
|
9ee25c4e42 | ||
|
|
2d7fb3fd67 | ||
|
|
7596270154 | ||
|
|
5d9e861ee4 | ||
|
|
447a5481a3 | ||
|
|
8248e382f3 | ||
|
|
4b182f9248 | ||
|
|
2b47c9145a | ||
|
|
fcb3bc894b | ||
|
|
a223a2d662 | ||
|
|
5e2fe56c22 | ||
|
|
89afbc80a6 | ||
|
|
971723964e | ||
|
|
28486f9e76 | ||
|
|
869551a17c | ||
|
|
13a910c372 | ||
|
|
0a7b01ff07 | ||
|
|
dfb513cce7 | ||
|
|
3f01a459ac | ||
|
|
83981fbb15 | ||
|
|
ff935af18b | ||
|
|
ffd850c761 | ||
|
|
bf44a1c862 |
4
.rspec_parallel
Normal file
4
.rspec_parallel
Normal file
@@ -0,0 +1,4 @@
|
||||
--format progress
|
||||
--format ParallelTests::RSpec::SummaryLogger --out tmp/spec_summary.log
|
||||
--format ParallelTests::RSpec::RuntimeLogger --out tmp/parallel_runtime_rspec.log
|
||||
--tag ~performance
|
||||
4
Gemfile
4
Gemfile
@@ -49,6 +49,7 @@ gem 'custom_error_message', :github => 'jeremydurham/custom-err-msg'
|
||||
gem 'angularjs-file-upload-rails', '~> 1.1.0'
|
||||
gem 'roadie-rails', '~> 1.0.3'
|
||||
gem 'figaro'
|
||||
gem 'acts-as-taggable-on', '~> 3.4'
|
||||
|
||||
gem 'foreigner'
|
||||
gem 'immigrant'
|
||||
@@ -69,7 +70,7 @@ group :assets do
|
||||
gem 'turbo-sprockets-rails3'
|
||||
gem 'foundation-icons-sass-rails'
|
||||
gem 'momentjs-rails'
|
||||
gem 'angular-rails-templates'
|
||||
gem 'angular-rails-templates', '~> 0.2.0'
|
||||
end
|
||||
gem "foundation-rails"
|
||||
gem 'foundation_rails_helper', github: 'willrjmarshall/foundation_rails_helper', branch: "rails3"
|
||||
@@ -112,4 +113,5 @@ group :development do
|
||||
gem 'guard-rails'
|
||||
gem 'guard-zeus'
|
||||
gem 'guard-rspec'
|
||||
gem 'parallel_tests'
|
||||
end
|
||||
|
||||
30
Gemfile.lock
30
Gemfile.lock
@@ -142,12 +142,14 @@ GEM
|
||||
activesupport (3.2.21)
|
||||
i18n (~> 0.6, >= 0.6.4)
|
||||
multi_json (~> 1.0)
|
||||
acts-as-taggable-on (3.5.0)
|
||||
activerecord (>= 3.2, < 5)
|
||||
acts_as_list (0.1.4)
|
||||
addressable (2.3.3)
|
||||
andand (1.3.3)
|
||||
angular-rails-templates (0.1.1)
|
||||
angular-rails-templates (0.2.0)
|
||||
railties (>= 3.1)
|
||||
sprockets
|
||||
sprockets (~> 2)
|
||||
tilt
|
||||
angularjs-file-upload-rails (1.1.0)
|
||||
angularjs-rails (1.2.13)
|
||||
@@ -249,8 +251,7 @@ GEM
|
||||
erubis (2.7.0)
|
||||
eventmachine (1.0.3)
|
||||
excon (0.25.3)
|
||||
execjs (1.4.0)
|
||||
multi_json (~> 1.0)
|
||||
execjs (2.5.2)
|
||||
factory_girl (3.3.0)
|
||||
activesupport (>= 3.0.0)
|
||||
factory_girl_rails (3.3.0)
|
||||
@@ -319,14 +320,14 @@ GEM
|
||||
jquery-rails (2.2.2)
|
||||
railties (>= 3.0, < 5.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
json (1.8.2)
|
||||
json (1.8.3)
|
||||
json_spec (1.1.1)
|
||||
multi_json (~> 1.0)
|
||||
rspec (~> 2.0)
|
||||
kaminari (0.14.1)
|
||||
actionpack (>= 3.0.0)
|
||||
activesupport (>= 3.0.0)
|
||||
kgio (2.7.4)
|
||||
kgio (2.9.3)
|
||||
launchy (2.1.2)
|
||||
addressable (~> 2.3)
|
||||
letter_opener (1.0.0)
|
||||
@@ -352,7 +353,7 @@ GEM
|
||||
net-scp (1.1.2)
|
||||
net-ssh (>= 2.6.5)
|
||||
net-ssh (2.6.8)
|
||||
newrelic_rpm (3.6.7.152)
|
||||
newrelic_rpm (3.12.0.288)
|
||||
nokogiri (1.6.6.2)
|
||||
mini_portile (~> 0.6.0)
|
||||
oj (2.1.2)
|
||||
@@ -362,6 +363,9 @@ GEM
|
||||
activesupport (>= 3.0.0)
|
||||
cocaine (~> 0.5.3)
|
||||
mime-types
|
||||
parallel (1.4.1)
|
||||
parallel_tests (1.3.7)
|
||||
parallel
|
||||
paypal-sdk-core (0.2.10)
|
||||
multi_json (~> 1.0)
|
||||
xml-simple
|
||||
@@ -413,7 +417,7 @@ GEM
|
||||
rake (>= 0.8.7)
|
||||
rdoc (~> 3.4)
|
||||
thor (>= 0.14.6, < 2.0)
|
||||
raindrops (0.9.0)
|
||||
raindrops (0.13.0)
|
||||
rake (10.4.2)
|
||||
ransack (0.7.2)
|
||||
actionpack (~> 3.0)
|
||||
@@ -497,10 +501,10 @@ GEM
|
||||
turn (0.8.3)
|
||||
ansi
|
||||
tzinfo (0.3.44)
|
||||
uglifier (1.2.4)
|
||||
uglifier (2.7.1)
|
||||
execjs (>= 0.3.0)
|
||||
multi_json (>= 1.0.2)
|
||||
unicorn (4.3.1)
|
||||
json (>= 1.8.0)
|
||||
unicorn (4.9.0)
|
||||
kgio (~> 2.6)
|
||||
rack
|
||||
raindrops (~> 0.7)
|
||||
@@ -532,8 +536,9 @@ PLATFORMS
|
||||
|
||||
DEPENDENCIES
|
||||
active_model_serializers
|
||||
acts-as-taggable-on (~> 3.4)
|
||||
andand
|
||||
angular-rails-templates
|
||||
angular-rails-templates (~> 0.2.0)
|
||||
angularjs-file-upload-rails (~> 1.1.0)
|
||||
angularjs-rails (= 1.2.13)
|
||||
awesome_print
|
||||
@@ -575,6 +580,7 @@ DEPENDENCIES
|
||||
newrelic_rpm
|
||||
oj
|
||||
paperclip
|
||||
parallel_tests
|
||||
pg
|
||||
poltergeist
|
||||
pry-debugger
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
angular.module("ofn.admin", ["ngResource", "ngAnimate", "ofn.dropdown", "admin.products", "admin.taxons", "infinite-scroll"]).config ($httpProvider) ->
|
||||
angular.module("ofn.admin", ["ngResource", "ngAnimate", "admin.indexUtils", "admin.dropdown", "admin.products", "admin.taxons", "infinite-scroll"]).config ($httpProvider) ->
|
||||
$httpProvider.defaults.headers.common["X-CSRF-Token"] = $("meta[name=csrf-token]").attr("content")
|
||||
$httpProvider.defaults.headers.common["Accept"] = "application/json, text/javascript, */*"
|
||||
|
||||
@@ -12,14 +12,21 @@
|
||||
//= require angular
|
||||
//= require angular-resource
|
||||
//= require angular-animate
|
||||
//= require angular-sanitize
|
||||
//= require admin/spree_core
|
||||
//= require admin/spree_auth
|
||||
//= require admin/spree_promo
|
||||
//= require admin/spree_paypal_express
|
||||
//= require ../shared/ng-infinite-scroll.min.js
|
||||
//= require ../shared/ng-tags-input.min.js
|
||||
//= require angular-rails-templates
|
||||
//= require_tree ../templates/admin
|
||||
//= require ./admin
|
||||
//= require ./customers/customers
|
||||
//= require ./dropdown/dropdown
|
||||
//= require ./enterprises/enterprises
|
||||
//= require ./enterprise_groups/enterprise_groups
|
||||
//= require ./index_utils/index_utils
|
||||
//= require ./payment_methods/payment_methods
|
||||
//= require ./products/products
|
||||
//= require ./shipping_methods/shipping_methods
|
||||
@@ -29,5 +36,6 @@
|
||||
//= require ./users/users
|
||||
//= require textAngular.min.js
|
||||
//= require textAngular-sanitize.min.js
|
||||
//= require ../shared/bindonce.min.js
|
||||
|
||||
//= require_tree .
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
angular.module("ofn.admin").controller "AdminOrderMgmtCtrl", [
|
||||
"$scope", "$http", "$filter", "dataFetcher", "blankOption", "pendingChanges", "VariantUnitManager", "OptionValueNamer", "SpreeApiKey"
|
||||
($scope, $http, $filter, dataFetcher, blankOption, pendingChanges, VariantUnitManager, OptionValueNamer, SpreeApiKey) ->
|
||||
"$scope", "$http", "$filter", "dataFetcher", "blankOption", "pendingChanges", "VariantUnitManager", "OptionValueNamer", "SpreeApiKey", "Columns"
|
||||
($scope, $http, $filter, dataFetcher, blankOption, pendingChanges, VariantUnitManager, OptionValueNamer, SpreeApiKey, Columns) ->
|
||||
$scope.loading = true
|
||||
|
||||
$scope.initialiseVariables = ->
|
||||
@@ -18,9 +18,7 @@ angular.module("ofn.admin").controller "AdminOrderMgmtCtrl", [
|
||||
$scope.selectedUnitsProduct = {};
|
||||
$scope.selectedUnitsVariant = {};
|
||||
$scope.sharedResource = false
|
||||
$scope.predicate = ""
|
||||
$scope.reverse = false
|
||||
$scope.columns =
|
||||
$scope.columns = Columns.setColumns
|
||||
order_no: { name: "Order No.", visible: false }
|
||||
full_name: { name: "Name", visible: true }
|
||||
email: { name: "Email", visible: false }
|
||||
@@ -32,7 +30,8 @@ angular.module("ofn.admin").controller "AdminOrderMgmtCtrl", [
|
||||
variant: { name: "Variant", visible: true }
|
||||
quantity: { name: "Quantity", visible: true }
|
||||
max: { name: "Max", visible: true }
|
||||
|
||||
unit_value: { name: "Weight/Volume", visible: false }
|
||||
price: { name: "Price", visible: false }
|
||||
$scope.initialise = ->
|
||||
$scope.initialiseVariables()
|
||||
authorise_api_reponse = ""
|
||||
@@ -62,7 +61,7 @@ angular.module("ofn.admin").controller "AdminOrderMgmtCtrl", [
|
||||
|
||||
$scope.fetchOrders = ->
|
||||
$scope.loading = true
|
||||
dataFetcher("/api/orders/managed?template=bulk_index;page=1;per_page=500;q[state_not_eq]=canceled;q[completed_at_not_null]=true;q[completed_at_gt]=#{$scope.startDate};q[completed_at_lt]=#{$scope.endDate}").then (data) ->
|
||||
dataFetcher("/admin/orders/managed?template=bulk_index;page=1;per_page=500;q[state_not_eq]=canceled;q[completed_at_not_null]=true;q[completed_at_gt]=#{$scope.startDate};q[completed_at_lt]=#{$scope.endDate}").then (data) ->
|
||||
$scope.resetOrders data
|
||||
$scope.loading = false
|
||||
|
||||
@@ -165,6 +164,20 @@ angular.module("ofn.admin").controller "AdminOrderMgmtCtrl", [
|
||||
$scope.orderCycleFilter = $scope.orderCycles[0].id
|
||||
$scope.quickSearch = ""
|
||||
|
||||
$scope.weightAdjustedPrice = (lineItem, oldValue) ->
|
||||
if oldValue <= 0
|
||||
oldValue = lineItem.units_variant.unit_value
|
||||
if lineItem.unit_value <= 0
|
||||
lineItem.unit_value = lineItem.units_variant.unit_value
|
||||
lineItem.price = lineItem.price * lineItem.unit_value / oldValue
|
||||
#$scope.bulk_order_form.line_item.price.$setViewValue($scope.bulk_order_form.line_item.price.$viewValue)
|
||||
|
||||
$scope.unitValueLessThanZero = (lineItem) ->
|
||||
if lineItem.units_variant.unit_value <= 0
|
||||
true
|
||||
else
|
||||
false
|
||||
|
||||
$scope.$watch "orderCycleFilter", (newVal, oldVal) ->
|
||||
unless $scope.orderCycleFilter == "0" || angular.equals(newVal, oldVal)
|
||||
$scope.startDate = $scope.orderCyclesByID[$scope.orderCycleFilter].first_order
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $http, BulkProducts, DisplayProperties, dataFetcher, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, SpreeApiAuth) ->
|
||||
angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $http, BulkProducts, DisplayProperties, dataFetcher, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, SpreeApiAuth, Columns, tax_categories) ->
|
||||
$scope.loading = true
|
||||
|
||||
$scope.StatusMessage = StatusMessage
|
||||
|
||||
$scope.columns =
|
||||
$scope.columns = Columns.setColumns
|
||||
producer: {name: "Producer", visible: true}
|
||||
sku: {name: "SKU", visible: false}
|
||||
name: {name: "Name", visible: true}
|
||||
unit: {name: "Unit", visible: true}
|
||||
price: {name: "Price", visible: true}
|
||||
on_hand: {name: "On Hand", visible: true}
|
||||
on_demand: {name: "On Demand", visible: false}
|
||||
category: {name: "Category", visible: false}
|
||||
tax_category: {name: "Tax Category", visible: false}
|
||||
inherits_properties: {name: "Inherits Properties?", visible: false}
|
||||
available_on: {name: "Available On", visible: false}
|
||||
|
||||
@@ -32,6 +34,7 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
|
||||
$scope.producers = producers
|
||||
$scope.taxons = Taxons.taxons
|
||||
$scope.tax_categories = tax_categories
|
||||
$scope.filterProducers = [{id: "0", name: ""}].concat $scope.producers
|
||||
$scope.filterTaxons = [{id: "0", name: ""}].concat $scope.taxons
|
||||
$scope.producerFilter = "0"
|
||||
@@ -106,6 +109,12 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
window.location = "/admin/products/" + product.permalink_live + ((if variant then "/variants/" + variant.id else "")) + "/edit"
|
||||
|
||||
|
||||
$scope.toggleShowAllVariants = ->
|
||||
showVariants = !DisplayProperties.showVariants 0
|
||||
$scope.filteredProducts.forEach (product) ->
|
||||
DisplayProperties.setShowVariants product.id, showVariants
|
||||
DisplayProperties.setShowVariants 0, showVariants
|
||||
|
||||
$scope.addVariant = (product) ->
|
||||
product.variants.push
|
||||
id: $scope.nextVariantId()
|
||||
@@ -137,15 +146,18 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
|
||||
|
||||
$scope.deleteVariant = (product, variant) ->
|
||||
if !$scope.variantSaved(variant)
|
||||
$scope.removeVariant(product, variant)
|
||||
if product.variants.length > 1
|
||||
if !$scope.variantSaved(variant)
|
||||
$scope.removeVariant(product, variant)
|
||||
else
|
||||
if confirm("Are you sure?")
|
||||
$http(
|
||||
method: "DELETE"
|
||||
url: "/api/products/" + product.permalink_live + "/variants/" + variant.id + "/soft_delete"
|
||||
).success (data) ->
|
||||
$scope.removeVariant(product, variant)
|
||||
else
|
||||
if confirm("Are you sure?")
|
||||
$http(
|
||||
method: "DELETE"
|
||||
url: "/api/products/" + product.permalink_live + "/variants/" + variant.id + "/soft_delete"
|
||||
).success (data) ->
|
||||
$scope.removeVariant(product, variant)
|
||||
alert("The last variant cannot be deleted!")
|
||||
|
||||
$scope.removeVariant = (product, variant) ->
|
||||
product.variants.splice product.variants.indexOf(variant), 1
|
||||
@@ -309,9 +321,15 @@ filterSubmitProducts = (productsToFilter) ->
|
||||
if product.hasOwnProperty("on_hand") and filteredVariants.length == 0 #only update if no variants present
|
||||
filteredProduct.on_hand = product.on_hand
|
||||
hasUpdatableProperty = true
|
||||
if product.hasOwnProperty("on_demand") and filteredVariants.length == 0 #only update if no variants present
|
||||
filteredProduct.on_demand = product.on_demand
|
||||
hasUpdatableProperty = true
|
||||
if product.hasOwnProperty("category_id")
|
||||
filteredProduct.primary_taxon_id = product.category_id
|
||||
hasUpdatableProperty = true
|
||||
if product.hasOwnProperty("tax_category_id")
|
||||
filteredProduct.tax_category_id = product.tax_category_id
|
||||
hasUpdatableProperty = true
|
||||
if product.hasOwnProperty("inherits_properties")
|
||||
filteredProduct.inherits_properties = product.inherits_properties
|
||||
hasUpdatableProperty = true
|
||||
@@ -337,6 +355,9 @@ filterSubmitVariant = (variant) ->
|
||||
if variant.hasOwnProperty("on_hand")
|
||||
filteredVariant.on_hand = variant.on_hand
|
||||
hasUpdatableProperty = true
|
||||
if variant.hasOwnProperty("on_demand")
|
||||
filteredVariant.on_demand = variant.on_demand
|
||||
hasUpdatableProperty = true
|
||||
if variant.hasOwnProperty("price")
|
||||
filteredVariant.price = variant.price
|
||||
hasUpdatableProperty = true
|
||||
|
||||
@@ -9,3 +9,26 @@ angular.module("ofn.admin").controller "AdminEnterpriseRelationshipsCtrl", ($sco
|
||||
$scope.delete = (enterprise_relationship) ->
|
||||
if confirm("Are you sure?")
|
||||
$scope.EnterpriseRelationships.delete enterprise_relationship
|
||||
|
||||
$scope.toggleKeyword = (string, key) ->
|
||||
string = '' unless string
|
||||
words = string.split ' '
|
||||
words = words.filter (s) ->
|
||||
s
|
||||
index = words.indexOf key
|
||||
if index > -1
|
||||
words.splice index, 1
|
||||
else
|
||||
words.push key
|
||||
words.join ' '
|
||||
|
||||
$scope.allPermissionsChecked = ->
|
||||
for i in EnterpriseRelationships.all_permissions
|
||||
if !$scope.permissions[i]
|
||||
return false
|
||||
return true
|
||||
|
||||
$scope.checkAllPermissions = ->
|
||||
newValue = !$scope.allPermissionsChecked()
|
||||
EnterpriseRelationships.all_permissions.forEach (p) ->
|
||||
$scope.permissions[p] = newValue
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
angular.module("admin.customers").controller "customersCtrl", ($scope, Customers, Columns, pendingChanges, shops) ->
|
||||
$scope.shop = null
|
||||
$scope.shops = shops
|
||||
$scope.submitAll = pendingChanges.submitAll
|
||||
|
||||
$scope.columns = Columns.setColumns
|
||||
email: { name: "Email", visible: true }
|
||||
code: { name: "Code", visible: true }
|
||||
tags: { name: "Tags", visible: true }
|
||||
|
||||
$scope.$watch "shop", ->
|
||||
if $scope.shop?
|
||||
Customers.loaded = false
|
||||
$scope.customers = Customers.index(enterprise_id: $scope.shop.id)
|
||||
|
||||
$scope.loaded = ->
|
||||
Customers.loaded
|
||||
@@ -0,0 +1 @@
|
||||
angular.module("admin.customers", ['ngResource', 'ngTagsInput', 'admin.indexUtils', 'admin.dropdown'])
|
||||
@@ -0,0 +1,8 @@
|
||||
angular.module("admin.customers").directive "tagsWithTranslation", ->
|
||||
restrict: "E"
|
||||
template: "<tags-input ng-model='object.tags'>"
|
||||
scope:
|
||||
object: "="
|
||||
link: (scope, element, attrs) ->
|
||||
scope.$watchCollection "object.tags", ->
|
||||
scope.object.tag_list = (tag.text for tag in scope.object.tags).join(",")
|
||||
@@ -0,0 +1,8 @@
|
||||
angular.module("admin.customers").factory 'CustomerResource', ($resource) ->
|
||||
$resource('/admin/customers.json', {}, {
|
||||
'index':
|
||||
method: 'GET'
|
||||
isArray: true
|
||||
params:
|
||||
enterprise_id: '@enterprise_id'
|
||||
})
|
||||
@@ -0,0 +1,16 @@
|
||||
angular.module("admin.customers").factory 'Customers', (CustomerResource) ->
|
||||
new class Customers
|
||||
customers: []
|
||||
customers_by_id: {}
|
||||
loaded: false
|
||||
|
||||
index: (params={}, callback=null) ->
|
||||
CustomerResource.index params, (data) =>
|
||||
for customer in data
|
||||
@customers.push customer
|
||||
@customers_by_id[customer.id] = customer
|
||||
|
||||
@loaded = true
|
||||
(callback || angular.noop)(@customers)
|
||||
|
||||
@customers
|
||||
@@ -1,23 +0,0 @@
|
||||
angular.module("ofn.admin").directive "ofnLineItemUpdAttr", [
|
||||
"switchClass", "pendingChanges"
|
||||
(switchClass, pendingChanges) ->
|
||||
require: "ngModel"
|
||||
link: (scope, element, attrs, ngModel) ->
|
||||
attrName = attrs.ofnLineItemUpdAttr
|
||||
element.dbValue = scope.$eval(attrs.ngModel)
|
||||
scope.$watch ->
|
||||
scope.$eval(attrs.ngModel)
|
||||
, (value) ->
|
||||
if ngModel.$dirty
|
||||
if value == element.dbValue
|
||||
pendingChanges.remove(scope.line_item.id, attrName)
|
||||
switchClass( element, "", ["update-pending", "update-error", "update-success"], false )
|
||||
else
|
||||
changeObj =
|
||||
lineItem: scope.line_item
|
||||
element: element
|
||||
attrName: attrName
|
||||
url: "/api/orders/#{scope.line_item.order.number}/line_items/#{scope.line_item.id}?line_item[#{attrName}]=#{value}"
|
||||
pendingChanges.add(scope.line_item.id, attrName, changeObj)
|
||||
switchClass( element, "update-pending", ["update-error", "update-success"], false )
|
||||
]
|
||||
@@ -1,11 +0,0 @@
|
||||
angular.module("ofn.admin").directive "ofnToggleColumn", ->
|
||||
link: (scope, element, attrs) ->
|
||||
element.addClass "selected" if scope.column.visible
|
||||
element.click "click", ->
|
||||
scope.$apply ->
|
||||
if scope.column.visible
|
||||
scope.column.visible = false
|
||||
element.removeClass "selected"
|
||||
else
|
||||
scope.column.visible = true
|
||||
element.addClass "selected"
|
||||
@@ -1,10 +1,8 @@
|
||||
angular.module("ofn.admin").directive "ofnToggleVariants", (DisplayProperties) ->
|
||||
link: (scope, element, attrs) ->
|
||||
if DisplayProperties.showVariants scope.product.id
|
||||
element.removeClass "icon-chevron-right"
|
||||
element.addClass "icon-chevron-down"
|
||||
else
|
||||
element.removeClass "icon-chevron-down"
|
||||
element.addClass "icon-chevron-right"
|
||||
|
||||
element.on "click", ->
|
||||
@@ -16,4 +14,4 @@ angular.module("ofn.admin").directive "ofnToggleVariants", (DisplayProperties) -
|
||||
else
|
||||
DisplayProperties.setShowVariants scope.product.id, true
|
||||
element.removeClass "icon-chevron-right"
|
||||
element.addClass "icon-chevron-down"
|
||||
element.addClass "icon-chevron-down"
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
angular.module("admin.dropdown").controller "DropDownCtrl", ($scope) ->
|
||||
$scope.expanded = false
|
||||
@@ -0,0 +1,5 @@
|
||||
angular.module("admin.dropdown").directive "ofnCloseOnClick", ($document) ->
|
||||
link: (scope, element, attrs) ->
|
||||
element.click (event) ->
|
||||
event.stopPropagation()
|
||||
scope.$emit "offClick"
|
||||
@@ -1,6 +1,4 @@
|
||||
dropDownModule = angular.module("ofn.dropdown", [])
|
||||
|
||||
dropDownModule.directive "ofnDropDown", ($document) ->
|
||||
angular.module("admin.dropdown").directive "ofnDropDown", ($document) ->
|
||||
link: (scope, element, attrs) ->
|
||||
outsideClickListener = (event) ->
|
||||
unless $(event.target).is("div.ofn_drop_down##{attrs.id} div.menu") ||
|
||||
@@ -20,12 +18,3 @@ dropDownModule.directive "ofnDropDown", ($document) ->
|
||||
scope.$apply ->
|
||||
scope.expanded = true
|
||||
element.addClass "expanded"
|
||||
|
||||
dropDownModule.directive "ofnCloseOnClick", ($document) ->
|
||||
link: (scope, element, attrs) ->
|
||||
element.click (event) ->
|
||||
event.stopPropagation()
|
||||
scope.$emit "offClick"
|
||||
|
||||
dropDownModule.controller "DropDownCtrl", ($scope) ->
|
||||
$scope.expanded = false
|
||||
1
app/assets/javascripts/admin/dropdown/dropdown.js.coffee
Normal file
1
app/assets/javascripts/admin/dropdown/dropdown.js.coffee
Normal file
@@ -0,0 +1 @@
|
||||
angular.module("admin.dropdown", [])
|
||||
@@ -1,6 +1,6 @@
|
||||
angular.module("admin.enterprises")
|
||||
.controller "enterpriseCtrl", ($scope, NavigationCheck, Enterprise, EnterprisePaymentMethods, EnterpriseShippingMethods, SideMenu) ->
|
||||
$scope.Enterprise = Enterprise.enterprise
|
||||
.controller "enterpriseCtrl", ($scope, NavigationCheck, enterprise, EnterprisePaymentMethods, EnterpriseShippingMethods, SideMenu) ->
|
||||
$scope.Enterprise = enterprise
|
||||
$scope.PaymentMethods = EnterprisePaymentMethods.paymentMethods
|
||||
$scope.ShippingMethods = EnterpriseShippingMethods.shippingMethods
|
||||
$scope.navClear = NavigationCheck.clear
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
angular.module("admin.enterprises").controller "EnterpriseIndexRowCtrl", ($scope) ->
|
||||
$scope.status = ->
|
||||
if $scope.enterprise.issues.length > 0
|
||||
"issue"
|
||||
else if $scope.enterprise.warnings.length > 0
|
||||
"warning"
|
||||
else
|
||||
"ok"
|
||||
|
||||
|
||||
$scope.producerText = ->
|
||||
switch $scope.enterprise.is_primary_producer
|
||||
when true
|
||||
"Producer"
|
||||
else
|
||||
"Non-Producer"
|
||||
|
||||
$scope.packageText = ->
|
||||
switch $scope.enterprise.is_primary_producer
|
||||
when true
|
||||
switch $scope.enterprise.sells
|
||||
when "none"
|
||||
"Profile"
|
||||
when "own"
|
||||
"Shop"
|
||||
when "any"
|
||||
"Hub"
|
||||
else
|
||||
"Choose"
|
||||
else
|
||||
switch $scope.enterprise.sells
|
||||
when "none"
|
||||
"Profile"
|
||||
when "any"
|
||||
"Hub"
|
||||
else
|
||||
"Choose"
|
||||
|
||||
$scope.updateRowText = ->
|
||||
$scope.producer = $scope.producerText()
|
||||
$scope.package = $scope.packageText()
|
||||
$scope.producerError = ($scope.producer == "Choose")
|
||||
$scope.packageError = ($scope.package == "Choose")
|
||||
|
||||
|
||||
$scope.updateRowText()
|
||||
|
||||
$scope.$on "enterprise:updated", ->
|
||||
$scope.updateRowText()
|
||||
@@ -0,0 +1,13 @@
|
||||
angular.module("admin.enterprises").controller 'enterprisesCtrl', ($scope, Enterprises, Columns) ->
|
||||
Enterprises.loaded = false
|
||||
$scope.allEnterprises = Enterprises.index()
|
||||
|
||||
$scope.loaded = ->
|
||||
Enterprises.loaded
|
||||
|
||||
$scope.columns = Columns.setColumns
|
||||
name: { name: "Name", visible: true }
|
||||
producer: { name: "Producer", visible: true }
|
||||
package: { name: "Package", visible: true }
|
||||
status: { name: "Status", visible: true }
|
||||
manage: { name: "Manage", visible: true }
|
||||
@@ -0,0 +1,2 @@
|
||||
angular.module("admin.enterprises").controller 'indexPackagePanelCtrl', ($scope, $controller) ->
|
||||
angular.extend this, $controller('indexPanelCtrl', {$scope: $scope})
|
||||
@@ -0,0 +1,23 @@
|
||||
angular.module("admin.enterprises").controller 'indexPanelCtrl', ($scope, Enterprises) ->
|
||||
$scope.enterprise = $scope.object
|
||||
$scope.saving = false
|
||||
|
||||
$scope.saved = ->
|
||||
Enterprises.saved($scope.enterprise)
|
||||
|
||||
$scope.save = ->
|
||||
unless $scope.saved()
|
||||
$scope.saving = true
|
||||
Enterprises.save($scope.enterprise).then (data) ->
|
||||
$scope.$emit("enterprise:updated")
|
||||
$scope.saving = false
|
||||
, (response) ->
|
||||
$scope.saving = false
|
||||
if response.status == 422 && response.data.errors?
|
||||
message = 'Please resolve the following errors:\n'
|
||||
for attr, msg of response.data.errors
|
||||
message += "#{attr} #{msg}\n"
|
||||
alert(message)
|
||||
|
||||
$scope.resetAttribute = (attribute) ->
|
||||
Enterprises.resetAttribute($scope.enterprise, attribute)
|
||||
@@ -0,0 +1,14 @@
|
||||
angular.module("admin.enterprises").controller 'indexProducerPanelCtrl', ($scope, $controller) ->
|
||||
angular.extend this, $controller('indexPanelCtrl', {$scope: $scope})
|
||||
|
||||
$scope.changeToProducer = ->
|
||||
$scope.resetAttribute('sells')
|
||||
$scope.resetAttribute('producer_profile_only')
|
||||
$scope.enterprise.is_primary_producer = true
|
||||
|
||||
$scope.changeToNonProducer = ->
|
||||
if $scope.enterprise.sells == 'own'
|
||||
$scope.enterprise.sells = 'any'
|
||||
if $scope.enterprise.producer_profile_only = true
|
||||
$scope.enterprise.producer_profile_only = false
|
||||
$scope.enterprise.is_primary_producer = false
|
||||
@@ -0,0 +1,3 @@
|
||||
angular.module("admin.enterprises").controller 'indexStatusPanelCtrl', ($scope, $filter) ->
|
||||
$scope.issues = $scope.object.issues
|
||||
$scope.warnings = $scope.object.warnings
|
||||
@@ -1,6 +1,6 @@
|
||||
angular.module("admin.enterprises")
|
||||
.controller "sideMenuCtrl", ($scope, $parse, Enterprise, SideMenu, enterprisePermissions) ->
|
||||
$scope.Enterprise = Enterprise.enterprise
|
||||
.controller "sideMenuCtrl", ($scope, $parse, enterprise, SideMenu, enterprisePermissions) ->
|
||||
$scope.Enterprise = enterprise
|
||||
$scope.menu = SideMenu
|
||||
$scope.select = SideMenu.select
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
angular.module("admin.enterprises", [
|
||||
angular.module("admin.enterprises", [
|
||||
@@ -1,11 +1,11 @@
|
||||
angular.module("admin.enterprises")
|
||||
.factory "EnterprisePaymentMethods", (Enterprise, PaymentMethods) ->
|
||||
.factory "EnterprisePaymentMethods", (enterprise, PaymentMethods) ->
|
||||
new class EnterprisePaymentMethods
|
||||
paymentMethods: PaymentMethods.paymentMethods
|
||||
|
||||
constructor: ->
|
||||
for payment_method in @paymentMethods
|
||||
payment_method.selected = payment_method.id in Enterprise.enterprise.payment_method_ids
|
||||
payment_method.selected = payment_method.id in enterprise.payment_method_ids
|
||||
|
||||
displayColor: ->
|
||||
if @paymentMethods.length > 0 && @selectedCount() > 0
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
angular.module("admin.enterprises").factory 'EnterpriseResource', ($resource) ->
|
||||
$resource('/admin/enterprises/:id.json', {}, {
|
||||
'index':
|
||||
method: 'GET'
|
||||
isArray: true
|
||||
'update':
|
||||
method: 'PUT'
|
||||
})
|
||||
@@ -1,11 +1,11 @@
|
||||
angular.module("admin.enterprises")
|
||||
.factory "EnterpriseShippingMethods", (Enterprise, ShippingMethods) ->
|
||||
.factory "EnterpriseShippingMethods", (enterprise, ShippingMethods) ->
|
||||
new class EnterpriseShippingMethods
|
||||
shippingMethods: ShippingMethods.shippingMethods
|
||||
|
||||
constructor: ->
|
||||
for shipping_method in @shippingMethods
|
||||
shipping_method.selected = shipping_method.id in Enterprise.enterprise.shipping_method_ids
|
||||
shipping_method.selected = shipping_method.id in enterprise.shipping_method_ids
|
||||
|
||||
displayColor: ->
|
||||
if @shippingMethods.length > 0 && @selectedCount() > 0
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
angular.module("admin.enterprises").factory 'Enterprises', ($q, EnterpriseResource) ->
|
||||
new class Enterprises
|
||||
enterprises: []
|
||||
enterprises_by_id: {}
|
||||
pristine_by_id: {}
|
||||
loaded: false
|
||||
|
||||
index: (params={}, callback=null) ->
|
||||
EnterpriseResource.index params, (data) =>
|
||||
for enterprise in data
|
||||
@enterprises.push enterprise
|
||||
@pristine_by_id[enterprise.id] = angular.copy(enterprise)
|
||||
|
||||
@loaded = true
|
||||
(callback || angular.noop)(@enterprises)
|
||||
|
||||
@enterprises
|
||||
|
||||
save: (enterprise) ->
|
||||
deferred = $q.defer()
|
||||
enterprise.$update({id: enterprise.permalink})
|
||||
.then( (data) =>
|
||||
@pristine_by_id[enterprise.id] = angular.copy(enterprise)
|
||||
deferred.resolve(data)
|
||||
).catch (response) ->
|
||||
deferred.reject(response)
|
||||
deferred.promise
|
||||
|
||||
saved: (enterprise) ->
|
||||
@diff(enterprise).length == 0
|
||||
|
||||
diff: (enterprise) ->
|
||||
changed = []
|
||||
for attr, value of enterprise when not angular.equals(value, @pristine_by_id[enterprise.id][attr])
|
||||
changed.push attr unless attr is "$$hashKey"
|
||||
changed
|
||||
|
||||
resetAttribute: (enterprise, attribute) ->
|
||||
enterprise[attribute] = @pristine_by_id[enterprise.id][attribute]
|
||||
@@ -0,0 +1,7 @@
|
||||
angular.module("ofn.admin").filter "keywords", ($filter) ->
|
||||
return (array, query) ->
|
||||
return array unless query
|
||||
keywords = query.split ' '
|
||||
keywords.forEach (key) ->
|
||||
array = $filter('filter')(array, key)
|
||||
array
|
||||
@@ -0,0 +1,4 @@
|
||||
angular.module("admin.indexUtils").controller "ColumnsCtrl", ($scope, Columns) ->
|
||||
$scope.columns = Columns.columns
|
||||
$scope.predicate = ""
|
||||
$scope.reverse = false
|
||||
@@ -0,0 +1,36 @@
|
||||
angular.module("admin.indexUtils").directive "objForUpdate", (switchClass, pendingChanges) ->
|
||||
scope:
|
||||
object: "&objForUpdate"
|
||||
type: "@objForUpdate"
|
||||
attr: "@attrForUpdate"
|
||||
link: (scope, element, attrs) ->
|
||||
scope.savedValue = scope.object()[scope.attr]
|
||||
|
||||
scope.$watch "object().#{scope.attr}", (value) ->
|
||||
if value == scope.savedValue
|
||||
pendingChanges.remove(scope.object().id, scope.attr)
|
||||
scope.clear()
|
||||
else
|
||||
change =
|
||||
object: scope.object()
|
||||
type: scope.type
|
||||
attr: scope.attr
|
||||
value: value
|
||||
scope: scope
|
||||
scope.pending()
|
||||
pendingChanges.add(scope.object().id, scope.attr, change)
|
||||
|
||||
scope.reset = (value) ->
|
||||
scope.savedValue = value
|
||||
|
||||
scope.success = ->
|
||||
switchClass( element, "update-success", ["update-pending", "update-error"], 3000 )
|
||||
|
||||
scope.pending = ->
|
||||
switchClass( element, "update-pending", ["update-error", "update-success"], false )
|
||||
|
||||
scope.error = ->
|
||||
switchClass( element, "update-error", ["update-pending", "update-success"], false )
|
||||
|
||||
scope.clear = ->
|
||||
switchClass( element, "", ["update-pending", "update-error", "update-success"], false )
|
||||
@@ -0,0 +1,37 @@
|
||||
angular.module("admin.indexUtils").directive "panelRow", (Panels, Columns) ->
|
||||
restrict: "C"
|
||||
templateUrl: "admin/panel.html"
|
||||
scope:
|
||||
object: "="
|
||||
panels: "="
|
||||
link: (scope, element, attrs) ->
|
||||
scope.template = ""
|
||||
selected = null
|
||||
scope.columnCount = Columns.visibleCount
|
||||
|
||||
scope.$on "columnCount:changed", (event, count) ->
|
||||
scope.columnCount = count
|
||||
|
||||
setTemplate = ->
|
||||
if selected?
|
||||
scope.template = 'admin/panels/' + scope.panels[selected] + '.html'
|
||||
else
|
||||
scope.template = ""
|
||||
|
||||
scope.getSelected = ->
|
||||
selected
|
||||
|
||||
scope.setSelected = (name) ->
|
||||
scope.$apply ->
|
||||
selected = name
|
||||
setTemplate()
|
||||
|
||||
scope.open = (name) ->
|
||||
element.show 0, ->
|
||||
scope.setSelected name
|
||||
|
||||
scope.close = ->
|
||||
element.hide 0, ->
|
||||
scope.setSelected null
|
||||
|
||||
Panels.register(scope.object.id, scope)
|
||||
@@ -0,0 +1,12 @@
|
||||
angular.module("admin.indexUtils").directive "panelToggle", ->
|
||||
restrict: "C"
|
||||
transclude: true
|
||||
template: '<div ng-transclude></div><i class=\'icon-chevron\'></i>'
|
||||
require: "^panelToggleRow"
|
||||
scope:
|
||||
name: "@"
|
||||
link: (scope, element, attrs, ctrl) ->
|
||||
scope.selected = ctrl.register(scope.name, element)
|
||||
|
||||
element.on "click", ->
|
||||
scope.selected = ctrl.select(scope.name)
|
||||
@@ -0,0 +1,29 @@
|
||||
angular.module("admin.indexUtils").directive "panelToggleRow", (Panels) ->
|
||||
restrict: "C"
|
||||
scope:
|
||||
object: "="
|
||||
selected: "@?"
|
||||
controller: ($scope) ->
|
||||
panelToggles = {}
|
||||
|
||||
this.register = (name, element) ->
|
||||
panelToggles[name] = element
|
||||
panelToggles[name].addClass("selected") if $scope.selected == name
|
||||
$scope.selected == name
|
||||
|
||||
this.select = (name) ->
|
||||
panelToggle.removeClass("selected") for panelName, panelToggle of panelToggles
|
||||
|
||||
switch $scope.selected = Panels.toggle($scope.object.id, name)
|
||||
when null
|
||||
panelToggles[name].parent(".panel-toggle-row").removeClass("expanded")
|
||||
else
|
||||
panelToggles[$scope.selected].addClass("selected")
|
||||
panelToggles[$scope.selected].parent(".panel-toggle-row").addClass("expanded")
|
||||
|
||||
$scope.selected == name
|
||||
|
||||
this
|
||||
#
|
||||
# link: (scope, element, attrs) ->
|
||||
# Panels.registerInitialSelection(scope.object.id, scope.selected)
|
||||
@@ -0,0 +1,8 @@
|
||||
angular.module("admin.indexUtils").directive "ofnToggleColumn", (Columns) ->
|
||||
link: (scope, element, attrs) ->
|
||||
element.addClass "selected" if scope.column.visible
|
||||
|
||||
element.click "click", ->
|
||||
scope.$apply ->
|
||||
Columns.toggleColumn(scope.column)
|
||||
element.toggleClass "selected"
|
||||
@@ -0,0 +1 @@
|
||||
angular.module("admin.indexUtils", ['ngResource', 'templates']).config ($httpProvider) ->
|
||||
@@ -0,0 +1,18 @@
|
||||
angular.module("admin.indexUtils").factory 'Columns', ($rootScope) ->
|
||||
new class Columns
|
||||
columns: {}
|
||||
visibleCount: 0
|
||||
|
||||
setColumns: (columns) =>
|
||||
@columns = {}
|
||||
@columns[name] = column for name, column of columns
|
||||
@calculateVisibleCount()
|
||||
@columns
|
||||
|
||||
toggleColumn: (column) =>
|
||||
column.visible = !column.visible
|
||||
@calculateVisibleCount()
|
||||
|
||||
calculateVisibleCount: =>
|
||||
@visibleCount = (column for name, column of @columns when column.visible).length
|
||||
$rootScope.$broadcast "columnCount:changed", @visibleCount
|
||||
@@ -0,0 +1,19 @@
|
||||
angular.module("admin.indexUtils").factory 'Panels', ->
|
||||
new class Panels
|
||||
panels: {}
|
||||
|
||||
register: (id, scope) ->
|
||||
if id? && scope?
|
||||
@panels[id] = scope
|
||||
|
||||
toggle: (id, name) ->
|
||||
scope = @panels[id]
|
||||
selected = scope.getSelected()
|
||||
switch selected
|
||||
when name
|
||||
scope.close()
|
||||
when null
|
||||
scope.open(name)
|
||||
else
|
||||
scope.setSelected(name)
|
||||
scope.getSelected()
|
||||
@@ -0,0 +1,33 @@
|
||||
angular.module("admin.indexUtils").factory "pendingChanges", (resources) ->
|
||||
new class pendingChanges
|
||||
pendingChanges: {}
|
||||
|
||||
add: (id, attr, change) =>
|
||||
@pendingChanges["#{id}"] = {} unless @pendingChanges.hasOwnProperty("#{id}")
|
||||
@pendingChanges["#{id}"]["#{attr}"] = change
|
||||
|
||||
removeAll: =>
|
||||
@pendingChanges = {}
|
||||
|
||||
remove: (id, attr) =>
|
||||
if @pendingChanges.hasOwnProperty("#{id}")
|
||||
delete @pendingChanges["#{id}"]["#{attr}"]
|
||||
delete @pendingChanges["#{id}"] if @changeCount( @pendingChanges["#{id}"] ) < 1
|
||||
|
||||
submitAll: =>
|
||||
all = []
|
||||
for id, objectChanges of @pendingChanges
|
||||
for attrName, change of objectChanges
|
||||
all.push @submit(change)
|
||||
all
|
||||
|
||||
submit: (change) ->
|
||||
resources.update(change).$promise.then (data) =>
|
||||
@remove change.object.id, change.attr
|
||||
change.scope.reset( data["#{change.attr}"] )
|
||||
change.scope.success()
|
||||
, (error) ->
|
||||
change.scope.error()
|
||||
|
||||
changeCount: (objectChanges) ->
|
||||
Object.keys(objectChanges).length
|
||||
@@ -0,0 +1,30 @@
|
||||
angular.module("admin.indexUtils").factory "resources", ($resource) ->
|
||||
LineItem = $resource '/api/orders/:order_number/line_items/:line_item_id.json',
|
||||
{ order_number: '@order_number', line_item_id: '@line_item_id'},
|
||||
'update': { method: 'PUT' }
|
||||
Customer = $resource '/admin/customers/:customer_id.json',
|
||||
{ customer_id: '@customer_id'},
|
||||
'update': { method: 'PUT' }
|
||||
|
||||
return {
|
||||
update: (change) ->
|
||||
params = {}
|
||||
data = {}
|
||||
resource = null
|
||||
|
||||
switch change.type
|
||||
when "line_item"
|
||||
resource = LineItem
|
||||
params.order_number = change.object.order.number
|
||||
params.line_item_id = change.object.id
|
||||
data.line_item = {}
|
||||
data.line_item[change.attr] = change.value
|
||||
when "customer"
|
||||
resource = Customer
|
||||
params.customer_id = change.object.id
|
||||
data.customer = {}
|
||||
data.customer[change.attr] = change.value
|
||||
else ""
|
||||
|
||||
resource.update(params, data)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
angular.module("admin.indexUtils").factory "switchClass", ($timeout) ->
|
||||
return (element,classToAdd,removeClasses,timeout) ->
|
||||
$timeout.cancel element.timeout if element.timeout
|
||||
element.removeClass className for className in removeClasses
|
||||
element.addClass classToAdd
|
||||
intRegex = /^\d+$/
|
||||
if timeout && intRegex.test(timeout)
|
||||
element.timeout = $timeout(->
|
||||
element.removeClass classToAdd
|
||||
, timeout, true)
|
||||
@@ -5,6 +5,13 @@ angular.module("admin.products")
|
||||
$scope.placeholder_text = ""
|
||||
|
||||
$scope.$watchCollection '[product.variant_unit_with_scale, product.master.unit_value_with_description]', ->
|
||||
$scope.processVariantUnitWithScale()
|
||||
$scope.processUnitValueWithDescription()
|
||||
$scope.placeholder_text = new OptionValueNamer($scope.product.master).name()
|
||||
|
||||
$scope.variant_unit_options = VariantUnitManager.variantUnitOptions()
|
||||
|
||||
$scope.processVariantUnitWithScale = ->
|
||||
if $scope.product.variant_unit_with_scale
|
||||
match = $scope.product.variant_unit_with_scale.match(/^([^_]+)_([\d\.]+)$/)
|
||||
if match
|
||||
@@ -16,18 +23,15 @@ angular.module("admin.products")
|
||||
else
|
||||
$scope.product.variant_unit = $scope.product.variant_unit_scale = null
|
||||
|
||||
$scope.processUnitValueWithDescription = ->
|
||||
if $scope.product.master.hasOwnProperty("unit_value_with_description")
|
||||
match = $scope.product.master.unit_value_with_description.match(/^([\d\.]+(?= |$)|)( |)(.*)$/)
|
||||
match = $scope.product.master.unit_value_with_description.match(/^([\d\.]+(?= *|$)|)( *)(.*)$/)
|
||||
if match
|
||||
$scope.product.master.unit_value = parseFloat(match[1])
|
||||
$scope.product.master.unit_value = null if isNaN($scope.product.master.unit_value)
|
||||
$scope.product.master.unit_value *= $scope.product.variant_unit_scale if $scope.product.master.unit_value && $scope.product.variant_unit_scale
|
||||
$scope.product.master.unit_description = match[3]
|
||||
|
||||
$scope.placeholder_text = new OptionValueNamer($scope.product.master).name()
|
||||
|
||||
$scope.variant_unit_options = VariantUnitManager.variantUnitOptions()
|
||||
|
||||
$scope.hasVariants = (product) ->
|
||||
Object.keys(product.variants).length > 0
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ angular.module("ofn.admin").factory "BulkProducts", (PagedFetcher, dataFetcher)
|
||||
# when a respond_overrride for the clone action is used.
|
||||
id = data.product.id
|
||||
dataFetcher("/api/products/" + id + "?template=bulk_show").then (newProduct) =>
|
||||
@addProducts [newProduct]
|
||||
@insertProductAfter(product, newProduct)
|
||||
|
||||
updateVariantLists: (serverProducts, productsWithUnsavedVariants) ->
|
||||
for product in productsWithUnsavedVariants
|
||||
@@ -39,6 +39,10 @@ angular.module("ofn.admin").factory "BulkProducts", (PagedFetcher, dataFetcher)
|
||||
@unpackProduct product
|
||||
@products.push product
|
||||
|
||||
insertProductAfter: (product, newProduct) ->
|
||||
index = @products.indexOf(product)
|
||||
@products.splice(index + 1, 0, newProduct)
|
||||
|
||||
unpackProduct: (product) ->
|
||||
#$scope.matchProducer product
|
||||
@loadVariantUnit product
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
angular.module("ofn.admin").factory "dataSubmitter", [
|
||||
"$http", "$q", "switchClass"
|
||||
($http, $q, switchClass) ->
|
||||
return (changeObj) ->
|
||||
deferred = $q.defer()
|
||||
$http.put(changeObj.url).success((data) ->
|
||||
switchClass changeObj.element, "update-success", ["update-pending", "update-error"], 3000
|
||||
deferred.resolve data
|
||||
).error ->
|
||||
switchClass changeObj.element, "update-error", ["update-pending", "update-success"], false
|
||||
deferred.reject()
|
||||
deferred.promise
|
||||
]
|
||||
@@ -3,12 +3,10 @@ angular.module("ofn.admin").factory "DisplayProperties", ->
|
||||
displayProperties: {}
|
||||
|
||||
showVariants: (product_id) ->
|
||||
@initProduct product_id
|
||||
@displayProperties[product_id].showVariants
|
||||
@productProperties(product_id).showVariants
|
||||
|
||||
setShowVariants: (product_id, showVariants) ->
|
||||
@initProduct product_id
|
||||
@displayProperties[product_id].showVariants = showVariants
|
||||
@productProperties(product_id).showVariants = showVariants
|
||||
|
||||
initProduct: (product_id) ->
|
||||
productProperties: (product_id) ->
|
||||
@displayProperties[product_id] ||= {showVariants: false}
|
||||
|
||||
@@ -26,7 +26,7 @@ angular.module("ofn.admin").factory 'EnterpriseRelationships', ($http, enterpris
|
||||
|
||||
permission_presentation: (permission) ->
|
||||
switch permission
|
||||
when "add_to_order_cycle" then "to add to order cycle"
|
||||
when "manage_products" then "to manage products"
|
||||
when "edit_profile" then "to edit profile"
|
||||
when "create_variant_overrides" then "to override variant details"
|
||||
when "add_to_order_cycle" then "add to order cycle"
|
||||
when "manage_products" then "manage products"
|
||||
when "edit_profile" then "edit profile"
|
||||
when "create_variant_overrides" then "override variant details"
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
angular.module("ofn.admin").factory "pendingChanges",[
|
||||
"dataSubmitter"
|
||||
(dataSubmitter) ->
|
||||
pendingChanges: {}
|
||||
|
||||
add: (id, attrName, changeObj) ->
|
||||
@pendingChanges["#{id}"] = {} unless @pendingChanges.hasOwnProperty("#{id}")
|
||||
@pendingChanges["#{id}"]["#{attrName}"] = changeObj
|
||||
|
||||
removeAll: ->
|
||||
@pendingChanges = {}
|
||||
|
||||
remove: (id, attrName) ->
|
||||
if @pendingChanges.hasOwnProperty("#{id}")
|
||||
delete @pendingChanges["#{id}"]["#{attrName}"]
|
||||
delete @pendingChanges["#{id}"] if @changeCount( @pendingChanges["#{id}"] ) < 1
|
||||
|
||||
submitAll: ->
|
||||
all = []
|
||||
for id,lineItem of @pendingChanges
|
||||
for attrName,changeObj of lineItem
|
||||
all.push @submit(id, attrName, changeObj)
|
||||
all
|
||||
|
||||
submit: (id, attrName, change) ->
|
||||
dataSubmitter(change).then (data) =>
|
||||
@remove id, attrName
|
||||
change.element.dbValue = data["#{attrName}"]
|
||||
|
||||
changeCount: (lineItem) ->
|
||||
Object.keys(lineItem).length
|
||||
]
|
||||
@@ -1,13 +0,0 @@
|
||||
angular.module("ofn.admin").factory "switchClass", [
|
||||
"$timeout"
|
||||
($timeout) ->
|
||||
return (element,classToAdd,removeClasses,timeout) ->
|
||||
$timeout.cancel element.timeout if element.timeout
|
||||
element.removeClass className for className in removeClasses
|
||||
element.addClass classToAdd
|
||||
intRegex = /^\d+$/
|
||||
if timeout && intRegex.test(timeout)
|
||||
element.timeout = $timeout(->
|
||||
element.removeClass classToAdd
|
||||
, timeout, true)
|
||||
]
|
||||
@@ -1,9 +1,10 @@
|
||||
Darkswarm.controller "GroupEnterprisesCtrl", ($scope, Search, FilterSelectorsService) ->
|
||||
Darkswarm.controller "GroupEnterprisesCtrl", ($scope, Search, FilterSelectorsService, EnterpriseModal) ->
|
||||
$scope.totalActive = FilterSelectorsService.totalActive
|
||||
$scope.clearAll = FilterSelectorsService.clearAll
|
||||
$scope.filterText = FilterSelectorsService.filterText
|
||||
$scope.FilterSelectorsService = FilterSelectorsService
|
||||
$scope.query = Search.search()
|
||||
$scope.openModal = EnterpriseModal.open
|
||||
$scope.activeTaxons = []
|
||||
$scope.show_profiles = false
|
||||
$scope.filtersActive = false
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
Darkswarm.controller "GroupsCtrl", ($scope, Groups, $anchorScroll, $rootScope) ->
|
||||
$scope.Groups = Groups
|
||||
$scope.order = 'position'
|
||||
|
||||
#$rootScope.$on "$locationChangeSuccess", (newRoute, oldRoute) ->
|
||||
#$anchorScroll()
|
||||
#
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Darkswarm.controller "HubNodeCtrl", ($scope, HashNavigation, Navigation, $location, $templateCache, CurrentHub) ->
|
||||
$scope.toggle = ->
|
||||
HashNavigation.toggle $scope.hub.hash
|
||||
$scope.toggle = (e) ->
|
||||
HashNavigation.toggle $scope.hub.hash if !angular.element(e.target).inheritedData('is-link')
|
||||
|
||||
$scope.open = ->
|
||||
HashNavigation.active $scope.hub.hash
|
||||
|
||||
@@ -22,17 +22,11 @@ Darkswarm.directive "filterSelector", (FilterSelectorsService)->
|
||||
.map (selector)->
|
||||
selector.object.id
|
||||
|
||||
# This can be called from a parent scope
|
||||
# when data has been loaded, in order to pass
|
||||
# selectors up
|
||||
scope.$on 'loadFilterSelectors', ->
|
||||
scope.allSelectors = scope.selectors() if attr.allSelectors?
|
||||
|
||||
scope.$watchCollection "selectors()", (newValue, oldValue) ->
|
||||
scope.allSelectors = scope.selectors() if attr.allSelectors?
|
||||
scope.$watchCollection "objects()", (newValue, oldValue) ->
|
||||
scope.allSelectors = scope.buildSelectors()
|
||||
|
||||
# Build a list of selectors
|
||||
scope.selectors = ->
|
||||
scope.buildSelectors = ->
|
||||
# Generate a selector for each object.
|
||||
# NOTE: THESE ARE MEMOIZED to stop new selectors from being created constantly, otherwise function always returns non-identical results
|
||||
# This means the $digest cycle can never close and times out
|
||||
|
||||
@@ -7,5 +7,5 @@ Darkswarm.factory "MapConfiguration", ->
|
||||
zoom: 12
|
||||
additional_options: {}
|
||||
#mapTypeId: 'satellite'
|
||||
styles: [{"featureType":"landscape","stylers":[{"saturation":-100},{"lightness":65},{"visibility":"on"}]},{"featureType":"poi","stylers":[{"saturation":-100},{"lightness":51},{"visibility":"simplified"}]},{"featureType":"road.highway","stylers":[{"saturation":-100},{"visibility":"simplified"}]},{"featureType":"road.arterial","stylers":[{"saturation":-100},{"lightness":30},{"visibility":"on"}]},{"featureType":"road.local","stylers":[{"saturation":-100},{"lightness":40},{"visibility":"on"}]},{"featureType":"transit","stylers":[{"saturation":-100},{"visibility":"simplified"}]},{"featureType":"administrative.province","stylers":[{"visibility":"off"}]},{"featureType":"water","elementType":"labels","stylers":[{"visibility":"on"},{"lightness":-25},{"saturation":-100}]},{"featureType":"water","elementType":"geometry","stylers":[{"hue":"#ffff00"},{"lightness":-25},{"saturation":-97}]}]
|
||||
styles: [{"featureType":"landscape","stylers":[{"saturation":-100},{"lightness":65},{"visibility":"on"}]},{"featureType":"poi","stylers":[{"saturation":-100},{"lightness":51},{"visibility":"simplified"}]},{"featureType":"road.highway","stylers":[{"saturation":-100},{"visibility":"simplified"}]},{"featureType":"road.arterial","stylers":[{"saturation":-100},{"lightness":30},{"visibility":"on"}]},{"featureType":"road.local","stylers":[{"saturation":-100},{"lightness":40},{"visibility":"on"}]},{"featureType":"transit","stylers":[{"saturation":-100},{"visibility":"simplified"}]},{"featureType":"administrative.province","stylers":[{"visibility":"off"}]},{"featureType":"water","elementType":"labels","stylers":[{"visibility":"on"},{"lightness":-25},{"saturation":-100}]},{"featureType":"water","elementType":"geometry","stylers":[{"hue":"#ffff00"},{"lightness":-25},{"saturation":-97}]},{"featureType":"road","elementType": "labels.icon","stylers":[{"visibility":"off"}]}]
|
||||
|
||||
|
||||
@@ -32,8 +32,9 @@ Darkswarm.factory 'Products', ($resource, Enterprises, Dereferencer, Taxons, Pro
|
||||
if product.variants
|
||||
product.variants = (Variants.register variant for variant in product.variants)
|
||||
variant.product = product for variant in product.variants
|
||||
product.master.product = product
|
||||
product.master = Variants.register product.master if product.master
|
||||
if product.master
|
||||
product.master.product = product
|
||||
product.master = Variants.register product.master
|
||||
|
||||
registerVariantsWithCart: ->
|
||||
for product in @products
|
||||
|
||||
1
app/assets/javascripts/shared/ng-tags-input.min.js
vendored
Executable file
1
app/assets/javascripts/shared/ng-tags-input.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
2
app/assets/javascripts/templates/admin/panel.html.haml
Normal file
2
app/assets/javascripts/templates/admin/panel.html.haml
Normal file
@@ -0,0 +1,2 @@
|
||||
%td{ colspan: "{{columnCount}}" }
|
||||
.panel{ ng: { include: "template" } }
|
||||
@@ -0,0 +1,133 @@
|
||||
.row.enterprise_package_panel{ ng: { controller: 'indexPackagePanelCtrl' } }
|
||||
.alpha.eight.columns
|
||||
%div{ ng: { if: "!enterprise.is_primary_producer", switch: "enterprise.sells" } }
|
||||
.info{ ng: { switch: { when: "none" } } }
|
||||
%h3 Hub Profile
|
||||
|
||||
%p
|
||||
%strong COST: ALWAYS FREE
|
||||
|
||||
%p People can find and contact you on the Open Food Network. Your enterprise will be visible on the map, and will be searchable in listings.
|
||||
|
||||
%p Having a profile, and making connections within your local food system through the Open Food Network will always be free.
|
||||
|
||||
.info{ ng: { switch: { when: "any" } } }
|
||||
%h3 Hub Shop
|
||||
|
||||
%p
|
||||
%strong COST: 2% OF SALES, CAPPED AT $50 PER MONTH
|
||||
|
||||
%p Your enterprise is the backbone of your local food system. You aggregate produce from other enterprises and can sell it through your shop on the Open Food Network.
|
||||
|
||||
%p Hubs can take many forms, whether they be a food co-op, a buying group, a veggie-box program, or a local grocery store.
|
||||
|
||||
%p If you also want to sell your own products, you will need to switch this enterprise to be a producer.
|
||||
|
||||
.info{ ng: { switch: { default: true } } }
|
||||
%h3
|
||||
Please Choose a Package
|
||||
%i.icon-arrow-right
|
||||
|
||||
%p
|
||||
%strong Your enterprise will not be fully activated until a package is selected from the options on the left.
|
||||
|
||||
%p
|
||||
Click on an option to see more detailed information about each package, and hit the red SAVE button when you are done!
|
||||
|
||||
|
||||
|
||||
%div{ ng: { if: "enterprise.is_primary_producer", switch: "enterprise.sells" } }
|
||||
.info{ ng: { switch: { when: "none" } } }
|
||||
%h3 Profile Only
|
||||
|
||||
%p
|
||||
%strong COST: ALWAYS FREE
|
||||
|
||||
%p A profile makes you visible and contactable to others and is a way to share your story.
|
||||
|
||||
%p If you prefer to focus on producing food, and want to leave the work of selling it to someone else, you won't require a shop on the Open Food Network.
|
||||
|
||||
%p Add your products to Open Food Network, allowing hubs to stock your products in their stores.
|
||||
|
||||
.info{ ng: { switch: { when: "own" } } }
|
||||
%h3 Producer Shop
|
||||
|
||||
%p
|
||||
%strong COST: 2% OF SALES, CAPPED AT $50 PER MONTH
|
||||
|
||||
%p Sell your products directly to customers through your very own Open Food Network shopfront.
|
||||
|
||||
%p A Producer Shop is for your produce only, if you want to sell produce grown/produced off site, please select 'Producer Hub'.
|
||||
|
||||
.info{ ng: { switch: { when: "any" } } }
|
||||
%h3 Producer Hub
|
||||
|
||||
%p
|
||||
%strong COST: 2% OF SALES, CAPPED AT $50 PER MONTH
|
||||
|
||||
%p Your enterprise is the backbone of your local food system. You can sell your own produce as well as produce aggregated from other enterprises through your shopfront on the Open Food Network.
|
||||
|
||||
%p Producer Hubs can take many forms, whether they be a CSA, a veggie-box program, or a food co-op with a rooftop garden.
|
||||
|
||||
%p The Open Food Network aims to support as many hub models as possible, so no matter your situation, we want to provide the tools you need to run your organisation or local food business.
|
||||
|
||||
.info{ ng: { switch: { default: true } } }
|
||||
%h3
|
||||
Please Choose a Package
|
||||
%i.icon-arrow-right
|
||||
|
||||
%p
|
||||
%strong Your producer enterprise will not be fully activated until a package is selected from the options on the left.
|
||||
|
||||
%p
|
||||
Click on an option to see more detailed information about each package, and hit the red SAVE button when you are done!
|
||||
|
||||
.omega.eight.columns{ ng: { switch: "enterprise.is_primary_producer" } }
|
||||
%div{ ng: { switch: { when: "false" } } }
|
||||
%a.button.selector.hub-profile{ ng: { click: "enterprise.owned && (enterprise.sells='none')", class: "{selected: enterprise.sells=='none', disabled: !enterprise.owned}" } }
|
||||
.top
|
||||
%h3 Profile Only
|
||||
%p Get a listing
|
||||
.bottom ALWAYS FREE
|
||||
%a.button.selector.hub{ ng: { click: "enterprise.owned && (enterprise.sells='any')", class: "{selected: enterprise.sells=='any', disabled: !enterprise.owned}" } }
|
||||
.top
|
||||
%h3 Hub Shop
|
||||
%p Sell produce from others
|
||||
.bottom
|
||||
\2% OF SALES
|
||||
%br
|
||||
CAPPED AT $50 PER MONTH
|
||||
|
||||
%div{ ng: { switch: { when: "true" } } }
|
||||
%a.button.selector.producer-profile{ ng: { click: "enterprise.owned && (enterprise.sells='none')", class: "{selected: enterprise.sells=='none', disabled: !enterprise.owned}" } }
|
||||
.top
|
||||
%h3 Profile Only
|
||||
%p Get a listing
|
||||
.bottom ALWAYS FREE
|
||||
%a.button.selector.producer-shop{ ng: { click: "enterprise.owned && (enterprise.sells='own')", class: "{selected: enterprise.sells=='own', disabled: !enterprise.owned}" } }
|
||||
.top
|
||||
%h3 Producer Shop
|
||||
%p Sell your own produce
|
||||
.bottom
|
||||
\2% OF SALES
|
||||
%br
|
||||
CAPPED AT $50 PER MONTH
|
||||
%a.button.selector.producer-hub{ ng: { click: "enterprise.owned && (enterprise.sells='any')", class: "{selected: enterprise.sells=='any', disabled: !enterprise.owned}" } }
|
||||
.top
|
||||
%h3 Producer Hub
|
||||
%p Sell produce from self and others
|
||||
.bottom
|
||||
\2% OF SALES
|
||||
%br
|
||||
CAPPED AT $50 PER MONTH
|
||||
|
||||
%a.button.update.fullwidth{ ng: { show: "enterprise.owned", class: "{disabled: saved() && !saving, saving: saving}", click: "save()" } }
|
||||
%span{ ng: {hide: "saved() || saving" } }
|
||||
SAVE
|
||||
%i.icon-save
|
||||
%span{ ng: {show: "saved() && !saving" } }
|
||||
SAVED
|
||||
%i.icon-ok-sign
|
||||
%span{ ng: {show: "saving" } }
|
||||
SAVING
|
||||
%i.icon-refresh
|
||||
@@ -0,0 +1,39 @@
|
||||
.row.enterprise_producer_panel{ ng: { controller: 'indexProducerPanelCtrl' } }
|
||||
|
||||
.alpha.eight.columns
|
||||
.info{ ng: { show: "enterprise.is_primary_producer==true" } }
|
||||
%h3 Producer
|
||||
%p Producers make yummy things to eat &/or drink. You're a producer if you grow it, raise it, brew it, bake it, ferment it, milk it or mould it.
|
||||
|
||||
%p Producers can also perform other functions, such as aggregating food from other enterprises and selling it through a shop on the Open Food Network.
|
||||
|
||||
|
||||
.info{ ng: { show: "enterprise.is_primary_producer==false" } }
|
||||
%h3 Non-Producer
|
||||
%p Non-producers do not produce any food themselves, meaning that they cannot create their own products for sale through the Open Food Network.
|
||||
|
||||
%p Instead, non-producers specialise in linking producers to the end eater, whether it be by aggregating, grading, packing, selling or delivering food.
|
||||
|
||||
.omega.eight.columns
|
||||
%a.button.selector.producer{ ng: { click: 'enterprise.owned && changeToProducer()', class: "{selected: enterprise.is_primary_producer==true, disabled: !enterprise.owned}" } }
|
||||
.top
|
||||
%h3 PRODUCER
|
||||
%p Producers of food
|
||||
.bottom eg. GROWERS, BAKERS, BREWERS, MAKERS
|
||||
|
||||
%a.button.selector.non-producer{ ng: { click: 'enterprise.owned && changeToNonProducer()', class: "{selected: enterprise.is_primary_producer==false, disabled: !enterprise.owned}" } }
|
||||
.top
|
||||
%h3 Non-Producer
|
||||
%p All other food enterprises
|
||||
.bottom eg. Grocery stores, Food co-ops, Buying groups
|
||||
|
||||
%a.button.update.fullwidth{ ng: { show: "enterprise.owned", class: "{disabled: saved() && !saving, saving: saving}", click: "save()" } }
|
||||
%span{ ng: {hide: "saved() || saving" } }
|
||||
SAVE
|
||||
%i.icon-save
|
||||
%span{ ng: {show: "saved() && !saving" } }
|
||||
SAVED
|
||||
%i.icon-ok-sign
|
||||
%span{ ng: {show: "saving" } }
|
||||
SAVING
|
||||
%i.icon-refresh
|
||||
@@ -0,0 +1,29 @@
|
||||
.row.enterprise_status_panel{ ng: { controller: 'indexStatusPanelCtrl' } }
|
||||
.alpha.omega.sixteen.columns
|
||||
|
||||
%h4.status-ok.text-center{ ng: { show: "issues.length == 0 && warnings.length == 0" } }
|
||||
%i.icon-ok-sign
|
||||
{{ object.name }} is set up and ready to go!
|
||||
|
||||
%table{ ng: { show: "issues.length > 0 || warnings.length > 0" } }
|
||||
%thead
|
||||
%th.severity
|
||||
Severity
|
||||
%th.description
|
||||
Description
|
||||
%th.resolve
|
||||
Resolve
|
||||
%tr{ ng: { repeat: "issue in issues"} }
|
||||
%td.severity
|
||||
%i.icon-warning-sign.issue
|
||||
%td.description
|
||||
%span{ bo: { bind: "issue.description" } }
|
||||
%td.resolve
|
||||
%div{ ng: { bind: { html: "issue.link" } } }
|
||||
%tr{ ng: { repeat: "warning in warnings"} }
|
||||
%td.severity
|
||||
%i.icon-warning-sign.warning
|
||||
%td.description
|
||||
%span{ bo: { bind: "warning.description" } }
|
||||
%td.resolve
|
||||
%div{ ng: { bind: { html: "warning.link" } } }
|
||||
@@ -1,4 +1,4 @@
|
||||
%div{bindonce:true, style: "display: inline-block" }
|
||||
%ul{ bindonce: true }
|
||||
%active-selector{ ng: { repeat: "selector in allSelectors", show: "ifDefined(selector.fits, true)" } }
|
||||
%render-svg{path: "{{selector.object.icon}}", ng: { if: "selector.object.icon"} }
|
||||
%span{"bo-text" => "selector.object.name"}
|
||||
|
||||
@@ -9,12 +9,10 @@
|
||||
%br
|
||||
|
||||
.filter-shopfront.taxon-selectors.inline-block
|
||||
%ul
|
||||
%filter-selector{ objects: "[product] | taxonsOf" }
|
||||
%filter-selector{ objects: "[product] | taxonsOf" }
|
||||
|
||||
.filter-shopfront.property-selectors.inline-block
|
||||
%ul
|
||||
%filter-selector{ objects: "[product] | propertiesWithValuesOf" }
|
||||
%filter-selector{ objects: "[product] | propertiesWithValuesOf" }
|
||||
|
||||
%div{"ng-if" => "product.description"}
|
||||
%hr
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
.small-12.columns
|
||||
.alert-box.info{ "ofn-inline-alert" => true, ng: { show: "visible" } }
|
||||
%h6 Success! {{ enterprise.name }} added to the Open Food Network
|
||||
%span If you exit the wizard at any stage, login and go to admin to edit or update your enterprise details.
|
||||
%span If you exit this wizard at any stage, you need to click the confirmation link in the email you have received. This will take you to your admin interface where you can continue setting up your profile.
|
||||
%a.close{ ng: { click: "close()" } } ×
|
||||
|
||||
.small-12.large-8.columns
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
%p
|
||||
We've sent a confirmation email to
|
||||
%strong {{ enterprise.email }}.
|
||||
%strong {{ enterprise.email }} if it hasn't been activated before.
|
||||
%br Please follow the instructions there to make your enterprise visible on the Open Food Network.
|
||||
|
||||
%a.button.primary{ type: "button", href: "/" } Open Food Network home >
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%h4
|
||||
%small
|
||||
%i.ofn-i_040-hub
|
||||
Create your enterprise profile
|
||||
You can now create a profile for your Producer or Hub
|
||||
.hide-for-large-up
|
||||
%hr
|
||||
%input.button.small.primary{ type: "button", value: "Let's get started!", ng: { click: "select('details')" } }
|
||||
@@ -38,6 +38,7 @@
|
||||
%strong contact
|
||||
you on the Open Food Network.
|
||||
%p Use this space to tell the story of your enterprise, to help drive connections to your social and online presence.
|
||||
%p It's also the first step towards trading on the Open Food Network, or opening an online store.
|
||||
|
||||
.row.show-for-large-up
|
||||
.small-12.columns
|
||||
|
||||
@@ -38,9 +38,13 @@
|
||||
%i.ofn-i_013-help
|
||||
|
||||
%p Producers make yummy things to eat &/or drink. You're a producer if you grow it, raise it, brew it, bake it, ferment it, milk it or mould it.
|
||||
/ %p Hubs connect the producer to the eater. Hubs can be co-ops, independent retailers, buying groups, wholesalers, CSA box schemes, farm-gate stalls, etc.
|
||||
.panel.callout
|
||||
.left
|
||||
%i.ofn-i_013-help
|
||||
|
||||
%p If you’re not a producer, you’re probably someone who sells and distributes food. You might be a hub, coop, buying group, retailer, wholesaler or other.
|
||||
|
||||
.row.buttons
|
||||
.small-12.columns
|
||||
%input.button.secondary{ type: "button", value: "Back", ng: { click: "select('contact')" } }
|
||||
%input.button.primary.right{ type: "submit", value: "Continue" }
|
||||
%input.button.primary.right{ type: "submit", value: "Create Profile" }
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
%ul
|
||||
-# In order for the single-line-selector scope to have access to the available selectors,
|
||||
%filter-selector{objects: "objects()", "active-selectors" => "activeSelectors", "all-selectors" => "allSelectors" }
|
||||
-# In order for the single-line-selector scope to have access to the available selectors,
|
||||
%filter-selector{objects: "objects()", "active-selectors" => "activeSelectors", "all-selectors" => "allSelectors" }
|
||||
|
||||
%li.more{ ng: { show: "overFlowSelectors().length > 0 || fitting" } }
|
||||
%ul{ ng: { if: "overFlowSelectors().length > 0 || fitting" } }
|
||||
%li.more
|
||||
%a.dropdown{ data: { dropdown: "{{ 'show-more-' + selectorName }}" }, ng: { class: "{active: selectedOverFlowSelectors().length > 0}" } }
|
||||
%span
|
||||
+ {{ overFlowSelectors().length }} more
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
*= require shared/jquery-ui-timepicker-addon
|
||||
*= require shared/textAngular.min
|
||||
*= require shared/ng-tags-input.min
|
||||
|
||||
*= require_self
|
||||
*= require_tree .
|
||||
|
||||
113
app/assets/stylesheets/admin/enterprise_index_panels.css.scss
Normal file
113
app/assets/stylesheets/admin/enterprise_index_panels.css.scss
Normal file
@@ -0,0 +1,113 @@
|
||||
.enterprise_package_panel, .enterprise_producer_panel {
|
||||
.info {
|
||||
p {
|
||||
font-size: 1rem;
|
||||
margin: 10px 0px;
|
||||
}
|
||||
}
|
||||
|
||||
a.update {
|
||||
cursor: pointer;
|
||||
margin-bottom: 10px;
|
||||
font-size: 1.3rem;
|
||||
background-color: #DA5354;
|
||||
&:hover {
|
||||
background-color: #CD4E4F;
|
||||
}
|
||||
&.disabled {
|
||||
background-color: #C1C1C1;
|
||||
}
|
||||
&.saving {
|
||||
background-color: #FF9848;
|
||||
i.icon-refresh {
|
||||
-webkit-animation: spin 2s infinite linear;
|
||||
animation: spin 2s infinite linear;
|
||||
}
|
||||
}
|
||||
span{
|
||||
i{
|
||||
font-size: 1.5rem;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a.selector {
|
||||
display: block;
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
border: 2px solid black;
|
||||
text-align: center;
|
||||
// width: 100%;
|
||||
cursor: pointer;
|
||||
&, & * {
|
||||
color: white;
|
||||
}
|
||||
&:hover {
|
||||
&:after {
|
||||
border-top-color: #9fc820;
|
||||
}
|
||||
}
|
||||
&.disabled{
|
||||
background-color: #C1C1C1;
|
||||
}
|
||||
.bottom {
|
||||
background: repeating-linear-gradient(60deg, rgba(84, 152, 218, 0), rgba(84, 152, 218, 0) 5px, rgba(255, 255, 255, 0.25) 5px, rgba(255, 255, 255, 0.25) 10px);
|
||||
margin-top: 1em;
|
||||
margin-left: -15px;
|
||||
margin-right: -15px;
|
||||
padding: 5px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
&.selected {
|
||||
background-color: #000000;
|
||||
|
||||
&:after {
|
||||
top: 50%;
|
||||
left: 0;
|
||||
border: solid transparent;
|
||||
content: " ";
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
|
||||
border-top: 20px solid transparent;
|
||||
border-bottom: 20px solid transparent;
|
||||
border-right: 20px solid #000000;
|
||||
margin-top: -20px;
|
||||
margin-left: -20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.enterprise_status_panel {
|
||||
.status-ok {
|
||||
margin: 30px 0px;
|
||||
i.icon-ok-sign {
|
||||
color: #9fc820;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
td.description{
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
td.severity {
|
||||
text-align: center;
|
||||
|
||||
i {
|
||||
font-size: 1.5rem;
|
||||
|
||||
&.issue{
|
||||
color: #da5354;
|
||||
}
|
||||
|
||||
&.warning{
|
||||
color: #ff9848;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
130
app/assets/stylesheets/admin/index_panels.css.scss
Normal file
130
app/assets/stylesheets/admin/index_panels.css.scss
Normal file
@@ -0,0 +1,130 @@
|
||||
tr.panel-toggle-row {
|
||||
td.panel-toggle{
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
position: relative;
|
||||
|
||||
i.icon-chevron::before {
|
||||
font-size: 1.2rem;
|
||||
content: "\f078";
|
||||
}
|
||||
|
||||
&.error::before {
|
||||
font-family: FontAwesome;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
display: inline-block;
|
||||
text-decoration: inherit;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
font-size: 2rem;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
content: "\f071";
|
||||
color: #da5354;
|
||||
}
|
||||
|
||||
&.status {
|
||||
i.icon-status::before {
|
||||
font-size: 1.5rem;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
i.issue::before {
|
||||
content: "\f071";
|
||||
color: #da5354;
|
||||
}
|
||||
|
||||
i.warning::before {
|
||||
content: "\f071";
|
||||
color: #ff9848;
|
||||
}
|
||||
|
||||
i.ok::before {
|
||||
content: "\f058";
|
||||
color: #9fc820;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
background-color: #d0e2f6;
|
||||
* {
|
||||
color: #1b3c56;
|
||||
}
|
||||
|
||||
i.icon-status::before {
|
||||
opacity: 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.expanded{
|
||||
td {
|
||||
border-bottom: 2px solid #444444;
|
||||
|
||||
&.selected {
|
||||
background-color: #ffffff;
|
||||
border-left: 2px solid #444444;
|
||||
border-right: 2px solid #444444;
|
||||
border-top: 2px solid #444444;
|
||||
border-bottom: none;
|
||||
|
||||
&:hover {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
* {
|
||||
color: #1b3c56;
|
||||
}
|
||||
|
||||
i.icon-status::before {
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
i.icon-chevron::before {
|
||||
content: "\f077";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tr.panel-row {
|
||||
display: none;
|
||||
|
||||
&:hover {
|
||||
td {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
>td {
|
||||
border-color: #444444;
|
||||
padding: 0;
|
||||
.panel {
|
||||
border-left: 1px solid #444444;
|
||||
border-right: 1px solid #444444;
|
||||
border-bottom: 1px solid #444444;
|
||||
|
||||
.row{
|
||||
margin: 0px -4px;
|
||||
|
||||
padding: 20px 0px;
|
||||
|
||||
.column.alpha, .columns.alpha {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.column.omega, .columns.omega {
|
||||
padding-right: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -249,3 +249,18 @@ span.required {
|
||||
color: red;
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
table td.actions {
|
||||
.icon-trash, .icon-edit, icon-copy {
|
||||
&.disabled {
|
||||
border-color: #d0d0d0;
|
||||
color: #c0c0c0;
|
||||
background-color: #fafafa;
|
||||
&:hover {
|
||||
border-color: #a5a5a5;
|
||||
color: #a5a5a5;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,16 +8,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
input.update-pending {
|
||||
border: solid 1px orange;
|
||||
input, div {
|
||||
&.update-pending {
|
||||
border: solid 1px orange;
|
||||
}
|
||||
}
|
||||
|
||||
input.update-error {
|
||||
border: solid 1px red;
|
||||
input, div {
|
||||
&.update-error {
|
||||
border: solid 1px red;
|
||||
}
|
||||
}
|
||||
|
||||
input.update-success {
|
||||
border: solid 1px #9fc820;
|
||||
input, div {
|
||||
&.update-success {
|
||||
border: solid 1px #9fc820;
|
||||
}
|
||||
}
|
||||
|
||||
.no-close .ui-dialog-titlebar-close {
|
||||
@@ -42,4 +48,4 @@ div#group_buy_calculation {
|
||||
.row span {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,24 +92,23 @@
|
||||
span.filter-label
|
||||
opacity: 0.75
|
||||
|
||||
.filter-shopfront.taxon-selectors, .filter-shopfront.property-selectors
|
||||
background: transparent
|
||||
|
||||
single-line-selectors
|
||||
overflow-x: hidden
|
||||
white-space: nowrap
|
||||
|
||||
.f-dropdown
|
||||
overflow-x: auto
|
||||
white-space: normal
|
||||
|
||||
ul
|
||||
margin: 0
|
||||
ul, ul li
|
||||
list-style: none
|
||||
|
||||
|
||||
.filter-shopfront
|
||||
&.taxon-selectors, &.property-selectors
|
||||
background: transparent
|
||||
|
||||
single-line-selectors
|
||||
overflow-x: hidden
|
||||
white-space: nowrap
|
||||
|
||||
.f-dropdown
|
||||
overflow-x: auto
|
||||
white-space: normal
|
||||
|
||||
ul
|
||||
margin: 0
|
||||
display: inline-block
|
||||
ul, ul li
|
||||
list-style: none
|
||||
|
||||
// Shopfront taxons
|
||||
&.taxon-selectors
|
||||
|
||||
@@ -30,9 +30,18 @@
|
||||
float: right
|
||||
margin-left: 0.5rem
|
||||
|
||||
//Hub Link
|
||||
@media all and (max-width: 640px)
|
||||
a.hub
|
||||
display: block
|
||||
|
||||
//Hub Name
|
||||
span.hub-name-listing
|
||||
font-weight: 700
|
||||
&:after
|
||||
content: ">>"
|
||||
display: inline-block
|
||||
margin-left: 5px
|
||||
|
||||
//CLOSED row
|
||||
&.closed
|
||||
@@ -65,6 +74,24 @@
|
||||
.active_table_row:nth-child(2)
|
||||
padding-bottom: 0.75rem
|
||||
|
||||
|
||||
.producers-list
|
||||
li.more-producers-link
|
||||
.less
|
||||
display: none
|
||||
a:hover
|
||||
text-decoration: underline
|
||||
li.additional-producer
|
||||
display: none
|
||||
&.show-more-producers
|
||||
li.additional-producer
|
||||
display: block
|
||||
li.more-producers-link
|
||||
.more
|
||||
display: none
|
||||
.less
|
||||
display: block
|
||||
|
||||
//CURRENT hub (shows selected hub)
|
||||
&.current
|
||||
//overwrites active_table
|
||||
@@ -83,6 +110,7 @@
|
||||
.active_table_row:first-child .skinny-head
|
||||
background-color: rgba(255,255,255,0.85)
|
||||
|
||||
|
||||
//INACTIVE - closed hub
|
||||
&.inactive
|
||||
&.closed, &.open
|
||||
|
||||
1
app/assets/stylesheets/shared/ng-tags-input.min.css
vendored
Executable file
1
app/assets/stylesheets/shared/ng-tags-input.min.css
vendored
Executable file
@@ -0,0 +1 @@
|
||||
tags-input{display:block}tags-input *,tags-input :after,tags-input :before{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}tags-input .host{position:relative;margin-top:5px;margin-bottom:5px;height:100%}tags-input .host:active{outline:0}tags-input .tags{-moz-appearance:textfield;-webkit-appearance:textfield;padding:1px;overflow:hidden;word-wrap:break-word;cursor:text;background-color:#fff;border:1px solid #a9a9a9;box-shadow:1px 1px 1px 0 #d3d3d3 inset;height:100%}tags-input .tags.focused{outline:0;-webkit-box-shadow:0 0 3px 1px rgba(5,139,242,.6);-moz-box-shadow:0 0 3px 1px rgba(5,139,242,.6);box-shadow:0 0 3px 1px rgba(5,139,242,.6)}tags-input .tags .tag-list{margin:0;padding:0;list-style-type:none}tags-input .tags .tag-item{margin:2px;padding:0 5px;display:inline-block;float:left;font:14px "Helvetica Neue",Helvetica,Arial,sans-serif;height:26px;line-height:25px;border:1px solid #acacac;border-radius:3px;background:-webkit-linear-gradient(top,#f0f9ff 0,#cbebff 47%,#a1dbff 100%);background:linear-gradient(to bottom,#f0f9ff 0,#cbebff 47%,#a1dbff 100%)}tags-input .tags .tag-item.selected{background:-webkit-linear-gradient(top,#febbbb 0,#fe9090 45%,#ff5c5c 100%);background:linear-gradient(to bottom,#febbbb 0,#fe9090 45%,#ff5c5c 100%)}tags-input .tags .tag-item .remove-button{margin:0 0 0 5px;padding:0;border:none;background:0 0;cursor:pointer;vertical-align:middle;font:700 16px Arial,sans-serif;color:#585858}tags-input .tags .tag-item .remove-button:active{color:red}tags-input .tags .input{border:0;outline:0;margin:2px;padding:0;padding-left:5px;float:left;height:26px;font:14px "Helvetica Neue",Helvetica,Arial,sans-serif}tags-input .tags .input.invalid-tag{color:red}tags-input .tags .input::-ms-clear{display:none}tags-input.ng-invalid .tags{-webkit-box-shadow:0 0 3px 1px rgba(255,0,0,.6);-moz-box-shadow:0 0 3px 1px rgba(255,0,0,.6);box-shadow:0 0 3px 1px rgba(255,0,0,.6)}tags-input[disabled] .host:focus{outline:0}tags-input[disabled] .tags{background-color:#eee;cursor:default}tags-input[disabled] .tags .tag-item{opacity:.65;background:-webkit-linear-gradient(top,#f0f9ff 0,rgba(203,235,255,.75)47%,rgba(161,219,255,.62)100%);background:linear-gradient(to bottom,#f0f9ff 0,rgba(203,235,255,.75)47%,rgba(161,219,255,.62)100%)}tags-input[disabled] .tags .tag-item .remove-button{cursor:default}tags-input[disabled] .tags .tag-item .remove-button:active{color:#585858}tags-input[disabled] .tags .input{background-color:#eee;cursor:default}tags-input .autocomplete{margin-top:5px;position:absolute;padding:5px 0;z-index:999;width:100%;background-color:#fff;border:1px solid rgba(0,0,0,.2);-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)}tags-input .autocomplete .suggestion-list{margin:0;padding:0;list-style-type:none;max-height:280px;overflow-y:auto;position:relative}tags-input .autocomplete .suggestion-item{padding:5px 10px;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font:16px "Helvetica Neue",Helvetica,Arial,sans-serif;color:#000;background-color:#fff}tags-input .autocomplete .suggestion-item.selected,tags-input .autocomplete .suggestion-item.selected em{color:#fff;background-color:#0097cf}tags-input .autocomplete .suggestion-item em{font:normal bold 16px "Helvetica Neue",Helvetica,Arial,sans-serif;color:#000;background-color:#fff}
|
||||
29
app/controllers/admin/customers_controller.rb
Normal file
29
app/controllers/admin/customers_controller.rb
Normal file
@@ -0,0 +1,29 @@
|
||||
module Admin
|
||||
class CustomersController < ResourceController
|
||||
before_filter :load_managed_shops, only: :index, if: :html_request?
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json do
|
||||
render json: ActiveModel::ArraySerializer.new( @collection,
|
||||
each_serializer: Api::Admin::CustomerSerializer, spree_current_user: spree_current_user
|
||||
).to_json
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def collection
|
||||
return Customer.where("1=0") unless json_request? && params[:enterprise_id].present?
|
||||
enterprise = Enterprise.managed_by(spree_current_user).find_by_id(params[:enterprise_id])
|
||||
Customer.of(enterprise)
|
||||
end
|
||||
|
||||
def load_managed_shops
|
||||
@shops = Enterprise.managed_by(spree_current_user).is_distributor
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -9,7 +9,7 @@ module Admin
|
||||
|
||||
def move_up
|
||||
EnterpriseGroup.with_isolation_level_serializable do
|
||||
@enterprise_group = EnterpriseGroup.find params[:enterprise_group_id]
|
||||
@enterprise_group = EnterpriseGroup.find_by_permalink params[:enterprise_group_id]
|
||||
@enterprise_group.move_higher
|
||||
end
|
||||
redirect_to main_app.admin_enterprise_groups_path
|
||||
@@ -17,7 +17,7 @@ module Admin
|
||||
|
||||
def move_down
|
||||
EnterpriseGroup.with_isolation_level_serializable do
|
||||
@enterprise_group = EnterpriseGroup.find params[:enterprise_group_id]
|
||||
@enterprise_group = EnterpriseGroup.find_by_permalink params[:enterprise_group_id]
|
||||
@enterprise_group.move_lower
|
||||
end
|
||||
redirect_to main_app.admin_enterprise_groups_path
|
||||
@@ -33,6 +33,12 @@ module Admin
|
||||
end
|
||||
alias_method_chain :build_resource, :address
|
||||
|
||||
# Overriding method on Spree's resource controller,
|
||||
# so that resources are found using permalink
|
||||
def find_resource
|
||||
EnterpriseGroup.find_by_permalink(params[:id])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_data
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
require 'open_food_network/referer_parser'
|
||||
|
||||
module Admin
|
||||
class EnterprisesController < ResourceController
|
||||
before_filter :load_enterprise_set, :only => :index
|
||||
before_filter :load_countries, :except => [:index, :set_sells, :check_permalink]
|
||||
before_filter :load_countries, :except => [:index, :register, :check_permalink]
|
||||
before_filter :load_methods_and_fees, :only => [:new, :edit, :update, :create]
|
||||
before_filter :load_groups, :only => [:new, :edit, :update, :create]
|
||||
before_filter :load_taxons, :only => [:new, :edit, :update, :create]
|
||||
before_filter :check_can_change_sells, only: :update
|
||||
before_filter :check_can_change_bulk_sells, only: :bulk_update
|
||||
@@ -15,34 +18,61 @@ module Admin
|
||||
before_filter :load_properties, only: [:edit, :update]
|
||||
before_filter :setup_property, only: [:edit]
|
||||
|
||||
|
||||
helper 'spree/products'
|
||||
include ActionView::Helpers::TextHelper
|
||||
include OrderCyclesHelper
|
||||
|
||||
def set_sells
|
||||
enterprise = Enterprise.find_by_permalink(params[:id]) || Enterprise.find(params[:id])
|
||||
attributes = { sells: params[:sells] }
|
||||
attributes[:producer_profile_only] = params[:sells] == "none" && !!params[:producer_profile_only]
|
||||
attributes[:shop_trial_start_date] = Time.now if params[:sells] == "own"
|
||||
def index
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json do
|
||||
render json: @collection, each_serializer: Api::Admin::IndexEnterpriseSerializer, spree_current_user: spree_current_user
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if %w(none own).include?(params[:sells])
|
||||
if params[:sells] == 'own' && enterprise.shop_trial_start_date
|
||||
expiry = enterprise.shop_trial_start_date + Enterprise::SHOP_TRIAL_LENGTH.days
|
||||
if Time.now > expiry
|
||||
flash[:error] = "Sorry, but you've already had a trial. Expired on: #{expiry.strftime('%Y-%m-%d')}"
|
||||
else
|
||||
attributes.delete :shop_trial_start_date
|
||||
enterprise.update_attributes(attributes)
|
||||
flash[:notice] = "Welcome back! Your trial expires on: #{expiry.strftime('%Y-%m-%d')}"
|
||||
end
|
||||
elsif enterprise.update_attributes(attributes)
|
||||
flash[:success] = "Congratulations! Registration for #{enterprise.name} is complete!"
|
||||
def welcome
|
||||
render layout: "spree/layouts/bare_admin"
|
||||
end
|
||||
|
||||
|
||||
def update
|
||||
invoke_callbacks(:update, :before)
|
||||
if @object.update_attributes(params[object_name])
|
||||
invoke_callbacks(:update, :after)
|
||||
flash[:success] = flash_message_for(@object, :successfully_updated)
|
||||
respond_with(@object) do |format|
|
||||
format.html { redirect_to location_after_save }
|
||||
format.js { render :layout => false }
|
||||
format.json { render json: @object, serializer: Api::Admin::IndexEnterpriseSerializer, spree_current_user: spree_current_user }
|
||||
end
|
||||
else
|
||||
flash[:error] = "Unauthorised"
|
||||
invoke_callbacks(:update, :fails)
|
||||
respond_with(@object) do |format|
|
||||
format.json { render json: { errors: @object.errors.messages }, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def register
|
||||
if params[:sells] == 'unspecified'
|
||||
flash[:error] = "Please select a package"
|
||||
return render :welcome, layout: "spree/layouts/bare_admin"
|
||||
end
|
||||
|
||||
attributes = { sells: params[:sells], visible: true }
|
||||
|
||||
if ['own', 'any'].include? params[:sells]
|
||||
attributes[:shop_trial_start_date] = @enterprise.shop_trial_start_date || Time.now
|
||||
end
|
||||
|
||||
if @enterprise.update_attributes(attributes)
|
||||
flash[:success] = "Congratulations! Registration for #{@enterprise.name} is complete!"
|
||||
redirect_to admin_path
|
||||
else
|
||||
flash[:error] = "Could not complete registration for #{@enterprise.name}"
|
||||
render :welcome, layout: "spree/layouts/bare_admin"
|
||||
end
|
||||
redirect_to admin_path
|
||||
end
|
||||
|
||||
def bulk_update
|
||||
@@ -95,7 +125,7 @@ module Admin
|
||||
private
|
||||
|
||||
def load_enterprise_set
|
||||
@enterprise_set = EnterpriseSet.new collection
|
||||
@enterprise_set = EnterpriseSet.new(collection) if spree_current_user.admin?
|
||||
end
|
||||
|
||||
def load_countries
|
||||
@@ -109,6 +139,16 @@ module Admin
|
||||
coordinator = Enterprise.find_by_id(params[:coordinator_id]) if params[:coordinator_id]
|
||||
order_cycle = OrderCycle.new(coordinator: coordinator) if order_cycle.nil? && coordinator.present?
|
||||
return OpenFoodNetwork::OrderCyclePermissions.new(spree_current_user, order_cycle).visible_enterprises
|
||||
when :index
|
||||
if spree_current_user.admin?
|
||||
OpenFoodNetwork::Permissions.new(spree_current_user).
|
||||
editable_enterprises.
|
||||
order('is_primary_producer ASC, name')
|
||||
elsif json_request?
|
||||
OpenFoodNetwork::Permissions.new(spree_current_user).editable_enterprises
|
||||
else
|
||||
Enterprise.where("1=0") unless json_request?
|
||||
end
|
||||
else
|
||||
# TODO was ordered with is_distributor DESC as well, not sure why or how we want to sort this now
|
||||
OpenFoodNetwork::Permissions.new(spree_current_user).
|
||||
@@ -127,6 +167,10 @@ module Admin
|
||||
@enterprise_fees = EnterpriseFee.managed_by(spree_current_user).for_enterprise(@enterprise).order(:fee_type, :name).all
|
||||
end
|
||||
|
||||
def load_groups
|
||||
@groups = EnterpriseGroup.managed_by(spree_current_user) | @enterprise.groups
|
||||
end
|
||||
|
||||
def load_taxons
|
||||
@taxons = Spree::Taxon.order(:name)
|
||||
end
|
||||
@@ -134,13 +178,15 @@ module Admin
|
||||
def check_can_change_bulk_sells
|
||||
unless spree_current_user.admin?
|
||||
params[:enterprise_set][:collection_attributes].each do |i, enterprise_params|
|
||||
enterprise_params.delete :sells
|
||||
enterprise_params.delete :sells unless spree_current_user == Enterprise.find_by_id(enterprise_params[:id]).owner
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def check_can_change_sells
|
||||
params[:enterprise].delete :sells unless spree_current_user.admin?
|
||||
unless spree_current_user.admin? || spree_current_user == @enterprise.owner
|
||||
params[:enterprise].delete :sells
|
||||
end
|
||||
end
|
||||
|
||||
def override_owner
|
||||
@@ -194,7 +240,8 @@ module Admin
|
||||
|
||||
# Overriding method on Spree's resource controller
|
||||
def location_after_save
|
||||
refered_from_edit = URI(request.referer).path == main_app.edit_admin_enterprise_path(@enterprise)
|
||||
referer_path = OpenFoodNetwork::RefererParser::path(request.referer)
|
||||
refered_from_edit = referer_path == main_app.edit_admin_enterprise_path(@enterprise)
|
||||
if params[:enterprise].key?(:producer_properties_attributes) && !refered_from_edit
|
||||
main_app.admin_enterprises_path
|
||||
else
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'open_food_network/referer_parser'
|
||||
|
||||
class ApplicationController < ActionController::Base
|
||||
protect_from_forgery
|
||||
|
||||
@@ -9,7 +11,8 @@ class ApplicationController < ActionController::Base
|
||||
end
|
||||
|
||||
def set_checkout_redirect
|
||||
if request.referer and referer_path = URI(request.referer).path
|
||||
referer_path = OpenFoodNetwork::RefererParser::path(request.referer)
|
||||
if referer_path
|
||||
session["spree_user_return_to"] = [main_app.checkout_path].include?(referer_path) ? referer_path : root_path
|
||||
end
|
||||
end
|
||||
|
||||
@@ -12,9 +12,6 @@ class BaseController < ApplicationController
|
||||
|
||||
before_filter :check_order_cycle_expiry
|
||||
|
||||
def load_active_distributors
|
||||
@active_distributors ||= Enterprise.distributors_with_active_order_cycles
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
|
||||
@@ -12,9 +12,6 @@ class CheckoutController < Spree::CheckoutController
|
||||
include EnterprisesHelper
|
||||
|
||||
def edit
|
||||
# Because this controller doesn't inherit from our BaseController
|
||||
# We need to duplicate the code here
|
||||
@active_distributors ||= Enterprise.distributors_with_active_order_cycles
|
||||
end
|
||||
|
||||
def update
|
||||
|
||||
@@ -40,7 +40,7 @@ class EnterpriseConfirmationsController < DeviseController
|
||||
def new_user_reset_path(resource)
|
||||
password = Devise.friendly_token.first(8)
|
||||
user = Spree::User.create(email: resource.email, password: password, password_confirmation: password)
|
||||
user.send_reset_password_instructions
|
||||
user.send_reset_password_instructions_without_delay
|
||||
resource.users << user
|
||||
spree.edit_spree_user_password_path(user, :reset_password_token => user.reset_password_token, return_to: spree.admin_path)
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ class EnterprisesController < BaseController
|
||||
include OrderCyclesHelper
|
||||
|
||||
# These prepended filters are in the reverse order of execution
|
||||
prepend_before_filter :load_active_distributors, :set_order_cycles, :require_distributor_chosen, :reset_order, only: :shop
|
||||
prepend_before_filter :set_order_cycles, :require_distributor_chosen, :reset_order, only: :shop
|
||||
before_filter :clean_permalink, only: :check_permalink
|
||||
|
||||
respond_to :js, only: :permalink_checker
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
class GroupsController < BaseController
|
||||
layout 'darkswarm'
|
||||
before_filter :load_active_distributors
|
||||
|
||||
def index
|
||||
@groups = EnterpriseGroup.on_front_page.by_position
|
||||
end
|
||||
|
||||
def show
|
||||
@group = EnterpriseGroup.find params[:id]
|
||||
@group = EnterpriseGroup.find_by_permalink(params[:id]) || EnterpriseGroup.find(params[:id])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
class HomeController < BaseController
|
||||
layout 'darkswarm'
|
||||
before_filter :load_active_distributors
|
||||
|
||||
|
||||
def index
|
||||
end
|
||||
|
||||
def about_us
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
class MapController < BaseController
|
||||
layout 'darkswarm'
|
||||
before_filter :load_active_distributors
|
||||
|
||||
def index
|
||||
end
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
class ProducersController < BaseController
|
||||
layout 'darkswarm'
|
||||
before_filter :load_active_distributors
|
||||
|
||||
|
||||
def index
|
||||
end
|
||||
end
|
||||
|
||||
@@ -10,12 +10,20 @@ class ShopController < BaseController
|
||||
end
|
||||
|
||||
def products
|
||||
# Can we make this query less slow?
|
||||
#
|
||||
if @products = products_for_shop
|
||||
|
||||
enterprise_fee_calculator = OpenFoodNetwork::EnterpriseFeeCalculator.new current_distributor, current_order_cycle
|
||||
|
||||
render status: 200,
|
||||
json: ActiveModel::ArraySerializer.new(@products, each_serializer: Api::ProductSerializer,
|
||||
current_order_cycle: current_order_cycle, current_distributor: current_distributor).to_json
|
||||
json: ActiveModel::ArraySerializer.new(@products,
|
||||
each_serializer: Api::ProductSerializer,
|
||||
current_order_cycle: current_order_cycle,
|
||||
current_distributor: current_distributor,
|
||||
variants: variants_for_shop_by_id,
|
||||
master_variants: master_variants_for_shop_by_id,
|
||||
enterprise_fee_calculator: enterprise_fee_calculator,
|
||||
).to_json
|
||||
|
||||
else
|
||||
render json: "", status: 404
|
||||
end
|
||||
@@ -56,4 +64,30 @@ class ShopController < BaseController
|
||||
"name ASC"
|
||||
end
|
||||
end
|
||||
|
||||
def all_variants_for_shop
|
||||
# We use the in_stock? method here instead of the in_stock scope because we need to
|
||||
# look up the stock as overridden by VariantOverrides, and the scope method is not affected
|
||||
# by them.
|
||||
Spree::Variant.
|
||||
for_distribution(current_order_cycle, current_distributor).
|
||||
each { |v| v.scope_to_hub current_distributor }.
|
||||
select(&:in_stock?)
|
||||
end
|
||||
|
||||
def variants_for_shop_by_id
|
||||
index_by_product_id all_variants_for_shop.reject(&:is_master)
|
||||
end
|
||||
|
||||
def master_variants_for_shop_by_id
|
||||
index_by_product_id all_variants_for_shop.select(&:is_master)
|
||||
end
|
||||
|
||||
def index_by_product_id(variants)
|
||||
variants.inject({}) do |vs, v|
|
||||
vs[v.product_id] ||= []
|
||||
vs[v.product_id] << v
|
||||
vs
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -58,4 +58,12 @@ Spree::Admin::BaseController.class_eval do
|
||||
"Until you set these up, customers will not be able to shop at this hub."
|
||||
end
|
||||
end
|
||||
|
||||
def html_request?
|
||||
request.format.html?
|
||||
end
|
||||
|
||||
def json_request?
|
||||
request.format.json?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,7 +7,7 @@ Spree::Admin::OrdersController.class_eval do
|
||||
# We need to add expections for collection actions other than :index here
|
||||
# because spree_auth_devise causes load_order to be called, which results
|
||||
# in an auth failure as the @order object is nil for collection actions
|
||||
before_filter :check_authorization, :except => :bulk_management
|
||||
before_filter :check_authorization, except: [:bulk_management, :managed]
|
||||
|
||||
# After updating an order, the fees should be updated as well
|
||||
# Currently, adding or deleting line items does not trigger updating the
|
||||
@@ -17,12 +17,19 @@ Spree::Admin::OrdersController.class_eval do
|
||||
after_filter :update_distribution_charge, :only => :update
|
||||
|
||||
respond_override :index => { :html =>
|
||||
{ :success => lambda {
|
||||
{ :success => lambda {
|
||||
# Filter orders to only show those distributed by current user (or all for admin user)
|
||||
@orders = @search.result.includes([:user, :shipments, :payments]).
|
||||
distributed_by_user(spree_current_user).
|
||||
page(params[:page]).
|
||||
per(params[:per_page] || Spree::Config[:orders_per_page])
|
||||
# Filter orders by distributor
|
||||
if params[:distributor_ids]
|
||||
@orders = @orders.where(distributor_id: params[:distributor_ids])
|
||||
end
|
||||
if params[:order_cycle_ids]
|
||||
@orders = @orders.where(order_cycle_id: params[:order_cycle_ids])
|
||||
end
|
||||
} } }
|
||||
|
||||
# Overwrite to use confirm_email_for_customer instead of confirm_email.
|
||||
@@ -37,4 +44,10 @@ Spree::Admin::OrdersController.class_eval do
|
||||
def update_distribution_charge
|
||||
@order.update_distribution_charge!
|
||||
end
|
||||
|
||||
def managed
|
||||
permissions = OpenFoodNetwork::Permissions.new(spree_current_user)
|
||||
@orders = permissions.editable_orders.order(:id).ransack(params[:q]).result.page(params[:page]).per(params[:per_page])
|
||||
render json: @orders, each_serializer: Api::Admin::OrderSerializer
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,16 +5,22 @@ Spree::Admin::OverviewController.class_eval do
|
||||
@product_count = Spree::Product.active.managed_by(spree_current_user).count
|
||||
@order_cycle_count = OrderCycle.active.managed_by(spree_current_user).count
|
||||
|
||||
unspecified = spree_current_user.owned_enterprises.where(sells: 'unspecified')
|
||||
outside_referral = !URI(request.referer.to_s).path.match(/^\/admin/)
|
||||
|
||||
if OpenFoodNetwork::Permissions.new(spree_current_user).manages_one_enterprise? && !spree_current_user.admin?
|
||||
@enterprise = @enterprises.first
|
||||
if @enterprise.sells == "unspecified"
|
||||
render "welcome", layout: "spree/layouts/bare_admin"
|
||||
if outside_referral && unspecified.any?
|
||||
redirect_to main_app.welcome_admin_enterprise_path(@enterprise)
|
||||
else
|
||||
render "single_enterprise_dashboard"
|
||||
end
|
||||
else
|
||||
render "multi_enterprise_dashboard"
|
||||
if outside_referral && unspecified.any?
|
||||
redirect_to main_app.admin_enterprises_path
|
||||
else
|
||||
render "multi_enterprise_dashboard"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
require 'open_food_network/spree_api_key_loader'
|
||||
require 'open_food_network/referer_parser'
|
||||
|
||||
Spree::Admin::ProductsController.class_eval do
|
||||
include OpenFoodNetwork::SpreeApiKeyLoader
|
||||
@@ -53,7 +54,8 @@ Spree::Admin::ProductsController.class_eval do
|
||||
|
||||
protected
|
||||
def location_after_save
|
||||
if URI(request.referer).path == '/admin/products/bulk_edit'
|
||||
referer_path = OpenFoodNetwork::RefererParser::path(request.referer)
|
||||
if referer_path == '/admin/products/bulk_edit'
|
||||
bulk_edit_admin_products_url
|
||||
else
|
||||
location_after_save_original
|
||||
|
||||
@@ -7,6 +7,7 @@ require 'open_food_network/customers_report'
|
||||
require 'open_food_network/users_and_enterprises_report'
|
||||
require 'open_food_network/order_cycle_management_report'
|
||||
require 'open_food_network/sales_tax_report'
|
||||
require 'open_food_network/xero_invoices_report'
|
||||
|
||||
Spree::Admin::ReportsController.class_eval do
|
||||
|
||||
@@ -679,7 +680,22 @@ Spree::Admin::ReportsController.class_eval do
|
||||
render_report(@report.header, @report.table, params[:csv], "users_and_enterprises_#{timestamp}.csv")
|
||||
end
|
||||
|
||||
def render_report (header, table, create_csv, csv_file_name)
|
||||
def xero_invoices
|
||||
if request.get?
|
||||
params[:q] ||= {}
|
||||
params[:q][:completed_at_gt] = Time.zone.now.beginning_of_month
|
||||
end
|
||||
@distributors = Enterprise.is_distributor.managed_by(spree_current_user)
|
||||
@order_cycles = OrderCycle.active_or_complete.accessible_by(spree_current_user).order('orders_close_at DESC')
|
||||
|
||||
@search = Spree::Order.complete.managed_by(spree_current_user).order('id DESC').search(params[:q])
|
||||
orders = @search.result
|
||||
@report = OpenFoodNetwork::XeroInvoicesReport.new orders, params
|
||||
render_report(@report.header, @report.table, params[:csv], "xero_invoices_#{timestamp}.csv")
|
||||
end
|
||||
|
||||
|
||||
def render_report(header, table, create_csv, csv_file_name)
|
||||
unless create_csv
|
||||
render :html => table
|
||||
else
|
||||
@@ -716,7 +732,9 @@ Spree::Admin::ReportsController.class_eval do
|
||||
:sales_total => { :name => "Sales Total", :description => "Sales Total For All Orders" },
|
||||
:users_and_enterprises => { :name => "Users & Enterprises", :description => "Enterprise Ownership & Status" },
|
||||
:order_cycle_management => {:name => "Order Cycle Management", :description => ''},
|
||||
:sales_tax => { :name => "Sales Tax", :description => "Sales Tax For Orders" }
|
||||
:sales_tax => { :name => "Sales Tax", :description => "Sales Tax For Orders" },
|
||||
:xero_invoices => { :name => "Xero Invoices", :description => 'Invoices for import into Xero' }
|
||||
|
||||
}
|
||||
# Return only reports the user is authorized to view.
|
||||
reports.select { |action| can? action, :report }
|
||||
|
||||
@@ -4,7 +4,7 @@ Spree::Admin::VariantsController.class_eval do
|
||||
def search
|
||||
search_params = { :product_name_cont => params[:q], :sku_cont => params[:q] }
|
||||
|
||||
@variants = Spree::Variant.ransack(search_params.merge(:m => 'or')).result
|
||||
@variants = Spree::Variant.where(is_master: false).ransack(search_params.merge(:m => 'or')).result
|
||||
|
||||
if params[:order_cycle_id].present?
|
||||
order_cycle = OrderCycle.find params[:order_cycle_id]
|
||||
|
||||
11
app/controllers/spree/api/line_items_controller_decorator.rb
Normal file
11
app/controllers/spree/api/line_items_controller_decorator.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
Spree::Api::LineItemsController.class_eval do
|
||||
after_filter :apply_enterprise_fees, only: :update
|
||||
|
||||
|
||||
private
|
||||
|
||||
def apply_enterprise_fees
|
||||
authorize! :read, order
|
||||
order.update_distribution_charge!
|
||||
end
|
||||
end
|
||||
@@ -4,12 +4,4 @@ Spree::Api::OrdersController.class_eval do
|
||||
# because Spree's API controller causes authorize_read! to be called, which
|
||||
# results in an ActiveRecord::NotFound Exception as the order object is not
|
||||
# defined for collection actions
|
||||
before_filter :authorize_read!, :except => [:managed]
|
||||
|
||||
def managed
|
||||
authorize! :admin, Spree::Order
|
||||
authorize! :read, Spree::Order
|
||||
@orders = Spree::Order.ransack(params[:q]).result.distributed_by_user(current_api_user).page(params[:page]).per(params[:per_page])
|
||||
respond_with(@orders, default_template: :index)
|
||||
end
|
||||
end
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user