Compare commits
402 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
312a6299a8 | ||
|
|
ef064819f9 | ||
|
|
924492ec5b | ||
|
|
e3723da65a | ||
|
|
b4755c37dc | ||
|
|
b86872095a | ||
|
|
3520127c41 | ||
|
|
3d0880857a | ||
|
|
e8c8d8885c | ||
|
|
6fb3fa55a1 | ||
|
|
f3f0766279 | ||
|
|
0d5ce5ff57 | ||
|
|
68b4cb59be | ||
|
|
f88fdac710 | ||
|
|
a7019e7e78 | ||
|
|
bd66091d75 | ||
|
|
d8f5669fbb | ||
|
|
5806f50a84 | ||
|
|
5cd528a87d | ||
|
|
f0f7e0ee2f | ||
|
|
7ffe0f042e | ||
|
|
f79fba52be | ||
|
|
4259b466f5 | ||
|
|
0a03483e36 | ||
|
|
28bf7037db | ||
|
|
ed9bbe2c45 | ||
|
|
b5c7607d67 | ||
|
|
e640376d63 | ||
|
|
9ab16d8cec | ||
|
|
d8c23d37ac | ||
|
|
89b153dc2c | ||
|
|
bd6bac8874 | ||
|
|
50d2ddc05f | ||
|
|
10b7a86745 | ||
|
|
6d33dc5070 | ||
|
|
d109e898d2 | ||
|
|
3dee29cd12 | ||
|
|
0921cd2dfa | ||
|
|
7b4130972b | ||
|
|
485eee4bdd | ||
|
|
f84e704d99 | ||
|
|
ad7e5a45bb | ||
|
|
d9404d3332 | ||
|
|
e43d726b97 | ||
|
|
8788322492 | ||
|
|
368402f115 | ||
|
|
9e70c80d1d | ||
|
|
8fb11defdb | ||
|
|
9c26b3ebb2 | ||
|
|
3fc616cdff | ||
|
|
16e9f0545b | ||
|
|
a3664d4448 | ||
|
|
11acb3ba59 | ||
|
|
e91de69d5a | ||
|
|
03ae740cd6 | ||
|
|
7c55285708 | ||
|
|
e6e063670c | ||
|
|
153604dd64 | ||
|
|
b7bac326bd | ||
|
|
a6cecdcc25 | ||
|
|
af78859db6 | ||
|
|
5efc0a5110 | ||
|
|
2c7a5c0656 | ||
|
|
0b652a2113 | ||
|
|
b498c28632 | ||
|
|
8184a7c7b2 | ||
|
|
b09ae550c8 | ||
|
|
f4df227ef0 | ||
|
|
a207f50aeb | ||
|
|
ecf635e080 | ||
|
|
2e66a082eb | ||
|
|
3b61d7a1e0 | ||
|
|
c3f99d7540 | ||
|
|
f6d87eee87 | ||
|
|
e82a3a9d82 | ||
|
|
8511bd19ce | ||
|
|
1268108877 | ||
|
|
2b0f867ed8 | ||
|
|
9e61a7d083 | ||
|
|
6bbd3f7c13 | ||
|
|
6a4de7c7e2 | ||
|
|
505fd8ff96 | ||
|
|
b1b1bfd8f6 | ||
|
|
f94a5a975a | ||
|
|
29faa5f3c6 | ||
|
|
8e2c224d4d | ||
|
|
bb2f2a6f54 | ||
|
|
dab3b59f6a | ||
|
|
bdf462926d | ||
|
|
355221a273 | ||
|
|
9149276048 | ||
|
|
c66a7e44b6 | ||
|
|
9eb99d1c4a | ||
|
|
6cde1f7732 | ||
|
|
7b83438b5e | ||
|
|
e6a98747b4 | ||
|
|
ed15b95de0 | ||
|
|
3df2720b31 | ||
|
|
eff8681d9b | ||
|
|
a937fd3c61 | ||
|
|
3412bc25bf | ||
|
|
f1a8011e13 | ||
|
|
92e03e208f | ||
|
|
0251d8962d | ||
|
|
1c617994fc | ||
|
|
4a4b3da551 | ||
|
|
e546388784 | ||
|
|
976c24cf4c | ||
|
|
f610a709e1 | ||
|
|
5d6f265c0a | ||
|
|
1f293bb787 | ||
|
|
a4a41ae26a | ||
|
|
7aeeb6d18f | ||
|
|
7a78f4870a | ||
|
|
28c79cdb50 | ||
|
|
b9e3ff54b8 | ||
|
|
0c0be0112e | ||
|
|
883a2e0a0e | ||
|
|
6c81109b17 | ||
|
|
1c9a95b3d6 | ||
|
|
53c4c8b5b7 | ||
|
|
d406f9ccdf | ||
|
|
7d4a4f8f9d | ||
|
|
35536a629c | ||
|
|
7b8938b5f6 | ||
|
|
b2717ffca0 | ||
|
|
700cb73b8f | ||
|
|
9d225142c8 | ||
|
|
998288e21f | ||
|
|
9f93c9f221 | ||
|
|
22127b2d18 | ||
|
|
692e58e8f7 | ||
|
|
4158663e9a | ||
|
|
a1673afff0 | ||
|
|
0d4dbd23fd | ||
|
|
0d9ba4257d | ||
|
|
c43eb9ef72 | ||
|
|
46690faffb | ||
|
|
32f14bca00 | ||
|
|
042e076b58 | ||
|
|
6d96a7a60b | ||
|
|
c8bf207187 | ||
|
|
9e8483348f | ||
|
|
81324f3cc4 | ||
|
|
0b8a619274 | ||
|
|
048c6a8ee8 | ||
|
|
3e8801b12b | ||
|
|
a6a5fdfb3b | ||
|
|
0bdb8f7241 | ||
|
|
05551aa2a9 | ||
|
|
9bbc151cae | ||
|
|
08fef890ec | ||
|
|
a93633a626 | ||
|
|
4bd1ff2011 | ||
|
|
2914990444 | ||
|
|
3ce2c5b84f | ||
|
|
77d7255243 | ||
|
|
6bb926f811 | ||
|
|
829d11d4b2 | ||
|
|
beec910445 | ||
|
|
68f0e51c02 | ||
|
|
210c76eddc | ||
|
|
e75c6a8e1d | ||
|
|
b44f2bcdf5 | ||
|
|
f13b52411d | ||
|
|
0cf8b017b9 | ||
|
|
2b5fc656fe | ||
|
|
524f02717b | ||
|
|
456a6f94f5 | ||
|
|
afe77925ba | ||
|
|
5940ff2b2c | ||
|
|
d1ab2d9dac | ||
|
|
ccc1f3df40 | ||
|
|
e9fbd74e88 | ||
|
|
bb3bdf37cd | ||
|
|
af4baabb50 | ||
|
|
3bbf42c3e7 | ||
|
|
530740158c | ||
|
|
771b9e0df5 | ||
|
|
1d5a4c93e4 | ||
|
|
61cb2514cd | ||
|
|
aef3fdf4b4 | ||
|
|
a384f5e3d4 | ||
|
|
318957551f | ||
|
|
e017c30ab7 | ||
|
|
23888b7576 | ||
|
|
ff07707af7 | ||
|
|
78bf87614a | ||
|
|
2b50f993de | ||
|
|
4672cc4863 | ||
|
|
768cfab591 | ||
|
|
7f973604e5 | ||
|
|
7f6c02ca29 | ||
|
|
34d1841d22 | ||
|
|
e570352a1b | ||
|
|
2e021941d1 | ||
|
|
48bf87ec73 | ||
|
|
548e3576b9 | ||
|
|
201bcb133a | ||
|
|
0c155e6e3a | ||
|
|
2072744870 | ||
|
|
0f9fbe6e8c | ||
|
|
b24cad7aeb | ||
|
|
bc89018ee1 | ||
|
|
88bae32971 | ||
|
|
6f81a9ba18 | ||
|
|
22a37cdc8a | ||
|
|
9c376f0b00 | ||
|
|
59a2c84857 | ||
|
|
6ac45f3dc8 | ||
|
|
e3138c3cd2 | ||
|
|
26d55baa35 | ||
|
|
02f8f293da | ||
|
|
2fd25f6cc4 | ||
|
|
24e3c9a9e1 | ||
|
|
8b7d321dfe | ||
|
|
72403fd021 | ||
|
|
1e168afd71 | ||
|
|
1e6fd94663 | ||
|
|
96c173414b | ||
|
|
226e2f0e2c | ||
|
|
2280a71b23 | ||
|
|
6f24e969ce | ||
|
|
e26ebf4239 | ||
|
|
81a745420e | ||
|
|
c28ebf63ab | ||
|
|
69004ac477 | ||
|
|
430320e3f9 | ||
|
|
60a3d8e0d1 | ||
|
|
8a3126f117 | ||
|
|
c7157ce7bd | ||
|
|
133f7e4ec7 | ||
|
|
fbcfe9b2a4 | ||
|
|
adc1b639bc | ||
|
|
61a9e2f7cc | ||
|
|
f6e635466b | ||
|
|
32cc17745a | ||
|
|
b1624a733e | ||
|
|
b8ce6ed0fc | ||
|
|
104a8ddecf | ||
|
|
4dcfec1de9 | ||
|
|
8859aa27ee | ||
|
|
24062e5585 | ||
|
|
4a87798bb4 | ||
|
|
ae1681b790 | ||
|
|
36c5cdf556 | ||
|
|
d516795774 | ||
|
|
7eb735f87e | ||
|
|
7448d41b27 | ||
|
|
7ebea23fda | ||
|
|
b7de8353bc | ||
|
|
52dc313e70 | ||
|
|
a4b80b1f33 | ||
|
|
f20844c2a0 | ||
|
|
136d361134 | ||
|
|
009b25a491 | ||
|
|
bf87394a76 | ||
|
|
d28fc7e42d | ||
|
|
a10de68430 | ||
|
|
3b9824171a | ||
|
|
5d7659aa3c | ||
|
|
1e1d52cc47 | ||
|
|
76648b97b0 | ||
|
|
5020eb4e32 | ||
|
|
cb376602f2 | ||
|
|
3aa5f6e023 | ||
|
|
8926e3765e | ||
|
|
5b235f356e | ||
|
|
8ed6653dc4 | ||
|
|
ca1a5b5f8d | ||
|
|
8d95ba2c69 | ||
|
|
94a88278a9 | ||
|
|
588e036c1d | ||
|
|
aa7ddbcba4 | ||
|
|
54af6886c2 | ||
|
|
d49dd62124 | ||
|
|
d4cf44a6dd | ||
|
|
6e77a5eebc | ||
|
|
2d5118290b | ||
|
|
74b7feda53 | ||
|
|
f5bacf71b7 | ||
|
|
3817ef202c | ||
|
|
aa170ef5f6 | ||
|
|
4d14acb64d | ||
|
|
43d2eb4d22 | ||
|
|
887579ecb8 | ||
|
|
9430999540 | ||
|
|
193a061c44 | ||
|
|
540ac845da | ||
|
|
5e015f0611 | ||
|
|
681dada5df | ||
|
|
99bd6244ed | ||
|
|
63e345f819 | ||
|
|
524645aff4 | ||
|
|
d115ef5f7e | ||
|
|
35b27fcfd2 | ||
|
|
b747f61eb1 | ||
|
|
45f6042d3d | ||
|
|
a1aa9512a8 | ||
|
|
7e24e6743e | ||
|
|
c9f343f680 | ||
|
|
d8c4e292c8 | ||
|
|
81765de7a7 | ||
|
|
4dff3fe79c | ||
|
|
1927bc55d0 | ||
|
|
e9f2e743ce | ||
|
|
1c09b8b76f | ||
|
|
00821a60cc | ||
|
|
252ddf9beb | ||
|
|
22161bfd6e | ||
|
|
6c4db7fc22 | ||
|
|
df4437ecfe | ||
|
|
2310a6a7db | ||
|
|
85e4b3970c | ||
|
|
75a37e16e3 | ||
|
|
f8a9652333 | ||
|
|
75ed259554 | ||
|
|
a9c7e4b716 | ||
|
|
0b082c964b | ||
|
|
8037811735 | ||
|
|
0ed1eeffd6 | ||
|
|
d471368412 | ||
|
|
09a102bd8b | ||
|
|
d8656a36c6 | ||
|
|
89d4a59e9d | ||
|
|
84f3097217 | ||
|
|
333a4ecf2f | ||
|
|
40b4edeca1 | ||
|
|
9650692699 | ||
|
|
69dc92dec1 | ||
|
|
d489e06009 | ||
|
|
daa30ed518 | ||
|
|
7fb8370c36 | ||
|
|
e2a4b9a898 | ||
|
|
2a7a106ad8 | ||
|
|
1005a06583 | ||
|
|
c36272ead6 | ||
|
|
c6ddf36856 | ||
|
|
ebb3688add | ||
|
|
5da9bdc614 | ||
|
|
af9a7a2ed4 | ||
|
|
fcfb1aeb87 | ||
|
|
e39d2eb113 | ||
|
|
7090bb518b | ||
|
|
0b1857771e | ||
|
|
938eff8482 | ||
|
|
b99e94cecf | ||
|
|
1f97052954 | ||
|
|
c76aa1d1c2 | ||
|
|
cdd41ad651 | ||
|
|
3c61bf9cc4 | ||
|
|
8a0bbb374c | ||
|
|
4e54a3c48e | ||
|
|
bfe7f49033 | ||
|
|
a6f0d8f69a | ||
|
|
95c09315f5 | ||
|
|
e38772ada0 | ||
|
|
e125bcf451 | ||
|
|
4491d3cc73 | ||
|
|
2b32252aff | ||
|
|
29c9f70a1c | ||
|
|
2c1ef4c8c1 | ||
|
|
7b1901253c | ||
|
|
dc1dd2e243 | ||
|
|
e3bc7cf894 | ||
|
|
e5cc9063e8 | ||
|
|
88edaceee0 | ||
|
|
bce64a1ead | ||
|
|
c8c07ed700 | ||
|
|
0258fc24f3 | ||
|
|
274a7a3c73 | ||
|
|
f90f7565fb | ||
|
|
208fa02ec0 | ||
|
|
2c89573441 | ||
|
|
0a300d1802 | ||
|
|
12c6878cbe | ||
|
|
4c4490a9b7 | ||
|
|
578475a403 | ||
|
|
3e2142c3cf | ||
|
|
e948bf1591 | ||
|
|
06f10398da | ||
|
|
55b8918ea1 | ||
|
|
067b814daa | ||
|
|
c992937608 | ||
|
|
cb623b75c1 | ||
|
|
3fe1fc3f67 | ||
|
|
d6c30ae1ef | ||
|
|
e7854bcd8e | ||
|
|
a21bfc909a | ||
|
|
1b709a3e03 | ||
|
|
0142f9467a | ||
|
|
24b40182b5 | ||
|
|
ed94cf57d3 | ||
|
|
5bddada013 | ||
|
|
4afef8215a | ||
|
|
4e1eb33ff5 | ||
|
|
fc7abd5d02 | ||
|
|
469b383781 | ||
|
|
15144bdddd | ||
|
|
d43f367f30 | ||
|
|
304bde3b9e | ||
|
|
e9fca885db |
4
Gemfile
@@ -15,6 +15,8 @@ gem 'spree_auth_devise', :github => 'spree/spree_auth_devise', :branch => '1-3-s
|
||||
gem 'spree_paypal_express', :github => "openfoodfoundation/better_spree_paypal_express", :branch => "1-3-stable"
|
||||
#gem 'spree_paypal_express', :github => "spree-contrib/better_spree_paypal_express", :branch => "1-3-stable"
|
||||
|
||||
gem 'delayed_job_active_record'
|
||||
gem 'daemons'
|
||||
gem 'comfortable_mexican_sofa'
|
||||
|
||||
# Fix bug in simple_form preventing collection_check_boxes usage within form_for block
|
||||
@@ -26,7 +28,7 @@ gem 'angularjs-rails', '1.2.13'
|
||||
gem 'bugsnag'
|
||||
gem 'newrelic_rpm'
|
||||
gem 'haml'
|
||||
gem 'sass', "~> 3.2"
|
||||
gem 'sass', "~> 3.3"
|
||||
gem 'sass-rails', '~> 3.2.3', groups: [:default, :assets]
|
||||
gem 'aws-sdk'
|
||||
gem 'db2fog'
|
||||
|
||||
51
Gemfile.lock
@@ -23,7 +23,7 @@ GIT
|
||||
|
||||
GIT
|
||||
remote: git://github.com/openfoodfoundation/spree.git
|
||||
revision: 4e0075b07acb56864aca89eee3d9670136176c23
|
||||
revision: afcc23e489eb604a3e2651598a7c8364e2acc7b3
|
||||
branch: 1-3-stable
|
||||
specs:
|
||||
spree (1.3.6.beta)
|
||||
@@ -123,7 +123,7 @@ GEM
|
||||
active_link_to (1.0.0)
|
||||
active_model_serializers (0.8.1)
|
||||
activemodel (>= 3.0)
|
||||
activemerchant (1.46.0)
|
||||
activemerchant (1.48.0)
|
||||
activesupport (>= 3.2.14, < 5.0.0)
|
||||
builder (>= 2.1.2, < 4.0.0)
|
||||
i18n (>= 0.6.9)
|
||||
@@ -177,11 +177,11 @@ GEM
|
||||
celluloid (0.15.2)
|
||||
timers (~> 1.1.0)
|
||||
chronic (0.10.2)
|
||||
chunky_png (1.3.0)
|
||||
chunky_png (1.3.4)
|
||||
climate_control (0.0.3)
|
||||
activesupport (>= 3.0)
|
||||
cliver (0.3.2)
|
||||
cocaine (0.5.5)
|
||||
cocaine (0.5.7)
|
||||
climate_control (>= 0.0.3, < 1.0)
|
||||
coderay (1.0.9)
|
||||
coffee-rails (3.2.2)
|
||||
@@ -191,22 +191,33 @@ GEM
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.3.3)
|
||||
colorize (0.7.5)
|
||||
colorize (0.7.7)
|
||||
columnize (0.3.6)
|
||||
comfortable_mexican_sofa (1.6.24)
|
||||
active_link_to (~> 1.0.0)
|
||||
paperclip (>= 2.3.0)
|
||||
rails (>= 3.0.0)
|
||||
compass (0.12.4)
|
||||
compass (1.0.3)
|
||||
chunky_png (~> 1.2)
|
||||
fssm (>= 0.2.7)
|
||||
sass (~> 3.2.17)
|
||||
compass-rails (1.0.3)
|
||||
compass (>= 0.12.2, < 0.14)
|
||||
compass-core (~> 1.0.2)
|
||||
compass-import-once (~> 1.0.5)
|
||||
rb-fsevent (>= 0.9.3)
|
||||
rb-inotify (>= 0.9)
|
||||
sass (>= 3.3.13, < 3.5)
|
||||
compass-core (1.0.3)
|
||||
multi_json (~> 1.0)
|
||||
sass (>= 3.3.0, < 3.5)
|
||||
compass-import-once (1.0.5)
|
||||
sass (>= 3.2, < 3.5)
|
||||
compass-rails (2.0.4)
|
||||
compass (~> 1.0.0)
|
||||
sass-rails (<= 5.0.1)
|
||||
sprockets (< 2.13)
|
||||
crack (0.4.1)
|
||||
safe_yaml (~> 0.9.0)
|
||||
css_parser (1.3.5)
|
||||
addressable
|
||||
daemons (1.2.2)
|
||||
dalli (2.7.2)
|
||||
database_cleaner (0.7.1)
|
||||
db2fog (0.8.0)
|
||||
@@ -219,6 +230,11 @@ GEM
|
||||
debugger-ruby_core_source (~> 1.2.3)
|
||||
debugger-linecache (1.2.0)
|
||||
debugger-ruby_core_source (1.2.3)
|
||||
delayed_job (4.0.4)
|
||||
activesupport (>= 3.0, < 4.2)
|
||||
delayed_job_active_record (4.0.2)
|
||||
activerecord (>= 3.0, < 4.2)
|
||||
delayed_job (>= 3.0, < 4.1)
|
||||
devise (2.2.8)
|
||||
bcrypt-ruby (~> 3.0)
|
||||
orm_adapter (~> 0.1)
|
||||
@@ -261,10 +277,9 @@ GEM
|
||||
foundation-icons-sass-rails (3.0.0)
|
||||
railties (>= 3.1.1)
|
||||
sass-rails (>= 3.1.1)
|
||||
foundation-rails (5.2.2.0)
|
||||
foundation-rails (5.5.0.0)
|
||||
railties (>= 3.1.0)
|
||||
sass (>= 3.2.0)
|
||||
fssm (0.2.10)
|
||||
sass (>= 3.2.0, < 3.4)
|
||||
fuubar (1.3.3)
|
||||
rspec (>= 2.14.0, < 3.1.0)
|
||||
ruby-progressbar (~> 1.4)
|
||||
@@ -332,7 +347,7 @@ GEM
|
||||
railties (>= 3.1)
|
||||
money (5.1.1)
|
||||
i18n (~> 0.6.0)
|
||||
multi_json (1.10.1)
|
||||
multi_json (1.11.0)
|
||||
multi_xml (0.5.5)
|
||||
net-scp (1.1.2)
|
||||
net-ssh (>= 2.6.5)
|
||||
@@ -442,7 +457,7 @@ GEM
|
||||
ruby-hmac (0.4.0)
|
||||
ruby-progressbar (1.7.1)
|
||||
safe_yaml (0.9.5)
|
||||
sass (3.2.19)
|
||||
sass (3.3.14)
|
||||
sass-rails (3.2.6)
|
||||
railties (~> 3.2.0)
|
||||
sass (>= 3.1.10)
|
||||
@@ -481,7 +496,7 @@ GEM
|
||||
sprockets (>= 2.0.0)
|
||||
turn (0.8.3)
|
||||
ansi
|
||||
tzinfo (0.3.43)
|
||||
tzinfo (0.3.44)
|
||||
uglifier (1.2.4)
|
||||
execjs (>= 0.3.0)
|
||||
multi_json (>= 1.0.2)
|
||||
@@ -529,11 +544,13 @@ DEPENDENCIES
|
||||
comfortable_mexican_sofa
|
||||
compass-rails
|
||||
custom_error_message!
|
||||
daemons
|
||||
dalli
|
||||
database_cleaner (= 0.7.1)
|
||||
db2fog
|
||||
debugger-linecache
|
||||
deface!
|
||||
delayed_job_active_record
|
||||
factory_girl_rails
|
||||
figaro
|
||||
foreigner
|
||||
@@ -569,7 +586,7 @@ DEPENDENCIES
|
||||
representative_view
|
||||
roadie-rails (~> 1.0.3)
|
||||
rspec-rails
|
||||
sass (~> 3.2)
|
||||
sass (~> 3.3)
|
||||
sass-rails (~> 3.2.3)
|
||||
shoulda-matchers
|
||||
simple_form!
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
[](http://ci.openfood.com.au:8080/job/openfoodweb%20-%20tests/)
|
||||
[](https://codeclimate.com/github/openfoodfoundation/openfoodnetwork)
|
||||
|
||||
# Open Food Network
|
||||
|
||||
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.9 KiB |
@@ -1,6 +1,6 @@
|
||||
angular.module("ofn.admin").controller "AdminOrderMgmtCtrl", [
|
||||
"$scope", "$http", "dataFetcher", "blankOption", "pendingChanges", "VariantUnitManager", "OptionValueNamer", "SpreeApiKey"
|
||||
($scope, $http, dataFetcher, blankOption, pendingChanges, VariantUnitManager, OptionValueNamer, SpreeApiKey) ->
|
||||
"$scope", "$http", "$filter", "dataFetcher", "blankOption", "pendingChanges", "VariantUnitManager", "OptionValueNamer", "SpreeApiKey"
|
||||
($scope, $http, $filter, dataFetcher, blankOption, pendingChanges, VariantUnitManager, OptionValueNamer, SpreeApiKey) ->
|
||||
$scope.loading = true
|
||||
|
||||
$scope.initialiseVariables = ->
|
||||
@@ -42,13 +42,15 @@ angular.module("ofn.admin").controller "AdminOrderMgmtCtrl", [
|
||||
if $scope.spree_api_key_ok
|
||||
$http.defaults.headers.common["X-Spree-Token"] = SpreeApiKey
|
||||
dataFetcher("/api/enterprises/accessible?template=bulk_index&q[is_primary_producer_eq]=true").then (data) ->
|
||||
$scope.suppliers = data
|
||||
$scope.suppliers = $filter('orderBy')(data, 'name')
|
||||
$scope.suppliers.unshift blankOption()
|
||||
dataFetcher("/api/enterprises/accessible?template=bulk_index&q[is_distributor_eq]=true").then (data) ->
|
||||
$scope.distributors = data
|
||||
dataFetcher("/api/enterprises/accessible?template=bulk_index&q[sells_in][]=own&q[sells_in][]=any").then (data) ->
|
||||
$scope.distributors = $filter('orderBy')(data, 'name')
|
||||
$scope.distributors.unshift blankOption()
|
||||
ocFetcher = dataFetcher("/api/order_cycles/accessible").then (data) ->
|
||||
ocFetcher = dataFetcher("/api/order_cycles/accessible?as=distributor&q[orders_close_at_gt]=#{formatDate(daysFromToday(-90))}").then (data) ->
|
||||
$scope.orderCycles = data
|
||||
$scope.orderCyclesByID = []
|
||||
$scope.orderCyclesByID[oc.id] = oc for oc in $scope.orderCycles
|
||||
$scope.orderCycles.unshift blankOption()
|
||||
$scope.fetchOrders()
|
||||
ocFetcher.then ->
|
||||
@@ -60,7 +62,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[completed_at_not_null]=true;q[completed_at_gt]=#{$scope.startDate};q[completed_at_lt]=#{$scope.endDate}").then (data) ->
|
||||
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) ->
|
||||
$scope.resetOrders data
|
||||
$scope.loading = false
|
||||
|
||||
@@ -162,6 +164,11 @@ angular.module("ofn.admin").controller "AdminOrderMgmtCtrl", [
|
||||
$scope.supplierFilter = $scope.suppliers[0].id
|
||||
$scope.orderCycleFilter = $scope.orderCycles[0].id
|
||||
$scope.quickSearch = ""
|
||||
|
||||
$scope.$watch "orderCycleFilter", (newVal, oldVal) ->
|
||||
unless $scope.orderCycleFilter == "0" || angular.equals(newVal, oldVal)
|
||||
$scope.startDate = $scope.orderCyclesByID[$scope.orderCycleFilter].first_order
|
||||
$scope.endDate = $scope.orderCyclesByID[$scope.orderCycleFilter].last_order
|
||||
]
|
||||
|
||||
daysFromToday = (days) ->
|
||||
|
||||
@@ -4,13 +4,15 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
$scope.StatusMessage = StatusMessage
|
||||
|
||||
$scope.columns =
|
||||
producer: {name: "Producer", visible: true}
|
||||
name: {name: "Name", visible: true}
|
||||
unit: {name: "Unit", visible: true}
|
||||
price: {name: "Price", visible: true}
|
||||
on_hand: {name: "On Hand", visible: true}
|
||||
category: {name: "Category", visible: false}
|
||||
available_on: {name: "Available On", visible: false}
|
||||
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}
|
||||
category: {name: "Category", visible: false}
|
||||
inherits_properties: {name: "Inherits Properties?", visible: false}
|
||||
available_on: {name: "Available On", visible: false}
|
||||
|
||||
$scope.variant_unit_options = VariantUnitManager.variantUnitOptions()
|
||||
|
||||
@@ -285,6 +287,9 @@ filterSubmitProducts = (productsToFilter) ->
|
||||
filteredMaster ?= { id: product.master.id }
|
||||
filteredMaster.display_as = product.master.display_as
|
||||
|
||||
if product.hasOwnProperty("sku")
|
||||
filteredProduct.sku = product.sku
|
||||
hasUpdatableProperty = true
|
||||
if product.hasOwnProperty("name")
|
||||
filteredProduct.name = product.name
|
||||
hasUpdatableProperty = true
|
||||
@@ -307,6 +312,9 @@ filterSubmitProducts = (productsToFilter) ->
|
||||
if product.hasOwnProperty("category_id")
|
||||
filteredProduct.primary_taxon_id = product.category_id
|
||||
hasUpdatableProperty = true
|
||||
if product.hasOwnProperty("inherits_properties")
|
||||
filteredProduct.inherits_properties = product.inherits_properties
|
||||
hasUpdatableProperty = true
|
||||
if product.hasOwnProperty("available_on")
|
||||
filteredProduct.available_on = product.available_on
|
||||
hasUpdatableProperty = true
|
||||
|
||||
@@ -1 +1 @@
|
||||
angular.module("admin.enterprise_groups", ["admin.side_menu", "admin.users"])
|
||||
angular.module("admin.enterprise_groups", ["admin.side_menu", "admin.users", "textAngular"])
|
||||
|
||||
@@ -13,6 +13,7 @@ angular.module("admin.enterprises")
|
||||
{ name: 'About', icon_class: "icon-pencil" }
|
||||
{ name: 'Business Details', icon_class: "icon-briefcase" }
|
||||
{ name: 'Images', icon_class: "icon-picture" }
|
||||
{ name: "Properties", icon_class: "icon-tags", show: "showProperties()" }
|
||||
{ name: "Shipping Methods", icon_class: "icon-truck", show: "showShippingMethods()" }
|
||||
{ name: "Payment Methods", icon_class: "icon-money", show: "showPaymentMethods()" }
|
||||
{ name: "Enterprise Fees", icon_class: "icon-tasks", show: "showEnterpriseFees()" }
|
||||
@@ -28,6 +29,9 @@ angular.module("admin.enterprises")
|
||||
else
|
||||
true
|
||||
|
||||
$scope.showProperties = ->
|
||||
!!$scope.Enterprise.is_primary_producer
|
||||
|
||||
$scope.showShippingMethods = ->
|
||||
enterprisePermissions.can_manage_shipping_methods && $scope.Enterprise.sells != "none"
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
angular.module('admin.order_cycles', ['ngResource'])
|
||||
.controller('AdminCreateOrderCycleCtrl', ['$scope', 'OrderCycle', 'Enterprise', 'EnterpriseFee', 'ocInstance', ($scope, OrderCycle, Enterprise, EnterpriseFee, ocInstance) ->
|
||||
$scope.enterprises = Enterprise.index()
|
||||
.controller('AdminCreateOrderCycleCtrl', ['$scope', '$filter', 'OrderCycle', 'Enterprise', 'EnterpriseFee', 'ocInstance', ($scope, $filter, OrderCycle, Enterprise, EnterpriseFee, ocInstance) ->
|
||||
$scope.enterprises = Enterprise.index(coordinator_id: ocInstance.coordinator_id)
|
||||
$scope.supplied_products = Enterprise.supplied_products
|
||||
$scope.enterprise_fees = EnterpriseFee.index()
|
||||
$scope.enterprise_fees = EnterpriseFee.index(coordinator_id: ocInstance.coordinator_id)
|
||||
|
||||
$scope.order_cycle = OrderCycle.order_cycle
|
||||
$scope.order_cycle.coordinator_id = ocInstance.coordinator_id
|
||||
$scope.order_cycle = OrderCycle.new({ coordinator_id: ocInstance.coordinator_id})
|
||||
|
||||
$scope.loaded = ->
|
||||
Enterprise.loaded && EnterpriseFee.loaded
|
||||
@@ -28,14 +27,14 @@ angular.module('admin.order_cycles', ['ngResource'])
|
||||
$scope.variantSuppliedToOrderCycle = (variant) ->
|
||||
OrderCycle.variantSuppliedToOrderCycle(variant)
|
||||
|
||||
$scope.incomingExchangesVariants = ->
|
||||
OrderCycle.incomingExchangesVariants()
|
||||
$scope.incomingExchangeVariantsFor = (enterprise_id) ->
|
||||
$filter('filterExchangeVariants')(OrderCycle.incomingExchangesVariants(), $scope.order_cycle.visible_variants_for_outgoing_exchanges[enterprise_id])
|
||||
|
||||
$scope.exchangeDirection = (exchange) ->
|
||||
OrderCycle.exchangeDirection(exchange)
|
||||
|
||||
$scope.participatingEnterprises = ->
|
||||
$scope.enterprises[id] for id in OrderCycle.participatingEnterpriseIds()
|
||||
$scope.enterprisesWithFees = ->
|
||||
$scope.enterprises[id] for id in OrderCycle.participatingEnterpriseIds() when $scope.enterpriseFeesForEnterprise(id).length > 0
|
||||
|
||||
$scope.toggleProducts = ($event, exchange) ->
|
||||
$event.preventDefault()
|
||||
@@ -80,12 +79,12 @@ angular.module('admin.order_cycles', ['ngResource'])
|
||||
OrderCycle.create()
|
||||
])
|
||||
|
||||
.controller('AdminEditOrderCycleCtrl', ['$scope', '$location', 'OrderCycle', 'Enterprise', 'EnterpriseFee', ($scope, $location, OrderCycle, Enterprise, EnterpriseFee) ->
|
||||
$scope.enterprises = Enterprise.index()
|
||||
$scope.supplied_products = Enterprise.supplied_products
|
||||
$scope.enterprise_fees = EnterpriseFee.index()
|
||||
|
||||
.controller('AdminEditOrderCycleCtrl', ['$scope', '$filter', '$location', 'OrderCycle', 'Enterprise', 'EnterpriseFee', ($scope, $filter, $location, OrderCycle, Enterprise, EnterpriseFee) ->
|
||||
order_cycle_id = $location.absUrl().match(/\/admin\/order_cycles\/(\d+)/)[1]
|
||||
$scope.enterprises = Enterprise.index(order_cycle_id: order_cycle_id)
|
||||
$scope.supplied_products = Enterprise.supplied_products
|
||||
$scope.enterprise_fees = EnterpriseFee.index(order_cycle_id: order_cycle_id)
|
||||
|
||||
$scope.order_cycle = OrderCycle.load(order_cycle_id)
|
||||
|
||||
$scope.loaded = ->
|
||||
@@ -109,14 +108,14 @@ angular.module('admin.order_cycles', ['ngResource'])
|
||||
$scope.variantSuppliedToOrderCycle = (variant) ->
|
||||
OrderCycle.variantSuppliedToOrderCycle(variant)
|
||||
|
||||
$scope.incomingExchangesVariants = ->
|
||||
OrderCycle.incomingExchangesVariants()
|
||||
$scope.incomingExchangeVariantsFor = (enterprise_id) ->
|
||||
$filter('filterExchangeVariants')(OrderCycle.incomingExchangesVariants(), $scope.order_cycle.visible_variants_for_outgoing_exchanges[enterprise_id])
|
||||
|
||||
$scope.exchangeDirection = (exchange) ->
|
||||
OrderCycle.exchangeDirection(exchange)
|
||||
|
||||
$scope.participatingEnterprises = ->
|
||||
$scope.enterprises[id] for id in OrderCycle.participatingEnterpriseIds()
|
||||
$scope.enterprisesWithFees = ->
|
||||
$scope.enterprises[id] for id in OrderCycle.participatingEnterpriseIds() when $scope.enterpriseFeesForEnterprise(id).length > 0
|
||||
|
||||
$scope.toggleProducts = ($event, exchange) ->
|
||||
$event.preventDefault()
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
angular.module('admin.order_cycles').controller "AdminSimpleCreateOrderCycleCtrl", ($scope, OrderCycle, Enterprise, EnterpriseFee) ->
|
||||
$scope.enterprises = Enterprise.index (enterprises) =>
|
||||
$scope.init(enterprises)
|
||||
$scope.enterprise_fees = EnterpriseFee.index()
|
||||
$scope.order_cycle = OrderCycle.order_cycle
|
||||
angular.module('admin.order_cycles').controller "AdminSimpleCreateOrderCycleCtrl", ($scope, OrderCycle, Enterprise, EnterpriseFee, ocInstance) ->
|
||||
$scope.order_cycle = OrderCycle.new {coordinator_id: ocInstance.coordinator_id}, =>
|
||||
# TODO: make this a get method, which only fetches one enterprise
|
||||
$scope.enterprises = Enterprise.index {coordinator_id: ocInstance.coordinator_id}, (enterprises) =>
|
||||
$scope.init(enterprises)
|
||||
$scope.enterprise_fees = EnterpriseFee.index(coordinator_id: ocInstance.coordinator_id)
|
||||
|
||||
$scope.init = (enterprises) ->
|
||||
enterprise = enterprises[Object.keys(enterprises)[0]]
|
||||
|
||||
@@ -2,8 +2,8 @@ angular.module('admin.order_cycles').controller "AdminSimpleEditOrderCycleCtrl",
|
||||
$scope.orderCycleId = ->
|
||||
$location.absUrl().match(/\/admin\/order_cycles\/(\d+)/)[1]
|
||||
|
||||
$scope.enterprises = Enterprise.index()
|
||||
$scope.enterprise_fees = EnterpriseFee.index()
|
||||
$scope.enterprises = Enterprise.index(order_cycle_id: $scope.orderCycleId())
|
||||
$scope.enterprise_fees = EnterpriseFee.index(order_cycle_id: $scope.orderCycleId())
|
||||
$scope.order_cycle = OrderCycle.load $scope.orderCycleId(), (order_cycle) =>
|
||||
$scope.init()
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
angular.module("admin.order_cycles").filter "filterExchangeVariants", ->
|
||||
return (variants, rules) ->
|
||||
if variants? && rules?
|
||||
return (variant for variant in variants when variant in rules)
|
||||
else
|
||||
return []
|
||||
@@ -0,0 +1,4 @@
|
||||
angular.module("admin.order_cycles").filter "visibleProductVariants", ->
|
||||
return (product, exchange, rules) ->
|
||||
variants = product.variants.concat( [{ "id": product.master_id}] )
|
||||
return (variant for variant in variants when variant.id in rules[exchange.enterprise_id])
|
||||
@@ -0,0 +1,3 @@
|
||||
angular.module("admin.order_cycles").filter "visibleProducts", ($filter) ->
|
||||
return (products, exchange, rules) ->
|
||||
return (product for product in products when $filter('visibleProductVariants')(product, exchange, rules).length > 0)
|
||||
@@ -1,24 +1,28 @@
|
||||
angular.module('admin.order_cycles').factory('Enterprise', ($resource) ->
|
||||
Enterprise = $resource('/admin/enterprises/for_order_cycle/:enterprise_id.json', {}, {'index': {method: 'GET', isArray: true}})
|
||||
|
||||
Enterprise = $resource('/admin/enterprises/for_order_cycle/:enterprise_id.json', {}, {
|
||||
'index':
|
||||
method: 'GET'
|
||||
isArray: true
|
||||
params:
|
||||
order_cycle_id: '@order_cycle_id'
|
||||
coordinator_id: '@coordinator_id'
|
||||
})
|
||||
{
|
||||
Enterprise: Enterprise
|
||||
enterprises: {}
|
||||
supplied_products: []
|
||||
loaded: false
|
||||
|
||||
index: (callback=null) ->
|
||||
service = this
|
||||
|
||||
Enterprise.index (data) ->
|
||||
index: (params={}, callback=null) ->
|
||||
Enterprise.index params, (data) =>
|
||||
for enterprise in data
|
||||
service.enterprises[enterprise.id] = enterprise
|
||||
@enterprises[enterprise.id] = enterprise
|
||||
|
||||
for product in enterprise.supplied_products
|
||||
service.supplied_products.push(product)
|
||||
@supplied_products.push(product)
|
||||
|
||||
service.loaded = true
|
||||
(callback || angular.noop)(service.enterprises)
|
||||
@loaded = true
|
||||
(callback || angular.noop)(@enterprises)
|
||||
|
||||
this.enterprises
|
||||
|
||||
@@ -40,4 +44,4 @@ angular.module('admin.order_cycles').factory('Enterprise', ($resource) ->
|
||||
numVariants += if product.variants.length == 0 then 1 else product.variants.length
|
||||
|
||||
numVariants
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
angular.module('admin.order_cycles').factory('EnterpriseFee', ($resource) ->
|
||||
EnterpriseFee = $resource('/admin/enterprise_fees/:enterprise_fee_id.json', {}, {'index': {method: 'GET', isArray: true}})
|
||||
EnterpriseFee = $resource('/admin/enterprise_fees/for_order_cycle/:enterprise_fee_id.json', {}, {
|
||||
'index':
|
||||
method: 'GET'
|
||||
isArray: true
|
||||
params:
|
||||
order_cycle_id: '@order_cycle_id'
|
||||
coordinator_id: '@coordinator_id'
|
||||
})
|
||||
|
||||
{
|
||||
EnterpriseFee: EnterpriseFee
|
||||
enterprise_fees: {}
|
||||
loaded: false
|
||||
|
||||
index: ->
|
||||
service = this
|
||||
EnterpriseFee.index (data) ->
|
||||
service.enterprise_fees = data
|
||||
service.loaded = true
|
||||
index: (params={}) ->
|
||||
EnterpriseFee.index params, (data) =>
|
||||
@enterprise_fees = data
|
||||
@loaded = true
|
||||
|
||||
forEnterprise: (enterprise_id) ->
|
||||
enterprise_fee for enterprise_fee in this.enterprise_fees when enterprise_fee.enterprise_id == enterprise_id
|
||||
enterprise_fee for enterprise_fee in @enterprise_fees when enterprise_fee.enterprise_id == enterprise_id
|
||||
})
|
||||
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
angular.module('admin.order_cycles').factory('OrderCycle', ($resource, $window) ->
|
||||
OrderCycle = $resource '/admin/order_cycles/:order_cycle_id.json', {}, {
|
||||
OrderCycle = $resource '/admin/order_cycles/:action_name/:order_cycle_id.json', {}, {
|
||||
'index': { method: 'GET', isArray: true}
|
||||
'new' : { method: 'GET', params: { action_name: "new" } }
|
||||
'create': { method: 'POST'}
|
||||
'update': { method: 'PUT'}}
|
||||
|
||||
{
|
||||
order_cycle:
|
||||
incoming_exchanges: []
|
||||
outgoing_exchanges: []
|
||||
coordinator_fees: []
|
||||
order_cycle: {}
|
||||
|
||||
loaded: false
|
||||
|
||||
@@ -24,7 +22,9 @@ angular.module('admin.order_cycles').factory('OrderCycle', ($resource, $window)
|
||||
exchange.showProducts = !exchange.showProducts
|
||||
|
||||
setExchangeVariants: (exchange, variants, selected) ->
|
||||
exchange.variants[variant] = selected for variant in variants
|
||||
direction = if exchange.incoming then "incoming" else "outgoing"
|
||||
editable = @order_cycle["editable_variants_for_#{direction}_exchanges"][exchange.enterprise_id] || []
|
||||
exchange.variants[variant] = selected for variant in variants when variant in editable
|
||||
|
||||
addSupplier: (new_supplier_id) ->
|
||||
this.order_cycle.incoming_exchanges.push({enterprise_id: new_supplier_id, incoming: true, active: true, variants: {}, enterprise_fees: []})
|
||||
@@ -84,6 +84,20 @@ angular.module('admin.order_cycles').factory('OrderCycle', ($resource, $window)
|
||||
for exchange in this.order_cycle.outgoing_exchanges
|
||||
exchange.variants[variant_id] = false
|
||||
|
||||
new: (params, callback=null) ->
|
||||
OrderCycle.new params, (oc) =>
|
||||
delete oc.$promise
|
||||
delete oc.$resolved
|
||||
angular.extend(@order_cycle, oc)
|
||||
@order_cycle.incoming_exchanges = []
|
||||
@order_cycle.outgoing_exchanges = []
|
||||
delete(@order_cycle.exchanges)
|
||||
@loaded = true
|
||||
|
||||
(callback || angular.noop)(@order_cycle)
|
||||
|
||||
@order_cycle
|
||||
|
||||
load: (order_cycle_id, callback=null) ->
|
||||
service = this
|
||||
OrderCycle.get {order_cycle_id: order_cycle_id}, (oc) ->
|
||||
@@ -127,6 +141,7 @@ angular.module('admin.order_cycles').factory('OrderCycle', ($resource, $window)
|
||||
|
||||
dataForSubmit: ->
|
||||
data = this.deepCopy()
|
||||
data = this.stripNonSubmittableAttributes(data)
|
||||
data = this.removeInactiveExchanges(data)
|
||||
data = this.translateCoordinatorFees(data)
|
||||
data = this.translateExchangeFees(data)
|
||||
@@ -147,6 +162,14 @@ angular.module('admin.order_cycles').factory('OrderCycle', ($resource, $window)
|
||||
|
||||
data
|
||||
|
||||
stripNonSubmittableAttributes: (order_cycle) ->
|
||||
delete order_cycle.id
|
||||
delete order_cycle.viewing_as_coordinator
|
||||
delete order_cycle.editable_variants_for_incoming_exchanges
|
||||
delete order_cycle.editable_variants_for_outgoing_exchanges
|
||||
delete order_cycle.visible_variants_for_outgoing_exchanges
|
||||
order_cycle
|
||||
|
||||
removeInactiveExchanges: (order_cycle) ->
|
||||
order_cycle.incoming_exchanges =
|
||||
(exchange for exchange in order_cycle.incoming_exchanges when exchange.active)
|
||||
|
||||
@@ -36,4 +36,4 @@
|
||||
$ ->
|
||||
# Hacky fix for issue - http://foundation.zurb.com/forum/posts/2112-foundation-5100-syntax-error-in-js
|
||||
Foundation.set_namespace ""
|
||||
#$(document).foundation()
|
||||
$(document).foundation()
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
Darkswarm.controller "GroupEnterprisesCtrl", ($scope, Enterprises, Search, FilterSelectorsService) ->
|
||||
$scope.Enterprises = Enterprises
|
||||
Darkswarm.controller "GroupEnterprisesCtrl", ($scope, Search, FilterSelectorsService) ->
|
||||
$scope.totalActive = FilterSelectorsService.totalActive
|
||||
$scope.clearAll = FilterSelectorsService.clearAll
|
||||
$scope.filterText = FilterSelectorsService.filterText
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
Darkswarm.controller "GroupPageCtrl", ($scope, group_enterprises, Enterprises, MapConfiguration, OfnMap) ->
|
||||
$scope.Enterprises = Enterprises
|
||||
|
||||
group_enterprises_ids = group_enterprises.map (enterprise) =>
|
||||
enterprise.id
|
||||
is_in_group = (enterprise) ->
|
||||
group_enterprises_ids.indexOf(enterprise.id) != -1
|
||||
|
||||
$scope.group_producers = Enterprises.producers.filter is_in_group
|
||||
$scope.group_hubs = Enterprises.hubs.filter is_in_group
|
||||
|
||||
$scope.map = angular.copy MapConfiguration.options
|
||||
$scope.mapMarkers = OfnMap.enterprise_markers group_enterprises
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Darkswarm.controller "ProductsCtrl", ($scope, $rootScope, Products, OrderCycle, FilterSelectorsService, Cart) ->
|
||||
Darkswarm.controller "ProductsCtrl", ($scope, $rootScope, Products, OrderCycle, FilterSelectorsService, Cart, Taxons, Properties) ->
|
||||
$scope.Products = Products
|
||||
$scope.Cart = Cart
|
||||
$scope.totalActive = FilterSelectorsService.totalActive
|
||||
@@ -9,6 +9,9 @@ Darkswarm.controller "ProductsCtrl", ($scope, $rootScope, Products, OrderCycle,
|
||||
$scope.limit = 3
|
||||
$scope.order_cycle = OrderCycle.order_cycle
|
||||
|
||||
$scope.$watch "Products.loading", (newValue, oldValue) ->
|
||||
$scope.$broadcast("loadFilterSelectors") if !newValue
|
||||
|
||||
$scope.incrementLimit = ->
|
||||
if $scope.limit < Products.products.length
|
||||
$scope.limit = $scope.limit + 1
|
||||
@@ -17,3 +20,17 @@ Darkswarm.controller "ProductsCtrl", ($scope, $rootScope, Products, OrderCycle,
|
||||
code = e.keyCode || e.which
|
||||
if code == 13
|
||||
e.preventDefault()
|
||||
|
||||
$scope.appliedTaxonsList = ->
|
||||
$scope.activeTaxons.map( (taxon_id) ->
|
||||
Taxons.taxons_by_id[taxon_id].name
|
||||
).join(" & ") if $scope.activeTaxons?
|
||||
|
||||
$scope.appliedPropertiesList = ->
|
||||
$scope.activeProperties.map( (property_id) ->
|
||||
Properties.properties_by_id[property_id].name
|
||||
).join(" & ") if $scope.activeProperties?
|
||||
|
||||
$scope.clearAll = ->
|
||||
$scope.query = ""
|
||||
FilterSelectorsService.clearAll()
|
||||
|
||||
@@ -3,7 +3,7 @@ Darkswarm.controller "RegistrationCtrl", ($scope, RegistrationService, Enterpris
|
||||
$scope.enterprise = EnterpriseRegistrationService.enterprise
|
||||
$scope.select = RegistrationService.select
|
||||
|
||||
$scope.steps = ['details','contact','type','about','images','social']
|
||||
$scope.steps = ['details', 'contact', 'type', 'about', 'images', 'social']
|
||||
|
||||
$scope.countries = availableCountries
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ Darkswarm.directive "activeSelector", ->
|
||||
replace: true
|
||||
templateUrl: 'active_selector.html'
|
||||
link: (scope, elem, attr)->
|
||||
scope.selector.emit = scope.emit
|
||||
elem.bind "click", ->
|
||||
scope.$apply ->
|
||||
scope.selector.active = !scope.selector.active
|
||||
# This function is a convention, e.g. a callback on the scope applied when active changes
|
||||
scope.emit() if scope.emit
|
||||
|
||||
unless scope.readOnly && scope.readOnly()
|
||||
scope.selector.emit = scope.emit
|
||||
elem.bind "click", ->
|
||||
scope.$apply ->
|
||||
scope.selector.active = !scope.selector.active
|
||||
# This function is a convention, e.g. a callback on the scope applied when active changes
|
||||
scope.emit() if scope.emit
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
Darkswarm.directive "filterSelector", (FilterSelectorsService)->
|
||||
# Automatically builds activeSelectors for taxons
|
||||
# Lots of magic here
|
||||
restrict: 'E'
|
||||
replace: true
|
||||
scope:
|
||||
objects: "&"
|
||||
activeSelectors: "=?"
|
||||
allSelectors: "=?" # Optional
|
||||
templateUrl: "filter_selector.html"
|
||||
|
||||
link: (scope, elem, attr)->
|
||||
selectors_by_id = {}
|
||||
selectors = null # To get scoping/closure right
|
||||
|
||||
scope.readOnly = ->
|
||||
!attr.activeSelectors?
|
||||
|
||||
scope.emit = ->
|
||||
scope.activeSelectors = selectors.filter (selector)->
|
||||
selector.active
|
||||
.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?
|
||||
|
||||
# Build a list of selectors
|
||||
scope.selectors = ->
|
||||
# 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
|
||||
# See http://stackoverflow.com/questions/19306452/how-to-fix-10-digest-iterations-reached-aborting-error-in-angular-1-2-fil
|
||||
selectors = []
|
||||
for id, object of scope.objects()
|
||||
if selector = selectors_by_id[id]
|
||||
selectors.push selector
|
||||
else
|
||||
selector = selectors_by_id[id] = FilterSelectorsService.new
|
||||
object: object
|
||||
selectors.push selector
|
||||
selectors
|
||||
|
||||
scope.ifDefined = (value, if_undefined) ->
|
||||
if angular.isDefined(value)
|
||||
value
|
||||
else
|
||||
if_undefined
|
||||
@@ -0,0 +1,73 @@
|
||||
Darkswarm.directive 'singleLineSelectors', ($timeout, $filter) ->
|
||||
restrict: 'E'
|
||||
templateUrl: "single_line_selectors.html"
|
||||
scope:
|
||||
objects: "&"
|
||||
activeSelectors: "="
|
||||
selectorName: "@activeSelectors"
|
||||
link: (scope,element,attrs) ->
|
||||
scope.fitting = false
|
||||
|
||||
scope.overFlowSelectors = ->
|
||||
return [] unless scope.allSelectors?
|
||||
$filter('filter')(scope.allSelectors, { fits: false })
|
||||
|
||||
scope.selectedOverFlowSelectors = ->
|
||||
$filter('filter')(scope.overFlowSelectors(), { active: true })
|
||||
|
||||
# had to duplicate this to make overflow selectors work
|
||||
scope.emit = ->
|
||||
scope.activeSelectors = scope.allSelectors.filter (selector)->
|
||||
selector.active
|
||||
.map (selector)->
|
||||
selector.object.id
|
||||
|
||||
# From: http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing
|
||||
debouncer = (func, timeout) ->
|
||||
timeoutID = undefined
|
||||
timeout = timeout or 50
|
||||
->
|
||||
subject = this
|
||||
args = arguments
|
||||
clearTimeout timeoutID
|
||||
timeoutID = setTimeout(->
|
||||
func.apply subject, Array::slice.call(args)
|
||||
, timeout)
|
||||
|
||||
loadWidths = ->
|
||||
$(element).find("li").not(".more").each (i) ->
|
||||
scope.allSelectors[i].width = $(this).outerWidth(true)
|
||||
return null # So we don't exit the loop weirdly
|
||||
|
||||
|
||||
fit = ->
|
||||
used = $(element).find("li.more").outerWidth(true)
|
||||
used += selector.width for selector in scope.allSelectors when selector.fits
|
||||
available = $(element).parent(".filter-shopfront").innerWidth() - used
|
||||
if available > 0
|
||||
for selector in scope.allSelectors when !selector.fits
|
||||
available -= selector.width
|
||||
selector.fits = true if available > 0
|
||||
else
|
||||
if scope.allSelectors.length > 0
|
||||
for i in [scope.allSelectors.length-1..0]
|
||||
selector = scope.allSelectors[i]
|
||||
if !selector.fits
|
||||
continue
|
||||
else
|
||||
if available < 0
|
||||
selector.fits = false
|
||||
available += selector.width
|
||||
scope.fitting = false
|
||||
|
||||
scope.$watchCollection "allSelectors", ->
|
||||
if scope.allSelectors?
|
||||
scope.fitting = true
|
||||
selector.fits = true for selector in scope.allSelectors
|
||||
$timeout(loadWidths, 0, true).then ->
|
||||
$timeout fit, 0, true
|
||||
|
||||
$(window).resize debouncer (e) ->
|
||||
scope.fitting = true
|
||||
if scope.allSelectors?
|
||||
$timeout fit, 0, true
|
||||
@@ -1,43 +0,0 @@
|
||||
Darkswarm.directive "taxonSelector", (FilterSelectorsService)->
|
||||
# Automatically builds activeSelectors for taxons
|
||||
# Lots of magic here
|
||||
restrict: 'E'
|
||||
replace: true
|
||||
scope:
|
||||
objects: "&"
|
||||
results: "="
|
||||
templateUrl: "taxon_selector.html"
|
||||
|
||||
link: (scope, elem, attr)->
|
||||
selectors_by_id = {}
|
||||
selectors = null # To get scoping/closure right
|
||||
|
||||
scope.emit = ->
|
||||
scope.results = selectors.filter (selector)->
|
||||
selector.active
|
||||
.map (selector)->
|
||||
selector.taxon.id
|
||||
|
||||
# Build hash of unique taxons, each of which gets an ActiveSelector
|
||||
scope.selectors = ->
|
||||
taxons = {}
|
||||
selectors = []
|
||||
for object in scope.objects()
|
||||
for taxon in object.taxons
|
||||
taxons[taxon.id] = taxon
|
||||
if object.supplied_taxons
|
||||
for taxon in object.supplied_taxons
|
||||
taxons[taxon.id] = taxon
|
||||
|
||||
# Generate a selector for each taxon.
|
||||
# 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
|
||||
# See http://stackoverflow.com/questions/19306452/how-to-fix-10-digest-iterations-reached-aborting-error-in-angular-1-2-fil
|
||||
for id, taxon of taxons
|
||||
if selector = selectors_by_id[id]
|
||||
selectors.push selector
|
||||
else
|
||||
selector = selectors_by_id[id] = FilterSelectorsService.new
|
||||
taxon: taxon
|
||||
selectors.push selector
|
||||
selectors
|
||||
@@ -0,0 +1,16 @@
|
||||
Darkswarm.filter 'properties', ()->
|
||||
# Filter anything that responds to object.properties
|
||||
(objects, ids) ->
|
||||
objects ||= []
|
||||
ids ?= []
|
||||
if ids.length == 0
|
||||
# No properties selected, pass all objects through.
|
||||
objects
|
||||
else
|
||||
objects.filter (obj)->
|
||||
properties = obj.properties
|
||||
# Combine object properties with supplied properties, if they exist.
|
||||
# properties = properties.concat obj.supplied_properties if obj.supplied_properties
|
||||
# Match property array.
|
||||
properties.some (property)->
|
||||
property.id in ids
|
||||
@@ -0,0 +1,7 @@
|
||||
Darkswarm.filter 'propertiesOf', ->
|
||||
(objects)->
|
||||
properties = {}
|
||||
for object in objects
|
||||
for property in object.properties
|
||||
properties[property.id] = property
|
||||
properties
|
||||
@@ -0,0 +1,7 @@
|
||||
Darkswarm.filter 'propertiesWithValuesOf', ->
|
||||
(objects)->
|
||||
propertiesWithValues = {}
|
||||
for object in objects
|
||||
for property in object.properties_with_values
|
||||
propertiesWithValues[property.id] = property
|
||||
propertiesWithValues
|
||||
10
app/assets/javascripts/darkswarm/filters/taxons_of.js.coffee
Normal file
@@ -0,0 +1,10 @@
|
||||
Darkswarm.filter 'taxonsOf', ->
|
||||
(objects)->
|
||||
taxons = {}
|
||||
for object in objects
|
||||
for taxon in object.taxons
|
||||
taxons[taxon.id] = taxon
|
||||
if object.supplied_taxons
|
||||
for taxon in object.supplied_taxons
|
||||
taxons[taxon.id] = taxon
|
||||
taxons
|
||||
@@ -25,7 +25,7 @@ Darkswarm.factory "AuthenticationService", (Navigation, $modal, $location, Redir
|
||||
active: Navigation.active
|
||||
|
||||
close: ->
|
||||
if location.pathname == "/"
|
||||
if location.pathname in ["/", "/checkout"]
|
||||
Navigation.navigate "/"
|
||||
else
|
||||
Loading.message = "Taking you back to the home page"
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
Darkswarm.factory "OfnMap", (Enterprises, EnterpriseModal, visibleFilter)->
|
||||
Darkswarm.factory "OfnMap", (Enterprises, EnterpriseModal, visibleFilter) ->
|
||||
new class OfnMap
|
||||
constructor: ->
|
||||
@enterprises = (@extend(enterprise) for enterprise in visibleFilter(Enterprises.enterprises))
|
||||
@enterprises = @enterprise_markers(Enterprises.enterprises)
|
||||
|
||||
enterprise_markers: (enterprises) ->
|
||||
@extend(enterprise) for enterprise in visibleFilter(enterprises)
|
||||
|
||||
# Adding methods to each enterprise
|
||||
extend: (enterprise)->
|
||||
extend: (enterprise) ->
|
||||
new class MapMarker
|
||||
# We're whitelisting attributes because GMaps tries to crawl
|
||||
# our data, and our data is recursive, so it breaks
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
Darkswarm.factory 'Products', ($resource, Enterprises, Dereferencer, Taxons, Cart, Variants) ->
|
||||
Darkswarm.factory 'Products', ($resource, Enterprises, Dereferencer, Taxons, Properties, Cart, Variants) ->
|
||||
new class Products
|
||||
constructor: ->
|
||||
@update()
|
||||
|
||||
|
||||
# TODO: don't need to scope this into object
|
||||
# Already on object as far as controller scope is concerned
|
||||
products: null
|
||||
loading: true
|
||||
|
||||
update: =>
|
||||
@loading = true
|
||||
@loading = true
|
||||
@products = $resource("/shop/products").query (products)=>
|
||||
@extend() && @dereference()
|
||||
@registerVariants()
|
||||
@registerVariants()
|
||||
@registerVariantsWithCart()
|
||||
@loading = false
|
||||
@
|
||||
|
||||
|
||||
dereference: ->
|
||||
for product in @products
|
||||
product.supplier = Enterprises.enterprises_by_id[product.supplier.id]
|
||||
Dereferencer.dereference product.taxons, Taxons.taxons_by_id
|
||||
|
||||
|
||||
product.properties = angular.copy(product.properties_with_values)
|
||||
Dereferencer.dereference product.properties, Properties.properties_by_id
|
||||
|
||||
# May return different objects! If the variant has already been registered
|
||||
# by another service, we fetch those
|
||||
registerVariants: ->
|
||||
@@ -45,7 +48,7 @@ Darkswarm.factory 'Products', ($resource, Enterprises, Dereferencer, Taxons, Car
|
||||
prices = (v.price for v in product.variants)
|
||||
product.price = Math.min.apply(null, prices)
|
||||
product.hasVariants = product.variants?.length > 0
|
||||
|
||||
|
||||
product.primaryImage = product.images[0]?.small_url if product.images
|
||||
product.primaryImageOrMissing = product.primaryImage || "/assets/noimage/small.png"
|
||||
product.largeImage = product.images[0]?.large_url if product.images
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
Darkswarm.factory "Properties", (properties)->
|
||||
new class Properties
|
||||
# Populate ProductProperties.properties from json in page.
|
||||
properties: properties
|
||||
properties_by_id: {}
|
||||
constructor: ->
|
||||
# Map properties to id/object pairs for lookup.
|
||||
for property in @properties
|
||||
@properties_by_id[property.id] = property
|
||||
@@ -1,2 +1,3 @@
|
||||
%li{"ng-class" => "{active: selector.active}"}
|
||||
%a{"ng-transclude" => true}
|
||||
%li{ ng: { class: "{active: selector.active}" } }
|
||||
%a{ "tooltip" => "{{selector.object.value}}", "tooltip-placement" => "bottom",
|
||||
ng: { transclude: true, class: "{active: selector.active, 'has-tip': selector.object.value}" } }
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
%div{bindonce:true, style: "display: inline-block" }
|
||||
%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"}
|
||||
@@ -1,14 +1,11 @@
|
||||
%div.contact-container{bindonce: true}
|
||||
%div.modal-centered{"bo-if" => "enterprise.email || enterprise.website || enterprise.phone"}
|
||||
%p.modal-header Contact
|
||||
%p{"ng-if" => "enterprise.phone"}
|
||||
{{ enterprise.phone }}
|
||||
%p{"bo-if" => "enterprise.phone", "bo-text" => "enterprise.phone"}
|
||||
|
||||
%p.word-wrap{"ng-if" => "enterprise.email"}
|
||||
%a{"ng-href" => "{{enterprise.email | stripUrl}}", target: "_blank", mailto: true}
|
||||
%span.email
|
||||
{{ enterprise.email | stripUrl }}
|
||||
%a{"bo-href" => "enterprise.email | stripUrl", target: "_blank", mailto: true}
|
||||
%span.email{"bo-bind" => "enterprise.email | stripUrl"}
|
||||
|
||||
%p.word-wrap{"ng-if" => "enterprise.website"}
|
||||
%a{"ng-href" => "http://{{enterprise.website | stripUrl}}", target: "_blank" }
|
||||
{{ enterprise.website | stripUrl }}
|
||||
%a{"bo-href-i" => "http://{{enterprise.website | stripUrl}}", target: "_blank", "bo-bind" => "enterprise.website | stripUrl"}
|
||||
|
||||
@@ -1,9 +1,28 @@
|
||||
.row{bindonce: true}
|
||||
.row{bindonce: true}
|
||||
.small-12.large-8.columns
|
||||
%div{"ng-if" => "enterprise.long_description.length > 0 || enterprise.logo"}
|
||||
/ TODO: Rob add logic for taxons and properties too:
|
||||
/ %div{"ng-if" => "enterprise.long_description.length > 0 || enterprise.logo"}
|
||||
%div
|
||||
%p.modal-header About
|
||||
.about-container
|
||||
%img.enterprise-logo{"bo-src" => "enterprise.logo", "bo-if" => "enterprise.logo"}
|
||||
/ TODO: Rob - add in taxons and properties and property pop-overs
|
||||
|
||||
-# TODO: Add producer taxons and properties here
|
||||
-# %div
|
||||
-# %span.filter-shopfront.taxon-selectors
|
||||
-# %ul.inline-block
|
||||
-# %li
|
||||
-# %a.button.tiny.disabled Grains
|
||||
-# %li
|
||||
-# %a.button.tiny.disabled Dairy
|
||||
-#
|
||||
-# %span.filter-shopfront.property-selectors.pad-top
|
||||
-# %ul.inline-block
|
||||
-# %li
|
||||
-# %a.button.tiny Organic certified
|
||||
-# / TODO: Rob - need popover, use will's directive or this? http://pineconellc.github.io/angular-foundation/
|
||||
-#
|
||||
.about-container.pad-top
|
||||
%img.enterprise-logo{"bo-src" => "enterprise.logo", "bo-if" => "enterprise.logo"}
|
||||
%p.text-small{"ng-bind-html" => "enterprise.long_description"}
|
||||
.small-12.large-4.columns
|
||||
%ng-include{src: "'partials/contact.html'"}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
.highlight{"ng-class" => "{'is_distributor' : enterprise.is_distributor}"}
|
||||
.highlight{bindonce: true, "ng-class" => "{'is_distributor' : enterprise.is_distributor}"}
|
||||
.highlight-top.row
|
||||
.small-12.medium-7.large-8.columns
|
||||
%h3{"ng-if" => "enterprise.is_distributor"}
|
||||
%a{"bo-href" => "enterprise.path", "ofn-empties-cart" => "enterprise", bindonce: true}
|
||||
%a{"bo-href" => "enterprise.path", "ofn-empties-cart" => "enterprise"}
|
||||
%i{"ng-class" => "enterprise.icon_font"}
|
||||
%span {{ enterprise.name }}
|
||||
%span{"bo-text" => "enterprise.name"}
|
||||
%h3{"ng-if" => "!enterprise.is_distributor", "ng-class" => "{'is_producer' : enterprise.is_primary_producer}"}
|
||||
%i{"ng-class" => "enterprise.icon_font"}
|
||||
%span {{ enterprise.name }}
|
||||
%span{"bo-text" => "enterprise.name"}
|
||||
.small-12.medium-5.large-4.columns.text-right.small-only-text-left
|
||||
%p {{ [enterprise.address.city, enterprise.address.state_name] | printArray}}
|
||||
%img.hero-img{"ng-src" => "{{enterprise.promo_image}}"}
|
||||
%p{"bo-bind" => "[enterprise.address.city, enterprise.address.state_name] | printArray"}
|
||||
%img.hero-img{"bo-src" => "enterprise.promo_image"}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
%div.modal-centered{"ng-if" => "enterprise.twitter || enterprise.facebook || enterprise.linkedin || enterprise.instagram"}
|
||||
%div.modal-centered{bindonce: true, "bo-if" => "enterprise.twitter || enterprise.facebook || enterprise.linkedin || enterprise.instagram"}
|
||||
%p.modal-header Follow
|
||||
.follow-icons{bindonce: true}
|
||||
%span{"ng-if" => "enterprise.twitter"}
|
||||
%a{"ng-href" => "http://twitter.com/{{enterprise.twitter}}", target: "_blank"}
|
||||
.follow-icons
|
||||
%span{"bo-if" => "enterprise.twitter"}
|
||||
%a{"bo-href-i" => "http://twitter.com/{{enterprise.twitter}}", target: "_blank"}
|
||||
%i.ofn-i_041-twitter
|
||||
|
||||
%span{"ng-if" => "enterprise.facebook"}
|
||||
%a{"ng-href" => "http://{{enterprise.facebook | stripUrl}}", target: "_blank"}
|
||||
%span{"bo-if" => "enterprise.facebook"}
|
||||
%a{"bo-href-i" => "http://{{enterprise.facebook | stripUrl}}", target: "_blank"}
|
||||
%i.ofn-i_044-facebook
|
||||
|
||||
%span{"ng-if" => "enterprise.linkedin"}
|
||||
%a{"ng-href" => "http://{{enterprise.linkedin | stripUrl}}", target: "_blank"}
|
||||
%span{"bo-if" => "enterprise.linkedin"}
|
||||
%a{"bo-href-i" => "http://{{enterprise.linkedin | stripUrl}}", target: "_blank"}
|
||||
%i.ofn-i_042-linkedin
|
||||
|
||||
%span{"ng-if" => "enterprise.instagram"}
|
||||
%a{"ng-href" => "http://instagram.com/{{enterprise.instagram}}", target: "_blank"}
|
||||
%span{"bo-if" => "enterprise.instagram"}
|
||||
%a{"bo-href-i" => "http://instagram.com/{{enterprise.instagram}}", target: "_blank"}
|
||||
%i.ofn-i_043-instagram
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
.cta-container.small-12.columns
|
||||
%label
|
||||
Shop for
|
||||
%strong {{enterprise.name}}
|
||||
%strong{"bo-text" => "enterprise.name"}
|
||||
products at:
|
||||
%a.cta-hub{"ng-repeat" => "hub in enterprise.hubs",
|
||||
"bo-href" => "hub.path",
|
||||
@@ -10,7 +10,7 @@
|
||||
"ofn-empties-cart" => "hub"}
|
||||
%i.ofn-i_033-open-sign{"bo-if" => "hub.active"}
|
||||
%i.ofn-i_032-closed-sign{"bo-if" => "!hub.active"}
|
||||
.hub-name {{hub.name}}
|
||||
.button-address {{ hub.address.city }} , {{hub.address.state_name}}
|
||||
.hub-name{"bo-text" => "hub.name"}
|
||||
.button-address{"bo-bind" => "[hub.address.city, hub.address.state_name] | printArray"}
|
||||
/ %i.ofn-i_007-caret-right
|
||||
|
||||
|
||||
@@ -19,6 +19,6 @@
|
||||
"ofn-empties-cart" => "enterprise"}
|
||||
%i.ofn-i_033-open-sign{"bo-if" => "enterprise.active"}
|
||||
%i.ofn-i_032-closed-sign{"bo-if" => "!enterprise.active"}
|
||||
.hub-name {{enterprise.name}}
|
||||
.button-address {{ enterprise.address.city }} , {{enterprise.address.state_name}}
|
||||
.hub-name{"bo-text" => "enterprise.name"}
|
||||
.button-address{"bo-bind" => "[enterprise.address.city, enterprise.address.state_name] | printArray"}
|
||||
/ %i.ofn-i_007-caret-right
|
||||
|
||||
@@ -1,9 +1,28 @@
|
||||
.row
|
||||
.columns.small-12.large-6
|
||||
%img.product-img{"ng-src" => "{{product.largeImage}}", "ng-if" => "product.largeImage"}
|
||||
.row{bindonce: true}
|
||||
|
||||
.columns.small-12.large-6.product-header
|
||||
%h2
|
||||
/ %render-svg{path: "{{product.primary_taxon.icon}}"}
|
||||
{{product.name}}
|
||||
%p {{product.description}}
|
||||
%h3{"bo-text" => "product.name"}
|
||||
%span
|
||||
%em from
|
||||
%span.avenir{"bo-text" => "enterprise.name"}
|
||||
|
||||
%br
|
||||
|
||||
.filter-shopfront.taxon-selectors.inline-block
|
||||
%ul
|
||||
%filter-selector{ objects: "[product] | taxonsOf" }
|
||||
|
||||
.filter-shopfront.property-selectors.inline-block
|
||||
%ul
|
||||
%filter-selector{ objects: "[product] | propertiesWithValuesOf" }
|
||||
|
||||
%div{"ng-if" => "product.description"}
|
||||
%hr
|
||||
%p.text-small{"bo-text" => "product.description"}
|
||||
%hr
|
||||
|
||||
.columns.small-12.large-6
|
||||
%img.product-img{"bo-src" => "product.largeImage", "bo-if" => "product.largeImage"}
|
||||
%img.product-img.placeholder{"bo-src" => "'/assets/noimage/large.png'", "bo-if" => "!product.largeImage"}
|
||||
|
||||
%ng-include{src: "'partials/close.html'"}
|
||||
|
||||
@@ -40,6 +40,16 @@
|
||||
.field
|
||||
%label{ for: 'enterprise_acn' } ACN:
|
||||
%input.chunky{ id: 'enterprise_acn', placeholder: "eg. 123 456 789", ng: { model: 'enterprise.acn' } }
|
||||
.row
|
||||
.small-12.columns
|
||||
.field
|
||||
%label{ for: 'enterprise_charges_sales_tax' }= t(:charges_sales_tax)
|
||||
%input{ id: 'enterprise_charges_sales_tax_true', type: 'radio', name: 'charges_sales_tax', value: 'true', required: true, ng: { model: 'enterprise.charges_sales_tax' } }
|
||||
%label{ for: 'enterprise_charges_sales_tax_true' } Yes
|
||||
%input{ id: 'enterprise_charges_sales_tax_false', type: 'radio', name: 'charges_sales_tax', value: 'false', required: true, ng: { model: 'enterprise.charges_sales_tax' } }
|
||||
%label{ for: 'enterprise_charges_sales_tax_false' } No
|
||||
%span.error.small-12.columns{ ng: { show: "about.charges_sales_tax.$error.required && submitted" } }
|
||||
You need to make a selection.
|
||||
|
||||
.row.buttons.pad-top
|
||||
.small-12.columns
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
%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" }
|
||||
|
||||
%li.more{ ng: { show: "overFlowSelectors().length > 0 || fitting" } }
|
||||
%a.dropdown{ data: { dropdown: "{{ 'show-more-' + selectorName }}" }, ng: { class: "{active: selectedOverFlowSelectors().length > 0}" } }
|
||||
%span
|
||||
+ {{ overFlowSelectors().length }} more
|
||||
%i.ofn-i_052-point-down
|
||||
.f-dropdown.text-right.content{ ng: { attr: { id: "{{ 'show-more-' + selectorName }}" } } }
|
||||
%ul
|
||||
%active-selector{ ng: { repeat: "selector in overFlowSelectors()", hide: "selector.fits" } }
|
||||
%render-svg{path: "{{selector.object.icon}}", ng: { if: "selector.object.icon"}}
|
||||
%span {{ selector.object.name }}
|
||||
@@ -1,3 +0,0 @@
|
||||
%active-selector{"ng-repeat" => "selector in selectors()"}
|
||||
%render-svg{path: "{{selector.taxon.icon}}"}
|
||||
%span {{ selector.taxon.name }}
|
||||
3
app/assets/stylesheets/admin/icons.css.scss
Normal file
@@ -0,0 +1,3 @@
|
||||
@import 'plugins/font-awesome';
|
||||
|
||||
.icon-refund:before { @extend .icon-ok:before }
|
||||
120
app/assets/stylesheets/darkswarm/_shop-filters.css.sass
Normal file
@@ -0,0 +1,120 @@
|
||||
@import mixins
|
||||
@import branding
|
||||
@import big-input
|
||||
@import animations
|
||||
|
||||
@mixin filter-selector($base-clr, $border-clr, $hover-clr)
|
||||
&.inline-block, ul.inline-block
|
||||
display: inline-block
|
||||
|
||||
li
|
||||
display: inline-block
|
||||
@include border-radius(0)
|
||||
padding: 0
|
||||
margin: 0 0 0.25rem 0.25rem
|
||||
&:hover, &:focus
|
||||
background: transparent
|
||||
&.active
|
||||
box-shadow: none
|
||||
|
||||
a, a.button
|
||||
display: block
|
||||
padding-top: 0.5rem
|
||||
@include border-radius(0.5em)
|
||||
border: 1px solid $border-clr
|
||||
padding: 0.5em 0.625em
|
||||
font-size: 0.875em
|
||||
color: $base-clr
|
||||
font-size: 0.75em
|
||||
background: white
|
||||
margin: 0
|
||||
i
|
||||
padding-left: 0.25rem
|
||||
|
||||
render-svg
|
||||
&, & svg
|
||||
width: 1rem
|
||||
height: 1rem
|
||||
float: left
|
||||
padding-right: 0.25rem
|
||||
path
|
||||
@include csstrans
|
||||
fill: $base-clr
|
||||
|
||||
&:hover, &:focus
|
||||
border-color: $hover-clr
|
||||
color: $hover-clr
|
||||
render-svg
|
||||
svg
|
||||
path
|
||||
fill: $hover-clr
|
||||
|
||||
&.disabled
|
||||
opacity: 0.6
|
||||
|
||||
&:hover, &:focus
|
||||
border-color: $border-clr
|
||||
color: $base-clr
|
||||
render-svg
|
||||
svg
|
||||
path
|
||||
fill: $base-clr
|
||||
|
||||
|
||||
&.active, &.active:hover, &.active:focus
|
||||
border: 1px solid $base-clr
|
||||
background: $base-clr
|
||||
color: white
|
||||
render-svg
|
||||
svg
|
||||
path
|
||||
fill: white
|
||||
|
||||
|
||||
// Alert when search, taxon, filter is triggered
|
||||
|
||||
.alert-box.search-alert
|
||||
background-color: $clr-yellow-light
|
||||
border-color: $clr-yellow-light
|
||||
color: #777
|
||||
font-size: 0.75rem
|
||||
padding: 0.5rem 0.75rem
|
||||
|
||||
span.applied-properties
|
||||
color: #333
|
||||
|
||||
span.applied-taxons
|
||||
color: $clr-blue
|
||||
|
||||
span.applied-search
|
||||
color: $clr-brick
|
||||
|
||||
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
|
||||
|
||||
// Shopfront taxons
|
||||
&.taxon-selectors
|
||||
@include filter-selector($clr-blue, $clr-blue-light, $clr-blue-bright)
|
||||
|
||||
// Shopfront properties
|
||||
&.property-selectors
|
||||
@include filter-selector(#666, #ccc, #777)
|
||||
@@ -9,8 +9,7 @@
|
||||
@include placeholder(rgba(0,0,0,0.4), #777)
|
||||
|
||||
input#search
|
||||
@include big-input(rgba(0,0,0,0.3), #777, $clr-brick)
|
||||
@include big-input-static
|
||||
@include medium-input(rgba(0,0,0,0.3), #777, $clr-brick)
|
||||
|
||||
// ordering
|
||||
product
|
||||
|
||||
6
app/assets/stylesheets/darkswarm/_shop-modals.css.sass
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
.product-header
|
||||
h1, h2, h3, h4, h5, h6
|
||||
margin: 0
|
||||
hr
|
||||
margin: 0.5em 0
|
||||
@@ -30,20 +30,20 @@
|
||||
text-decoration: underline
|
||||
|
||||
span.margin-top
|
||||
margin-top: 0.5rem
|
||||
margin-top: 0.5rem
|
||||
display: inline-block
|
||||
|
||||
// Generic text resize
|
||||
@media all and (max-width: 640px)
|
||||
@media all and (max-width: 640px)
|
||||
&, & *
|
||||
font-size: 0.875rem
|
||||
font-size: 0.875rem
|
||||
fat > div label
|
||||
&, & *
|
||||
font-size: 0.75rem
|
||||
&, & *
|
||||
font-size: 0.75rem
|
||||
|
||||
|
||||
.active_table_row // Inherits from active_table
|
||||
border: 1px solid transparent
|
||||
// Inherits from active_table
|
||||
.active_table_row
|
||||
border: 1px solid transparent
|
||||
@include border-radius(0.5em)
|
||||
|
||||
// Foundation overrides
|
||||
@@ -76,15 +76,15 @@
|
||||
.active_table_row:last-child
|
||||
border-bottom: 1px solid $disabled-bright
|
||||
@include border-radius-mixed(0, 0, 0.5em, 0.5em)
|
||||
|
||||
|
||||
|
||||
|
||||
//Open row sections
|
||||
.fat > div
|
||||
border-top: 1px solid #aaa
|
||||
@media all and (max-width: 640px)
|
||||
@media all and (max-width: 640px)
|
||||
margin-top: 1em
|
||||
|
||||
ul, ol
|
||||
ul, ol
|
||||
font-size: 0.875rem
|
||||
|
||||
[class*="block-grid-"] > li
|
||||
@@ -96,10 +96,10 @@
|
||||
margin-top: 0.25rem
|
||||
margin-bottom: 0.25rem
|
||||
color: #777
|
||||
|
||||
|
||||
p.trans-sentence
|
||||
text-transform: capitalize
|
||||
|
||||
|
||||
&.closed
|
||||
&:hover, &:active, &:focus
|
||||
.active_table_row.closed
|
||||
@@ -112,7 +112,3 @@
|
||||
&.open
|
||||
.active_table_row:first-child
|
||||
color: $dark-grey
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
margin-left: 0
|
||||
margin-right: 0
|
||||
|
||||
.row.filter-box:first-child, .row.filter-box.filter-box-shopfront
|
||||
.row.filter-box:first-child
|
||||
border: 1px solid $clr-blue-light
|
||||
@include border-radius(0.25em)
|
||||
margin-top: 2px
|
||||
@@ -19,13 +19,9 @@
|
||||
background: transparent
|
||||
margin-top: 1em
|
||||
|
||||
.row.filter-box.filter-box-shopfront
|
||||
margin-top: 0
|
||||
|
||||
products .filter-box
|
||||
background: #f7f7f7
|
||||
|
||||
|
||||
.filter-box
|
||||
background: rgba(245,245,245,0.6)
|
||||
.tdhead
|
||||
@@ -40,7 +36,6 @@ products .filter-box
|
||||
[class*="block-grid-"] > li
|
||||
padding-bottom: 0.5rem !important
|
||||
|
||||
|
||||
li
|
||||
@include border-radius(12px)
|
||||
padding-top: 0.5rem
|
||||
@@ -105,16 +100,6 @@ products .filter-box
|
||||
path
|
||||
fill: #666
|
||||
|
||||
.filter-box.filter-box-shopfront
|
||||
.tdhead
|
||||
margin-top: 0rem
|
||||
margin-bottom: 0.75rem
|
||||
padding: 0.5rem 0
|
||||
h5
|
||||
color: $clr-blue
|
||||
.button.tiny
|
||||
margin-bottom: 0rem
|
||||
|
||||
.button.filterbtn
|
||||
margin-bottom: 0 !important
|
||||
min-width: 160px
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
// ANIMATION FUNCTIONS
|
||||
|
||||
|
||||
//
|
||||
@-webkit-keyframes slideInDown
|
||||
0%
|
||||
opacity: 0
|
||||
@@ -22,6 +24,8 @@
|
||||
-ms-transform: translateY(0)
|
||||
transform: translateY(0)
|
||||
|
||||
|
||||
|
||||
@-webkit-keyframes slideOutUp
|
||||
0%
|
||||
-webkit-transform: translateY(0)
|
||||
@@ -160,6 +164,51 @@ product.animate-repeat
|
||||
-webkit-animation-fill-mode: both
|
||||
animation-fill-mode: both
|
||||
|
||||
//
|
||||
|
||||
.animate-slide
|
||||
max-height: 500px
|
||||
opacity: 1 !important
|
||||
-webkit-transition: all 300ms ease-in-out
|
||||
-moz-transition: all 300ms ease-in-out
|
||||
-o-transition: all 300ms ease-in-out
|
||||
transition: all 300ms ease-in-out
|
||||
|
||||
&.ng-hide
|
||||
overflow: hidden
|
||||
max-height: 0
|
||||
opacity: 0 !important
|
||||
|
||||
// &.ng-hide-add-active, &.ng-hide-remove-active
|
||||
|
||||
&.ng-hide-add, &.ng-hide-remove
|
||||
/* IMPORTANT: this needs to be here to make it visible during the animation
|
||||
since the .ng-hide class is already on the element rendering
|
||||
it as hidden. */
|
||||
display: block !important
|
||||
|
||||
|
||||
.animate-show
|
||||
opacity: 1 !important
|
||||
-webkit-transition: all 300ms ease-in-out
|
||||
-moz-transition: all 300ms ease-in-out
|
||||
-o-transition: all 300ms ease-in-out
|
||||
transition: all 300ms ease-in-out
|
||||
|
||||
&.ng-hide
|
||||
opacity: 0 !important
|
||||
|
||||
// &.ng-hide-add-active, &.ng-hide-remove-active
|
||||
|
||||
&.ng-hide-add, &.ng-hide-remove
|
||||
/* IMPORTANT: this needs to be here to make it visible during the animation
|
||||
since the .ng-hide class is already on the element rendering
|
||||
it as hidden. */
|
||||
display: block !important
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@mixin csstrans
|
||||
-webkit-transition: all 300ms ease
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
border: 2px solid $input
|
||||
font-size: 2rem
|
||||
box-shadow: 0
|
||||
padding: 0.75rem 1rem 0.35rem 1rem
|
||||
padding: 0.75rem 1rem 0.35rem
|
||||
height: auto
|
||||
width: 100%
|
||||
margin-bottom: 0.5rem
|
||||
@@ -33,8 +33,9 @@
|
||||
background: white
|
||||
background: rgba(255,255,255,0.5)
|
||||
text-shadow: 0 0 10px #ffffff
|
||||
padding: 1.5rem 1rem 1rem 1rem
|
||||
padding: 1.5rem 1rem 1rem
|
||||
letter-spacing: 0.02rem
|
||||
outline: none
|
||||
|
||||
@mixin big-input-static
|
||||
outline: 0
|
||||
@@ -42,6 +43,34 @@
|
||||
padding: 0.75rem 1rem 0.35rem 1rem
|
||||
letter-spacing: 0
|
||||
|
||||
@mixin medium-input($input, $inputhvr, $inputactv)
|
||||
@include avenir
|
||||
@include csstrans
|
||||
@include border-radius(0.5rem)
|
||||
background: rgba(255,255,255,0.1)
|
||||
border: 2px solid $input
|
||||
font-size: 0.875rem
|
||||
box-shadow: 0
|
||||
padding: 0.5rem 0.625rem 0.375rem
|
||||
height: auto
|
||||
width: 100%
|
||||
margin-bottom: 0.5rem
|
||||
box-shadow: none
|
||||
color: $inputactv
|
||||
|
||||
&:hover
|
||||
@include box-shadow(0 1px 1px 0 rgba(255,255,255,0.25))
|
||||
border: 2px solid $inputhvr
|
||||
color: $inputactv
|
||||
|
||||
&:active, &:focus, &.active
|
||||
border: 2px solid $inputactv
|
||||
color: $inputactv
|
||||
background: white
|
||||
background: rgba(255,255,255,0.5)
|
||||
text-shadow: 0 0 10px #ffffff
|
||||
outline: none
|
||||
|
||||
@mixin placeholder($placeholder, $placeholderhvr)
|
||||
::-webkit-input-placeholder
|
||||
color: $placeholder
|
||||
|
||||
@@ -15,6 +15,8 @@ $clr-blue: #0096ad
|
||||
$clr-blue-light: #85d9e5
|
||||
$clr-blue-bright: #14b6cc
|
||||
|
||||
$clr-yellow-light: #faf6c7
|
||||
|
||||
$disabled-light: #e5e5e5
|
||||
$disabled-bright: #ccc
|
||||
$disabled-med: #b3b3b3
|
||||
@@ -25,3 +27,4 @@ $med-drk-grey: #444
|
||||
$dark-grey: #333
|
||||
$light-grey: #ddd
|
||||
$black: #000
|
||||
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
margin-bottom: 10px
|
||||
outline: 1px solid #ccc
|
||||
@include box-shadow(0 1px 2px 1px rgba(0,0,0,0.15))
|
||||
// placeholder for when no product images
|
||||
&.placeholder
|
||||
opacity: 0.35
|
||||
@media all and (max-width: 1024px)
|
||||
display: none
|
||||
|
||||
.hero-img
|
||||
outline: 1px solid $disabled-bright
|
||||
|
||||
@@ -10,11 +10,12 @@
|
||||
height: 100%
|
||||
width: 100%
|
||||
|
||||
img // https://github.com/zurb/foundation/issues/112
|
||||
// https://github.com/zurb/foundation/issues/112
|
||||
img
|
||||
max-width: none
|
||||
height: auto
|
||||
|
||||
#pac-input
|
||||
#pac-input
|
||||
@include big-input(#888, #333, $clr-brick)
|
||||
@include big-input-static
|
||||
font-size: 1.5rem
|
||||
|
||||
@@ -8,6 +8,7 @@ dialog, .reveal-modal
|
||||
border-bottom: 30px solid white
|
||||
overflow-y: scroll
|
||||
overflow-x: hidden
|
||||
min-height: 260px
|
||||
// Not working yet - want a nice gradient shadow when there is overflow - needs JS too
|
||||
// &:after
|
||||
// @include elipse-shadow(0 0 40px rgba(0, 0, 0, 0.8))
|
||||
@@ -32,6 +33,7 @@ dialog, .reveal-modal
|
||||
|
||||
.reveal-modal-bg
|
||||
background-color: rgba(0,0,0,0.85)
|
||||
position: fixed
|
||||
|
||||
dialog .close-reveal-modal, .reveal-modal .close-reveal-modal
|
||||
right: 0.25rem
|
||||
|
||||
@@ -15,10 +15,8 @@
|
||||
|
||||
products
|
||||
display: block
|
||||
padding-top: 2.3em
|
||||
padding-top: 20px
|
||||
@media all and (max-width: 768px)
|
||||
padding-top: 1em
|
||||
|
||||
input.button.right
|
||||
float: left
|
||||
|
||||
|
||||
@@ -20,21 +20,27 @@
|
||||
right: 22px !important
|
||||
left: auto
|
||||
|
||||
ul, li
|
||||
list-style: none
|
||||
margin-left: 0
|
||||
table
|
||||
width: 100%
|
||||
border: none
|
||||
border-spacing: 0px
|
||||
margin-bottom: 5px
|
||||
|
||||
li
|
||||
float: none
|
||||
|
||||
.row .columns
|
||||
padding-left: 0.25rem
|
||||
padding-right: 0.25rem
|
||||
|
||||
li.total-cart
|
||||
background-color: #424242
|
||||
li.product-cart
|
||||
border-top: 1px solid #424242
|
||||
tr.total-cart
|
||||
color: #fff
|
||||
background-color: #424242
|
||||
td
|
||||
color: #fff
|
||||
tr.product-cart
|
||||
background-color: #333333
|
||||
border-top: 1px solid #424242
|
||||
td
|
||||
padding: 4px 12px
|
||||
color: #fff
|
||||
.buttons
|
||||
.button
|
||||
height: auto
|
||||
top: 0px
|
||||
|
||||
// Shopping cart
|
||||
#cart-detail
|
||||
|
||||
@@ -20,6 +20,17 @@ module Admin
|
||||
end
|
||||
end
|
||||
|
||||
def for_order_cycle
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json do
|
||||
render json: ActiveModel::ArraySerializer.new( @collection,
|
||||
each_serializer: Api::Admin::EnterpriseFeeSerializer, controller: self
|
||||
).to_json
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def bulk_update
|
||||
@enterprise_fee_set = EnterpriseFeeSet.new(params[:enterprise_fee_set])
|
||||
if @enterprise_fee_set.save
|
||||
@@ -63,9 +74,22 @@ module Admin
|
||||
end
|
||||
|
||||
def collection
|
||||
collection = EnterpriseFee.managed_by(spree_current_user).order('enterprise_id', 'fee_type', 'name')
|
||||
collection = collection.for_enterprise(current_enterprise) if current_enterprise
|
||||
collection
|
||||
case action
|
||||
when :for_order_cycle
|
||||
order_cycle = OrderCycle.find_by_id(params[:order_cycle_id]) if params[:order_cycle_id]
|
||||
coordinator = Enterprise.find_by_id(params[:coordinator_id]) if params[:coordinator_id]
|
||||
order_cycle = OrderCycle.new(coordinator: coordinator) if order_cycle.nil? && coordinator.present?
|
||||
enterprises = OpenFoodNetwork::OrderCyclePermissions.new(spree_current_user, order_cycle).visible_enterprises
|
||||
return EnterpriseFee.for_enterprises(enterprises).order('enterprise_id', 'fee_type', 'name')
|
||||
else
|
||||
collection = EnterpriseFee.managed_by(spree_current_user).order('enterprise_id', 'fee_type', 'name')
|
||||
collection = collection.for_enterprise(current_enterprise) if current_enterprise
|
||||
collection
|
||||
end
|
||||
end
|
||||
|
||||
def collection_actions
|
||||
[:index, :for_order_cycle]
|
||||
end
|
||||
|
||||
def current_enterprise
|
||||
|
||||
@@ -11,16 +11,15 @@ module Admin
|
||||
before_filter :check_can_change_owner, only: :update
|
||||
before_filter :check_can_change_bulk_owner, only: :bulk_update
|
||||
before_filter :check_can_change_managers, only: :update
|
||||
before_filter :strip_new_properties, only: [:create, :update]
|
||||
before_filter :load_properties, only: [:edit, :update]
|
||||
before_filter :setup_property, only: [:edit]
|
||||
|
||||
|
||||
helper 'spree/products'
|
||||
include ActionView::Helpers::TextHelper
|
||||
include OrderCyclesHelper
|
||||
|
||||
def for_order_cycle
|
||||
@collection = order_cycle_permitted_enterprises
|
||||
end
|
||||
|
||||
def set_sells
|
||||
enterprise = Enterprise.find_by_permalink(params[:id]) || Enterprise.find(params[:id])
|
||||
attributes = { sells: params[:sells] }
|
||||
@@ -67,6 +66,16 @@ module Admin
|
||||
end
|
||||
end
|
||||
|
||||
def for_order_cycle
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
render json: ActiveModel::ArraySerializer.new( @collection,
|
||||
each_serializer: Api::Admin::ForOrderCycle::EnterpriseSerializer, spree_current_user: spree_current_user
|
||||
).to_json
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def build_resource_with_address
|
||||
@@ -94,10 +103,18 @@ module Admin
|
||||
end
|
||||
|
||||
def collection
|
||||
# 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).
|
||||
editable_enterprises.
|
||||
order('is_primary_producer ASC, name')
|
||||
case action
|
||||
when :for_order_cycle
|
||||
order_cycle = OrderCycle.find_by_id(params[:order_cycle_id]) if params[:order_cycle_id]
|
||||
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
|
||||
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).
|
||||
editable_enterprises.
|
||||
order('is_primary_producer ASC, name')
|
||||
end
|
||||
end
|
||||
|
||||
def collection_actions
|
||||
@@ -132,8 +149,9 @@ module Admin
|
||||
|
||||
def override_sells
|
||||
unless spree_current_user.admin?
|
||||
has_hub = spree_current_user.enterprises.is_hub.any?
|
||||
params[:enterprise][:sells] = has_hub ? 'any' : 'none'
|
||||
has_hub = spree_current_user.owned_enterprises.is_hub.any?
|
||||
new_enterprise_is_producer = Enterprise.new(params[:enterprise]).is_primary_producer
|
||||
params[:enterprise][:sells] = (has_hub && !new_enterprise_is_producer) ? 'any' : 'none'
|
||||
end
|
||||
end
|
||||
|
||||
@@ -157,9 +175,27 @@ module Admin
|
||||
end
|
||||
end
|
||||
|
||||
def strip_new_properties
|
||||
unless spree_current_user.admin? || params[:enterprise][:producer_properties_attributes].nil?
|
||||
names = Spree::Property.pluck(:name)
|
||||
params[:enterprise][:producer_properties_attributes].each do |key, property|
|
||||
params[:enterprise][:producer_properties_attributes].delete key unless names.include? property[:property_name]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def load_properties
|
||||
@properties = Spree::Property.pluck(:name)
|
||||
end
|
||||
|
||||
def setup_property
|
||||
@enterprise.producer_properties.build
|
||||
end
|
||||
|
||||
# Overriding method on Spree's resource controller
|
||||
def location_after_save
|
||||
if params[:enterprise].key? :producer_properties_attributes
|
||||
refered_from_edit = URI(request.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
|
||||
main_app.edit_admin_enterprise_path(@enterprise)
|
||||
|
||||
@@ -1,24 +1,32 @@
|
||||
require 'open_food_network/permissions'
|
||||
require 'open_food_network/order_cycle_permissions'
|
||||
require 'open_food_network/order_cycle_form_applicator'
|
||||
|
||||
module Admin
|
||||
class OrderCyclesController < ResourceController
|
||||
include OrderCyclesHelper
|
||||
|
||||
before_filter :load_order_cycle_set, :only => :index
|
||||
before_filter :load_data_for_index, :only => :index
|
||||
before_filter :require_coordinator, only: :new
|
||||
before_filter :remove_protected_attrs, only: [:update]
|
||||
before_filter :remove_unauthorized_bulk_attrs, only: [:bulk_update]
|
||||
around_filter :protect_invalid_destroy, only: :destroy
|
||||
|
||||
|
||||
def show
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json
|
||||
format.json do
|
||||
render json: Api::Admin::OrderCycleSerializer.new(@order_cycle, current_user: spree_current_user).to_json
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def new
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json
|
||||
format.json do
|
||||
render json: Api::Admin::OrderCycleSerializer.new(@order_cycle, current_user: spree_current_user).to_json
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -27,7 +35,7 @@ module Admin
|
||||
|
||||
respond_to do |format|
|
||||
if @order_cycle.save
|
||||
OpenFoodNetwork::OrderCycleFormApplicator.new(@order_cycle, order_cycle_permitted_enterprises).go!
|
||||
OpenFoodNetwork::OrderCycleFormApplicator.new(@order_cycle, spree_current_user).go!
|
||||
|
||||
flash[:notice] = 'Your order cycle has been created.'
|
||||
format.html { redirect_to admin_order_cycles_path }
|
||||
@@ -44,7 +52,7 @@ module Admin
|
||||
|
||||
respond_to do |format|
|
||||
if @order_cycle.update_attributes(params[:order_cycle])
|
||||
OpenFoodNetwork::OrderCycleFormApplicator.new(@order_cycle, order_cycle_permitted_enterprises).go!
|
||||
OpenFoodNetwork::OrderCycleFormApplicator.new(@order_cycle, spree_current_user).go!
|
||||
|
||||
flash[:notice] = 'Your order cycle has been updated.'
|
||||
format.html { redirect_to admin_order_cycles_path }
|
||||
@@ -73,26 +81,27 @@ module Admin
|
||||
|
||||
|
||||
protected
|
||||
def collection
|
||||
ocs = OrderCycle.managed_by(spree_current_user)
|
||||
def collection(show_more=false)
|
||||
ocs = OrderCycle.accessible_by(spree_current_user)
|
||||
|
||||
ocs.undated +
|
||||
ocs.soonest_closing +
|
||||
ocs.soonest_opening +
|
||||
ocs.most_recently_closed
|
||||
(show_more ? ocs.closed : ocs.recently_closed)
|
||||
end
|
||||
|
||||
private
|
||||
def load_order_cycle_set
|
||||
@order_cycle_set = OrderCycleSet.new :collection => collection
|
||||
def load_data_for_index
|
||||
@show_more = !!params[:show_more]
|
||||
@order_cycle_set = OrderCycleSet.new :collection => collection(@show_more)
|
||||
end
|
||||
|
||||
def require_coordinator
|
||||
if params[:coordinator_id] && @order_cycle.coordinator = order_cycle_coordinating_enterprises.find_by_id(params[:coordinator_id])
|
||||
if params[:coordinator_id] && @order_cycle.coordinator = permitted_coordinating_enterprises_for(@order_cycle).find_by_id(params[:coordinator_id])
|
||||
return
|
||||
end
|
||||
|
||||
available_coordinators = order_cycle_coordinating_enterprises.select(&:confirmed?)
|
||||
available_coordinators = permitted_coordinating_enterprises_for(@order_cycle).select(&:confirmed?)
|
||||
case available_coordinators.count
|
||||
when 0
|
||||
flash[:error] = "None of your enterprises have permission to coordinate an order cycle"
|
||||
@@ -104,5 +113,31 @@ module Admin
|
||||
render :set_coordinator
|
||||
end
|
||||
end
|
||||
|
||||
def protect_invalid_destroy
|
||||
begin
|
||||
yield
|
||||
rescue ActiveRecord::InvalidForeignKey
|
||||
redirect_to main_app.admin_order_cycles_url
|
||||
flash[:error] = "That order cycle has been selected by a customer and cannot be deleted. To prevent customers from accessing it, please close it instead."
|
||||
end
|
||||
end
|
||||
|
||||
def remove_protected_attrs
|
||||
params[:order_cycle].delete :coordinator_id
|
||||
|
||||
unless Enterprise.managed_by(spree_current_user).include?(@order_cycle.coordinator)
|
||||
params[:order_cycle].delete_if{ |k,v| [:name, :orders_open_at, :orders_close_at].include? k.to_sym }
|
||||
end
|
||||
end
|
||||
|
||||
def remove_unauthorized_bulk_attrs
|
||||
params[:order_cycle_set][:collection_attributes].each do |i, hash|
|
||||
order_cycle = OrderCycle.find(hash[:id])
|
||||
unless Enterprise.managed_by(spree_current_user).include?(order_cycle.andand.coordinator)
|
||||
params[:order_cycle_set][:collection_attributes].delete i
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,7 +2,6 @@ require 'open_food_network/spree_api_key_loader'
|
||||
|
||||
module Admin
|
||||
class VariantOverridesController < ResourceController
|
||||
include OrderCyclesHelper
|
||||
include OpenFoodNetwork::SpreeApiKeyLoader
|
||||
|
||||
before_filter :load_spree_api_key, only: :index
|
||||
@@ -35,7 +34,8 @@ module Admin
|
||||
private
|
||||
|
||||
def load_data
|
||||
@hubs = order_cycle_hub_enterprises
|
||||
@hubs = OpenFoodNetwork::Permissions.new(spree_current_user).
|
||||
variant_override_hubs.by_name
|
||||
|
||||
# Used in JS to look up the name of the producer of each product
|
||||
@producers = OpenFoodNetwork::Permissions.new(spree_current_user).
|
||||
|
||||
@@ -13,7 +13,8 @@ module Api
|
||||
end
|
||||
|
||||
def accessible
|
||||
@enterprises = Enterprise.ransack(params[:q]).result.accessible_by(current_api_user)
|
||||
permitted = OpenFoodNetwork::Permissions.new(current_api_user).order_cycle_enterprises
|
||||
@enterprises = permitted.ransack(params[:q]).result
|
||||
render params[:template] || :bulk_index
|
||||
end
|
||||
|
||||
@@ -63,7 +64,9 @@ module Api
|
||||
end
|
||||
|
||||
def override_sells
|
||||
params[:enterprise][:sells] = 'unspecified'
|
||||
has_hub = current_api_user.owned_enterprises.is_hub.any?
|
||||
new_enterprise_is_producer = !!params[:enterprise][:is_primary_producer]
|
||||
params[:enterprise][:sells] = (has_hub && !new_enterprise_is_producer) ? 'any' : 'unspecified'
|
||||
end
|
||||
|
||||
def override_visible
|
||||
|
||||
@@ -9,7 +9,16 @@ module Api
|
||||
end
|
||||
|
||||
def accessible
|
||||
@order_cycles = OrderCycle.ransack(params[:q]).result.accessible_by(current_api_user)
|
||||
@order_cycles = if params[:as] == "distributor"
|
||||
OrderCycle.ransack(params[:q]).result.
|
||||
involving_managed_distributors_of(current_api_user).order('updated_at DESC')
|
||||
elsif params[:as] == "producer"
|
||||
OrderCycle.ransack(params[:q]).result.
|
||||
involving_managed_producers_of(current_api_user).order('updated_at DESC')
|
||||
else
|
||||
OrderCycle.ransack(params[:q]).result.accessible_by(current_api_user)
|
||||
end
|
||||
|
||||
render params[:template] || :bulk_index
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,15 +8,12 @@ class ApplicationController < ActionController::Base
|
||||
super(options, response_status)
|
||||
end
|
||||
|
||||
def after_sign_in_path_for(resource)
|
||||
def set_checkout_redirect
|
||||
if request.referer and referer_path = URI(request.referer).path
|
||||
[main_app.checkout_path].include?(referer_path) ? referer_path : root_path
|
||||
else
|
||||
root_path
|
||||
session["spree_user_return_to"] = [main_app.checkout_path].include?(referer_path) ? referer_path : root_path
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def require_distributor_chosen
|
||||
|
||||
@@ -19,6 +19,7 @@ class CheckoutController < Spree::CheckoutController
|
||||
|
||||
def update
|
||||
if @order.update_attributes(object_params)
|
||||
check_order_for_phantom_fees
|
||||
fire_event('spree.checkout.update')
|
||||
while @order.state != "complete"
|
||||
if @order.state == "payment"
|
||||
@@ -58,6 +59,20 @@ class CheckoutController < Spree::CheckoutController
|
||||
|
||||
private
|
||||
|
||||
def check_order_for_phantom_fees
|
||||
phantom_fees = @order.adjustments.joins('LEFT OUTER JOIN spree_line_items ON spree_line_items.id = spree_adjustments.source_id').
|
||||
where("originator_type = 'EnterpriseFee' AND source_type = 'Spree::LineItem' AND spree_line_items.id IS NULL")
|
||||
|
||||
if phantom_fees.any?
|
||||
Bugsnag.notify(RuntimeError.new("Phantom Fees"), {
|
||||
phantom_fees: {
|
||||
phantom_total: phantom_fees.sum(&:amount).to_s,
|
||||
phantom_fees: phantom_fees.as_json
|
||||
}
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
# Copied and modified from spree. Remove check for order state, since the state machine is
|
||||
# progressed all the way in one go with the one page checkout.
|
||||
def object_params
|
||||
@@ -110,7 +125,7 @@ class CheckoutController < Spree::CheckoutController
|
||||
last_used_bill_address, last_used_ship_address = find_last_used_addresses(@order.email)
|
||||
preferred_bill_address, preferred_ship_address = spree_current_user.bill_address, spree_current_user.ship_address if spree_current_user.respond_to?(:bill_address) && spree_current_user.respond_to?(:ship_address)
|
||||
@order.bill_address ||= preferred_bill_address || last_used_bill_address || Spree::Address.default
|
||||
@order.ship_address ||= preferred_ship_address || last_used_ship_address || Spree::Address.default
|
||||
@order.ship_address ||= preferred_ship_address || last_used_ship_address || Spree::Address.default
|
||||
end
|
||||
|
||||
def after_payment
|
||||
|
||||
@@ -32,6 +32,24 @@ class EnterpriseConfirmationsController < DeviseController
|
||||
set_flash_message(:error, :not_confirmed) if is_navigational_format?
|
||||
end
|
||||
|
||||
respond_with_navigational(resource){ redirect_to spree.admin_path }
|
||||
respond_with_navigational(resource){ redirect_to redirect_path(resource) }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
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
|
||||
resource.users << user
|
||||
spree.edit_spree_user_password_path(user, :reset_password_token => user.reset_password_token, return_to: spree.admin_path)
|
||||
end
|
||||
|
||||
def redirect_path(resource)
|
||||
if resource.persisted? && !Spree::User.exists?(email: resource.email)
|
||||
new_user_reset_path(resource)
|
||||
else
|
||||
spree.admin_path
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
Spree::Admin::LineItemsController.class_eval do
|
||||
private
|
||||
|
||||
def load_order
|
||||
@order = Spree::Order.find_by_number!(params[:order_id])
|
||||
authorize! :update, @order
|
||||
end
|
||||
end
|
||||
@@ -9,6 +9,13 @@ Spree::Admin::OrdersController.class_eval do
|
||||
# in an auth failure as the @order object is nil for collection actions
|
||||
before_filter :check_authorization, :except => :bulk_management
|
||||
|
||||
# After updating an order, the fees should be updated as well
|
||||
# Currently, adding or deleting line items does not trigger updating the
|
||||
# fees! This is a quick fix for that.
|
||||
# TODO: update fees when adding/removing line items
|
||||
# instead of the update_distribution_charge method.
|
||||
after_filter :update_distribution_charge, :only => :update
|
||||
|
||||
respond_override :index => { :html =>
|
||||
{ :success => lambda {
|
||||
# Filter orders to only show those distributed by current user (or all for admin user)
|
||||
@@ -17,4 +24,17 @@ Spree::Admin::OrdersController.class_eval do
|
||||
page(params[:page]).
|
||||
per(params[:per_page] || Spree::Config[:orders_per_page])
|
||||
} } }
|
||||
|
||||
# Overwrite to use confirm_email_for_customer instead of confirm_email.
|
||||
# This uses a new template. See mailers/spree/order_mailer_decorator.rb.
|
||||
def resend
|
||||
Spree::OrderMailer.confirm_email_for_customer(@order.id, true).deliver
|
||||
flash[:success] = t(:order_email_resent)
|
||||
|
||||
respond_with(@order) { |format| format.html { redirect_to :back } }
|
||||
end
|
||||
|
||||
def update_distribution_charge
|
||||
@order.update_distribution_charge!
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,6 +5,7 @@ Spree::Admin::ProductsController.class_eval do
|
||||
include OrderCyclesHelper
|
||||
before_filter :load_form_data, :only => [:bulk_edit, :new, :create, :edit, :update]
|
||||
before_filter :load_spree_api_key, :only => [:bulk_edit, :variant_overrides]
|
||||
before_filter :strip_new_properties, only: [:create, :update]
|
||||
|
||||
alias_method :location_after_save_original, :location_after_save
|
||||
|
||||
@@ -95,4 +96,13 @@ Spree::Admin::ProductsController.class_eval do
|
||||
@producers = OpenFoodNetwork::Permissions.new(spree_current_user).managed_product_enterprises.is_primary_producer.by_name
|
||||
@taxons = Spree::Taxon.order(:name)
|
||||
end
|
||||
|
||||
def strip_new_properties
|
||||
unless spree_current_user.admin? || params[:product][:product_properties_attributes].nil?
|
||||
names = Spree::Property.pluck(:name)
|
||||
params[:product][:product_properties_attributes].each do |key, property|
|
||||
params[:product][:product_properties_attributes].delete key unless names.include? property[:property_name]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -102,7 +102,7 @@ Spree::Admin::ReportsController.class_eval do
|
||||
send_data csv_string, :filename => "orders_and_distributors_#{timestamp}.csv"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def sales_tax
|
||||
params[:q] ||= {}
|
||||
|
||||
@@ -323,7 +323,7 @@ Spree::Admin::ReportsController.class_eval do
|
||||
sort_by: proc { |payment_state| payment_state } },
|
||||
{ group_by: proc { |payment| payment.order.distributor },
|
||||
sort_by: proc { |distributor| distributor.name } },
|
||||
{ group_by: proc { |payment| payment.payment_method },
|
||||
{ group_by: proc { |payment| Spree::PaymentMethod.unscoped { payment.payment_method } },
|
||||
sort_by: proc { |method| method.name } } ]
|
||||
|
||||
when "itemised_payment_totals"
|
||||
@@ -406,27 +406,34 @@ Spree::Admin::ReportsController.class_eval do
|
||||
end
|
||||
params[:q][:meta_sort] ||= "completed_at.desc"
|
||||
|
||||
# -- Search
|
||||
@search = Spree::Order.complete.not_state(:canceled).managed_by(spree_current_user).search(params[:q])
|
||||
orders = @search.result
|
||||
@line_items = orders.map do |o|
|
||||
lis = o.line_items.managed_by(spree_current_user)
|
||||
lis = lis.supplied_by_any(params[:supplier_id_in]) if params[:supplier_id_in].present?
|
||||
lis
|
||||
end.flatten
|
||||
#payments = orders.map { |o| o.payments.select { |payment| payment.completed? } }.flatten # Only select completed payments
|
||||
permissions = OpenFoodNetwork::Permissions.new(spree_current_user)
|
||||
|
||||
# -- Prepare form options
|
||||
my_distributors = Enterprise.is_distributor.managed_by(spree_current_user)
|
||||
my_suppliers = Enterprise.is_primary_producer.managed_by(spree_current_user)
|
||||
# -- Search
|
||||
|
||||
@search = Spree::Order.complete.not_state(:canceled).search(params[:q])
|
||||
orders = permissions.visible_orders.merge(@search.result)
|
||||
|
||||
@line_items = permissions.visible_line_items.merge(Spree::LineItem.where(order_id: orders))
|
||||
@line_items = @line_items.supplied_by_any(params[:supplier_id_in]) if params[:supplier_id_in].present?
|
||||
|
||||
line_items_with_hidden_details = @line_items.where('"spree_line_items"."id" NOT IN (?)', permissions.editable_line_items)
|
||||
@line_items.select{ |li| line_items_with_hidden_details.include? li }.each do |line_item|
|
||||
# TODO We should really be hiding customer code here too, but until we
|
||||
# have an actual association between order and customer, it's a bit tricky
|
||||
line_item.order.bill_address.assign_attributes(firstname: "HIDDEN", lastname: "", phone: "", address1: "", address2: "", city: "", zipcode: "", state: nil)
|
||||
line_item.order.ship_address.assign_attributes(firstname: "HIDDEN", lastname: "", phone: "", address1: "", address2: "", city: "", zipcode: "", state: nil)
|
||||
line_item.order.assign_attributes(email: "HIDDEN")
|
||||
end
|
||||
|
||||
# My distributors and any distributors distributing products I supply
|
||||
@distributors = my_distributors | Enterprise.with_distributed_products_outer.merge(Spree::Product.in_any_supplier(my_suppliers))
|
||||
@distributors = permissions.visible_enterprises_for_order_reports.is_distributor
|
||||
|
||||
# My suppliers and any suppliers supplying products I distribute
|
||||
@suppliers = my_suppliers | my_distributors.map { |d| Spree::Product.in_distributor(d) }.flatten.map(&:supplier).uniq
|
||||
@suppliers = permissions.visible_enterprises_for_order_reports.is_primary_producer
|
||||
|
||||
@order_cycles = OrderCycle.active_or_complete.
|
||||
involving_managed_distributors_of(spree_current_user).order('orders_close_at DESC')
|
||||
|
||||
@order_cycles = OrderCycle.active_or_complete.accessible_by(spree_current_user).order('orders_close_at DESC')
|
||||
@report_types = REPORT_TYPES[:orders_and_fulfillment]
|
||||
@report_type = params[:report_type]
|
||||
|
||||
@@ -525,18 +532,26 @@ Spree::Admin::ReportsController.class_eval do
|
||||
table_items = @line_items
|
||||
@include_blank = 'All'
|
||||
|
||||
header = ["Hub", "Customer", "Email", "Phone", "Producer", "Product", "Variant", "Amount", "Item (#{currency_symbol})", "Item + Fees (#{currency_symbol})", "Dist (#{currency_symbol})", "Ship (#{currency_symbol})", "Total (#{currency_symbol})", "Paid?",
|
||||
"Shipping", "Delivery?", "Ship street", "Ship street 2", "Ship city", "Ship postcode", "Ship state", "Order notes"]
|
||||
header = ["Hub", "Customer", "Email", "Phone", "Producer", "Product", "Variant",
|
||||
"Amount", "Item (#{currency_symbol})", "Item + Fees (#{currency_symbol})", "Admin & Handling (#{currency_symbol})", "Ship (#{currency_symbol})", "Total (#{currency_symbol})", "Paid?",
|
||||
"Shipping", "Delivery?",
|
||||
"Ship Street", "Ship Street 2", "Ship City", "Ship Postcode", "Ship State",
|
||||
"Comments", "SKU",
|
||||
"Order Cycle", "Payment Method", "Customer Code", "Tags",
|
||||
"Billing Street 1", "Billing Street 2", "Billing City", "Billing Postcode", "Billing State"
|
||||
]
|
||||
|
||||
rsa = proc { |line_items| line_items.first.order.shipping_method.andand.require_ship_address }
|
||||
|
||||
columns = [ proc { |line_items| line_items.first.order.distributor.name },
|
||||
columns = [
|
||||
proc { |line_items| line_items.first.order.distributor.name },
|
||||
proc { |line_items| line_items.first.order.bill_address.firstname + " " + line_items.first.order.bill_address.lastname },
|
||||
proc { |line_items| line_items.first.order.email },
|
||||
proc { |line_items| line_items.first.order.bill_address.phone },
|
||||
proc { |line_items| line_items.first.variant.product.supplier.name },
|
||||
proc { |line_items| line_items.first.variant.product.name },
|
||||
proc { |line_items| line_items.first.variant.full_name },
|
||||
|
||||
proc { |line_items| line_items.sum { |li| li.quantity } },
|
||||
proc { |line_items| line_items.sum { |li| li.amount } },
|
||||
proc { |line_items| line_items.sum { |li| li.amount_with_adjustments } },
|
||||
@@ -547,25 +562,40 @@ Spree::Admin::ReportsController.class_eval do
|
||||
|
||||
proc { |line_items| line_items.first.order.shipping_method.andand.name },
|
||||
proc { |line_items| rsa.call(line_items) ? 'Y' : 'N' },
|
||||
|
||||
proc { |line_items| line_items.first.order.ship_address.andand.address1 if rsa.call(line_items) },
|
||||
proc { |line_items| line_items.first.order.ship_address.andand.address2 if rsa.call(line_items) },
|
||||
proc { |line_items| line_items.first.order.ship_address.andand.city if rsa.call(line_items) },
|
||||
proc { |line_items| line_items.first.order.ship_address.andand.zipcode if rsa.call(line_items) },
|
||||
proc { |line_items| line_items.first.order.ship_address.andand.state if rsa.call(line_items) },
|
||||
|
||||
proc { |line_items| line_items.first.order.special_instructions }]
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| line_items.first.variant.product.sku },
|
||||
|
||||
proc { |line_items| line_items.first.order.order_cycle.andand.name },
|
||||
proc { |line_items| line_items.first.order.payments.first.andand.payment_method.andand.name },
|
||||
proc { |line_items| line_items.first.order.user.andand.customer_of(line_items.first.order.distributor).andand.code },
|
||||
proc { |line_items| "" },
|
||||
|
||||
proc { |line_items| line_items.first.order.bill_address.andand.address1 },
|
||||
proc { |line_items| line_items.first.order.bill_address.andand.address2 },
|
||||
proc { |line_items| line_items.first.order.bill_address.andand.city },
|
||||
proc { |line_items| line_items.first.order.bill_address.andand.zipcode },
|
||||
proc { |line_items| line_items.first.order.bill_address.andand.state } ]
|
||||
|
||||
rules = [ { group_by: proc { |line_item| line_item.order.distributor },
|
||||
sort_by: proc { |distributor| distributor.name } },
|
||||
{ group_by: proc { |line_item| line_item.order },
|
||||
sort_by: proc { |order| order.bill_address.lastname + " " + order.bill_address.firstname },
|
||||
summary_columns: [ proc { |line_items| line_items.first.order.distributor.name },
|
||||
summary_columns: [
|
||||
proc { |line_items| line_items.first.order.distributor.name },
|
||||
proc { |line_items| line_items.first.order.bill_address.firstname + " " + line_items.first.order.bill_address.lastname },
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "TOTAL" },
|
||||
proc { |line_items| "" },
|
||||
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| line_items.sum { |li| li.amount } },
|
||||
proc { |line_items| line_items.sum { |li| li.amount_with_adjustments } },
|
||||
@@ -576,13 +606,27 @@ Spree::Admin::ReportsController.class_eval do
|
||||
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" },
|
||||
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" },
|
||||
|
||||
proc { |line_items| "" } ] },
|
||||
proc { |line_items| line_items.first.order.special_instructions } ,
|
||||
proc { |line_items| "" },
|
||||
|
||||
proc { |line_items| line_items.first.order.order_cycle.andand.name },
|
||||
proc { |line_items| line_items.first.order.payments.first.andand.payment_method.andand.name },
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" },
|
||||
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" }
|
||||
] },
|
||||
|
||||
{ group_by: proc { |line_item| line_item.variant.product },
|
||||
sort_by: proc { |product| product.name } },
|
||||
|
||||
@@ -6,15 +6,18 @@ Spree::Admin::VariantsController.class_eval do
|
||||
|
||||
@variants = Spree::Variant.ransack(search_params.merge(:m => 'or')).result
|
||||
|
||||
if params[:distributor_id].present?
|
||||
distributor = Enterprise.find params[:distributor_id]
|
||||
@variants = @variants.in_distributor(distributor)
|
||||
end
|
||||
|
||||
if params[:order_cycle_id].present?
|
||||
order_cycle = OrderCycle.find params[:order_cycle_id]
|
||||
@variants = @variants.in_order_cycle(order_cycle)
|
||||
end
|
||||
|
||||
if params[:distributor_id].present?
|
||||
distributor = Enterprise.find params[:distributor_id]
|
||||
@variants = @variants.in_distributor(distributor)
|
||||
# Perform scoping after all filtering is done.
|
||||
# Filtering could be a problem on scoped variants.
|
||||
@variants.each { |v| v.scope_to_hub(distributor) }
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
|
||||
@@ -20,15 +20,6 @@ Spree::Api::ProductsController.class_eval do
|
||||
render_paged_products @products
|
||||
end
|
||||
|
||||
def distributable
|
||||
producers = OpenFoodNetwork::Permissions.new(current_api_user).
|
||||
order_cycle_enterprises.is_primary_producer.by_name
|
||||
|
||||
@products = paged_products_for_producers producers
|
||||
|
||||
render_paged_products @products
|
||||
end
|
||||
|
||||
def overridable
|
||||
producers = OpenFoodNetwork::Permissions.new(current_api_user).
|
||||
variant_override_producers.by_name
|
||||
@@ -74,7 +65,7 @@ Spree::Api::ProductsController.class_eval do
|
||||
end
|
||||
|
||||
def render_paged_products(products)
|
||||
render text: { products: ActiveModel::ArraySerializer.new(products, each_serializer: Spree::Api::ProductSerializer), pages: products.num_pages }.to_json
|
||||
render text: { products: ActiveModel::ArraySerializer.new(products, each_serializer: Api::Admin::ProductSerializer), pages: products.num_pages }.to_json
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
Spree::UserSessionsController.class_eval do
|
||||
before_filter :set_checkout_redirect, only: :create
|
||||
|
||||
def create
|
||||
authenticate_spree_user!
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
class UserPasswordsController < Spree::UserPasswordsController
|
||||
layout 'darkswarm'
|
||||
|
||||
before_filter :set_admin_redirect, only: :edit
|
||||
|
||||
def create
|
||||
self.resource = resource_class.send_reset_password_instructions(params[resource_name])
|
||||
|
||||
@@ -18,4 +20,10 @@ class UserPasswordsController < Spree::UserPasswordsController
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_admin_redirect
|
||||
session["spree_user_return_to"] = params[:return_to] if params[:return_to]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
class UserRegistrationsController < Spree::UserRegistrationsController
|
||||
before_filter :set_checkout_redirect, only: :create
|
||||
|
||||
# POST /resource/sign_up
|
||||
def create
|
||||
|
||||
@@ -47,7 +47,7 @@ module Admin
|
||||
end
|
||||
|
||||
def admin_inject_products
|
||||
admin_inject_json_ams_array "ofn.admin", "products", @products, Spree::Api::ProductSerializer
|
||||
admin_inject_json_ams_array "ofn.admin", "products", @products, Api::Admin::ProductSerializer
|
||||
end
|
||||
|
||||
def admin_inject_taxons
|
||||
|
||||
@@ -18,20 +18,24 @@ module CheckoutHelper
|
||||
end
|
||||
|
||||
def display_checkout_admin_and_handling_adjustments_total_for(order)
|
||||
adjustments = order.adjustments.eligible.where('originator_type = ? AND source_type != ? ', 'EnterpriseFee', 'Spree::LineItem' )
|
||||
Spree::Money.new( adjustments.sum( &:amount ) , { :currency => order.currency })
|
||||
adjustments = order.adjustments.eligible.where('originator_type = ? AND source_type != ? ', 'EnterpriseFee', 'Spree::LineItem')
|
||||
Spree::Money.new adjustments.sum(&:amount) , currency: order.currency
|
||||
end
|
||||
|
||||
def checkout_line_item_adjustments(order)
|
||||
order.adjustments.eligible.where( source_type: "Spree::LineItem")
|
||||
order.adjustments.eligible.where(source_type: "Spree::LineItem")
|
||||
end
|
||||
|
||||
def checkout_subtotal(order)
|
||||
order.item_total + checkout_line_item_adjustments(order).sum( &:amount )
|
||||
order.item_total + checkout_line_item_adjustments(order).sum(&:amount)
|
||||
end
|
||||
|
||||
def display_checkout_subtotal(order)
|
||||
Spree::Money.new( checkout_subtotal(order) , { :currency => order.currency })
|
||||
Spree::Money.new checkout_subtotal(order) , currency: order.currency
|
||||
end
|
||||
|
||||
def display_checkout_tax_total(order)
|
||||
Spree::Money.new order.total_tax, currency: order.currency
|
||||
end
|
||||
|
||||
def checkout_state_options(source_address)
|
||||
|
||||
@@ -21,6 +21,10 @@ module InjectionHelper
|
||||
inject_json_ams "taxons", Spree::Taxon.all, Api::TaxonSerializer
|
||||
end
|
||||
|
||||
def inject_properties
|
||||
inject_json_ams "properties", Spree::Property.all, Api::IdNameSerializer
|
||||
end
|
||||
|
||||
def inject_currency_config
|
||||
inject_json_ams "currencyConfig", {}, Api::CurrencyConfigSerializer
|
||||
end
|
||||
|
||||
@@ -3,36 +3,32 @@ module OrderCyclesHelper
|
||||
@current_order_cycle ||= current_order(false).andand.order_cycle
|
||||
end
|
||||
|
||||
def order_cycle_permitted_in(enterprises)
|
||||
enterprises.merge(order_cycle_permitted_enterprises)
|
||||
def permitted_enterprises_for(order_cycle)
|
||||
OpenFoodNetwork::OrderCyclePermissions.new(spree_current_user, order_cycle).visible_enterprises
|
||||
end
|
||||
|
||||
def order_cycle_permitted_enterprises
|
||||
OpenFoodNetwork::Permissions.new(spree_current_user).order_cycle_enterprises
|
||||
def permitted_producer_enterprises_for(order_cycle)
|
||||
permitted_enterprises_for(order_cycle).is_primary_producer.by_name
|
||||
end
|
||||
|
||||
def order_cycle_producer_enterprises
|
||||
order_cycle_permitted_enterprises.is_primary_producer.by_name
|
||||
def permitted_producer_enterprise_options_for(order_cycle)
|
||||
validated_enterprise_options permitted_producer_enterprises_for(order_cycle), confirmed: true
|
||||
end
|
||||
|
||||
def order_cycle_producer_enterprise_options
|
||||
validated_enterprise_options order_cycle_producer_enterprises, confirmed: true
|
||||
def permitted_coordinating_enterprises_for(order_cycle)
|
||||
Enterprise.managed_by(spree_current_user).is_distributor.by_name
|
||||
end
|
||||
|
||||
def order_cycle_coordinating_enterprises
|
||||
order_cycle_permitted_enterprises.is_distributor.by_name
|
||||
def permitted_coordinating_enterprise_options_for(order_cycle)
|
||||
validated_enterprise_options permitted_coordinating_enterprises_for(order_cycle), confirmed: true
|
||||
end
|
||||
|
||||
def order_cycle_coordinating_enterprise_options
|
||||
validated_enterprise_options order_cycle_coordinating_enterprises, confirmed: true
|
||||
def permitted_hub_enterprises_for(order_cycle)
|
||||
permitted_enterprises_for(order_cycle).is_hub.by_name
|
||||
end
|
||||
|
||||
def order_cycle_hub_enterprises
|
||||
order_cycle_permitted_enterprises.is_hub.by_name
|
||||
end
|
||||
|
||||
def order_cycle_hub_enterprise_options
|
||||
validated_enterprise_options order_cycle_hub_enterprises, confirmed: true, shipping_and_payment_methods: true
|
||||
def permitted_hub_enterprise_options_for(order_cycle)
|
||||
validated_enterprise_options permitted_hub_enterprises_for(order_cycle), confirmed: true, shipping_and_payment_methods: true
|
||||
end
|
||||
|
||||
def order_cycle_status_class(order_cycle)
|
||||
@@ -79,6 +75,14 @@ module OrderCyclesHelper
|
||||
order_cycle.exchanges.to_enterprises(current_distributor).outgoing.first.pickup_time
|
||||
end
|
||||
|
||||
def can_delete?(order_cycle)
|
||||
Spree::Order.where(order_cycle_id: order_cycle).none?
|
||||
end
|
||||
|
||||
def viewing_as_coordinator_of?(order_cycle)
|
||||
Enterprise.managed_by(spree_current_user).include? order_cycle.coordinator
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def validated_enterprise_options(enterprises, options={})
|
||||
|
||||
6
app/jobs/confirm_order_job.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
ConfirmOrderJob = Struct.new(:order_id) do
|
||||
def perform
|
||||
Spree::OrderMailer.confirm_email_for_customer(order_id).deliver
|
||||
Spree::OrderMailer.confirm_email_for_shop(order_id).deliver
|
||||
end
|
||||
end
|
||||
6
app/jobs/confirm_signup_job.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
ConfirmSignupJob = Struct.new(:user_id) do
|
||||
def perform
|
||||
user = Spree::User.find user_id
|
||||
Spree::UserMailer.signup_confirmation(user).deliver
|
||||
end
|
||||
end
|
||||
6
app/jobs/welcome_enterprise_job.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
WelcomeEnterpriseJob = Struct.new(:enterprise_id) do
|
||||
def perform
|
||||
enterprise = Enterprise.find enterprise_id
|
||||
EnterpriseMailer.welcome(enterprise).deliver
|
||||
end
|
||||
end
|
||||
@@ -1,7 +1,10 @@
|
||||
class Customer < ActiveRecord::Base
|
||||
belongs_to :enterprise
|
||||
belongs_to :user, :class_name => Spree.user_class
|
||||
|
||||
validates :code, presence: true, uniqueness: {scope: :enterprise_id}
|
||||
validates :email, presence: true
|
||||
validates :enterprise_id, presence: true
|
||||
|
||||
scope :of, ->(enterprise) { where(enterprise_id: enterprise) }
|
||||
end
|
||||
|
||||
@@ -8,6 +8,8 @@ class Enterprise < ActiveRecord::Base
|
||||
preference :shopfront_taxon_order, :string, default: ""
|
||||
|
||||
devise :confirmable, reconfirmable: true, confirmation_keys: [ :id, :email ]
|
||||
handle_asynchronously :send_confirmation_instructions
|
||||
handle_asynchronously :send_on_create_confirmation_instructions
|
||||
|
||||
self.inheritance_column = nil
|
||||
|
||||
@@ -15,6 +17,7 @@ class Enterprise < ActiveRecord::Base
|
||||
|
||||
has_and_belongs_to_many :groups, class_name: 'EnterpriseGroup'
|
||||
has_many :producer_properties, foreign_key: 'producer_id'
|
||||
has_many :properties, through: :producer_properties
|
||||
has_many :supplied_products, :class_name => 'Spree::Product', :foreign_key => 'supplier_id', :dependent => :destroy
|
||||
has_many :distributed_orders, :class_name => 'Spree::Order', :foreign_key => 'distributor_id'
|
||||
belongs_to :address, :class_name => 'Spree::Address'
|
||||
@@ -76,7 +79,7 @@ class Enterprise < ActiveRecord::Base
|
||||
after_rollback :restore_permalink
|
||||
|
||||
scope :by_name, order('name')
|
||||
scope :visible, where(:visible => true)
|
||||
scope :visible, where(visible: true)
|
||||
scope :confirmed, where('confirmed_at IS NOT NULL')
|
||||
scope :unconfirmed, where('confirmed_at IS NULL')
|
||||
scope :activated, where("confirmed_at IS NOT NULL AND sells != 'unspecified'")
|
||||
@@ -114,6 +117,9 @@ class Enterprise < ActiveRecord::Base
|
||||
scope :with_distributed_products_outer,
|
||||
joins('LEFT OUTER JOIN product_distributions ON product_distributions.distributor_id = enterprises.id').
|
||||
joins('LEFT OUTER JOIN spree_products ON spree_products.id = product_distributions.product_id')
|
||||
scope :with_order_cycles_as_supplier_outer,
|
||||
joins("LEFT OUTER JOIN exchanges ON (exchanges.sender_id = enterprises.id AND exchanges.incoming = 't')").
|
||||
joins('LEFT OUTER JOIN order_cycles ON (order_cycles.id = exchanges.order_cycle_id)')
|
||||
scope :with_order_cycles_as_distributor_outer,
|
||||
joins("LEFT OUTER JOIN exchanges ON (exchanges.receiver_id = enterprises.id AND exchanges.incoming = 'f')").
|
||||
joins('LEFT OUTER JOIN order_cycles ON (order_cycles.id = exchanges.order_cycle_id)')
|
||||
@@ -156,17 +162,6 @@ class Enterprise < ActiveRecord::Base
|
||||
end
|
||||
}
|
||||
|
||||
# Return enterprises that participate in order cycles that user coordinates, sends to or receives from
|
||||
scope :accessible_by, lambda { |user|
|
||||
if user.has_spree_role?('admin')
|
||||
scoped
|
||||
else
|
||||
with_order_cycles_outer.
|
||||
where('order_cycles.id IN (?)', OrderCycle.accessible_by(user)).
|
||||
select('DISTINCT enterprises.*')
|
||||
end
|
||||
}
|
||||
|
||||
def self.find_near(suburb)
|
||||
enterprises = []
|
||||
|
||||
@@ -316,6 +311,11 @@ class Enterprise < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
# Based on a devise method, but without adding errors
|
||||
def pending_any_confirmation?
|
||||
!confirmed? || pending_reconfirmation?
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def devise_mailer
|
||||
@@ -344,7 +344,7 @@ class Enterprise < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def send_welcome_email
|
||||
EnterpriseMailer.welcome(self).deliver
|
||||
Delayed::Job.enqueue WelcomeEnterpriseJob.new(self.id)
|
||||
end
|
||||
|
||||
def strip_url(url)
|
||||
@@ -378,13 +378,12 @@ class Enterprise < ActiveRecord::Base
|
||||
enterprises = owner.owned_enterprises.where('enterprises.id != ?', self)
|
||||
|
||||
# We grant permissions to all pre-existing hubs
|
||||
hub_permissions = [:add_to_order_cycle]
|
||||
hub_permissions << :create_variant_overrides if is_primary_producer
|
||||
enterprises.is_hub.each do |enterprise|
|
||||
EnterpriseRelationship.create!(parent: self,
|
||||
child: enterprise,
|
||||
permissions_list: [:add_to_order_cycle,
|
||||
:manage_products,
|
||||
:edit_profile,
|
||||
:create_variant_overrides])
|
||||
permissions_list: hub_permissions)
|
||||
end
|
||||
|
||||
# All pre-existing producers grant permission to new hubs
|
||||
@@ -393,8 +392,6 @@ class Enterprise < ActiveRecord::Base
|
||||
EnterpriseRelationship.create!(parent: enterprise,
|
||||
child: self,
|
||||
permissions_list: [:add_to_order_cycle,
|
||||
:manage_products,
|
||||
:edit_profile,
|
||||
:create_variant_overrides])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -20,6 +20,7 @@ class EnterpriseFee < ActiveRecord::Base
|
||||
|
||||
|
||||
scope :for_enterprise, lambda { |enterprise| where(enterprise_id: enterprise) }
|
||||
scope :for_enterprises, lambda { |enterprises| where(enterprise_id: enterprises) }
|
||||
|
||||
scope :managed_by, lambda { |user|
|
||||
if user.has_spree_role?('admin')
|
||||
|
||||
@@ -28,4 +28,8 @@ class EnterpriseRelationship < ActiveRecord::Base
|
||||
def permissions_list=(perms)
|
||||
perms.andand.each { |name| permissions.build name: name }
|
||||
end
|
||||
|
||||
def has_permission?(name)
|
||||
permissions.map(&:name).map(&:to_sym).include? name.to_sym
|
||||
end
|
||||
end
|
||||
|
||||
@@ -22,6 +22,7 @@ class Exchange < ActiveRecord::Base
|
||||
scope :to_enterprise, lambda { |enterprise| where(receiver_id: enterprise) }
|
||||
scope :from_enterprises, lambda { |enterprises| where('exchanges.sender_id IN (?)', enterprises) }
|
||||
scope :to_enterprises, lambda { |enterprises| where('exchanges.receiver_id IN (?)', enterprises) }
|
||||
scope :involving, lambda { |enterprises| where('exchanges.receiver_id IN (?) OR exchanges.sender_id IN (?)', enterprises, enterprises).select('DISTINCT exchanges.*') }
|
||||
scope :supplying_to, lambda { |distributor| where('exchanges.incoming OR exchanges.receiver_id = ?', distributor) }
|
||||
scope :with_variant, lambda { |variant| joins(:exchange_variants).where('exchange_variants.variant_id = ?', variant) }
|
||||
scope :with_any_variant, lambda { |variants| joins(:exchange_variants).where('exchange_variants.variant_id IN (?)', variants).select('DISTINCT exchanges.*') }
|
||||
|
||||
@@ -19,7 +19,14 @@ class OrderCycle < ActiveRecord::Base
|
||||
scope :undated, where(orders_open_at: nil, orders_close_at: nil)
|
||||
|
||||
scope :soonest_closing, lambda { active.order('order_cycles.orders_close_at ASC') }
|
||||
# TODO This method returns all the closed orders. So maybe we can replace it with :recently_closed.
|
||||
scope :most_recently_closed, lambda { closed.order('order_cycles.orders_close_at DESC') }
|
||||
|
||||
scope :recently_closed, -> {
|
||||
closed.
|
||||
where("order_cycles.orders_close_at >= ?", 31.days.ago).
|
||||
order("order_cycles.orders_close_at DESC") }
|
||||
|
||||
scope :soonest_opening, lambda { upcoming.order('order_cycles.orders_open_at ASC') }
|
||||
|
||||
scope :distributing_product, lambda { |product|
|
||||
@@ -57,6 +64,23 @@ class OrderCycle < ActiveRecord::Base
|
||||
joins('LEFT OUTER JOIN enterprises ON (enterprises.id = exchanges.sender_id OR enterprises.id = exchanges.receiver_id)')
|
||||
}
|
||||
|
||||
scope :involving_managed_distributors_of, lambda { |user|
|
||||
enterprises = Enterprise.managed_by(user)
|
||||
|
||||
# Order cycles where I managed an enterprise at either end of an outgoing exchange
|
||||
# ie. coordinator or distibutor
|
||||
joins(:exchanges).merge(Exchange.outgoing).
|
||||
where('exchanges.receiver_id IN (?) OR exchanges.sender_id IN (?)', enterprises, enterprises)
|
||||
}
|
||||
|
||||
scope :involving_managed_producers_of, lambda { |user|
|
||||
enterprises = Enterprise.managed_by(user)
|
||||
|
||||
# Order cycles where I managed an enterprise at either end of an incoming exchange
|
||||
# ie. coordinator or producer
|
||||
joins(:exchanges).merge(Exchange.incoming).
|
||||
where('exchanges.receiver_id IN (?) OR exchanges.sender_id IN (?)', enterprises, enterprises)
|
||||
}
|
||||
|
||||
def self.first_opening_for(distributor)
|
||||
with_distributor(distributor).soonest_opening.first
|
||||
|
||||
@@ -8,6 +8,7 @@ class AbilityDecorator
|
||||
add_enterprise_management_abilities user if can_manage_enterprises? user
|
||||
add_group_management_abilities user if can_manage_groups? user
|
||||
add_product_management_abilities user if can_manage_products? user
|
||||
add_order_cycle_management_abilities user if can_manage_order_cycles? user
|
||||
add_order_management_abilities user if can_manage_orders? user
|
||||
add_relationship_management_abilities user if can_manage_relationships? user
|
||||
end
|
||||
@@ -33,6 +34,13 @@ class AbilityDecorator
|
||||
user.enterprises.any? { |e| e.category != :hub_profile && e.producer_profile_only != true }
|
||||
end
|
||||
|
||||
# Users can manage order cycles if they manage a sells own/any enterprise
|
||||
# OR if they manage a producer which is included in any order cycles
|
||||
def can_manage_order_cycles?(user)
|
||||
can_manage_orders?(user) ||
|
||||
OrderCycle.accessible_by(user).any?
|
||||
end
|
||||
|
||||
# Users can manage orders if they have a sells own/any enterprise.
|
||||
def can_manage_orders?(user)
|
||||
( user.enterprises.map(&:sells) & %w(own any) ).any?
|
||||
@@ -95,7 +103,7 @@ class AbilityDecorator
|
||||
|
||||
can [:admin, :index, :read, :update, :bulk_update], VariantOverride do |vo|
|
||||
hub_auth = OpenFoodNetwork::Permissions.new(user).
|
||||
order_cycle_enterprises.is_distributor.
|
||||
variant_override_hubs.
|
||||
include? vo.hub
|
||||
|
||||
producer_auth = OpenFoodNetwork::Permissions.new(user).
|
||||
@@ -112,7 +120,18 @@ class AbilityDecorator
|
||||
can [:admin, :index, :read, :create, :edit], Spree::Classification
|
||||
|
||||
# Reports page
|
||||
can [:admin, :index, :customers, :orders_and_distributors, :group_buys, :bulk_coop, :payments, :orders_and_fulfillment, :products_and_inventory], :report
|
||||
can [:admin, :index, :customers, :orders_and_distributors, :group_buys, :bulk_coop, :payments, :orders_and_fulfillment, :products_and_inventory, :order_cycle_management], :report
|
||||
end
|
||||
|
||||
def add_order_cycle_management_abilities(user)
|
||||
can [:admin, :index, :read, :edit, :update], OrderCycle do |order_cycle|
|
||||
OrderCycle.accessible_by(user).include? order_cycle
|
||||
end
|
||||
can [:bulk_update, :clone, :destroy], OrderCycle do |order_cycle|
|
||||
user.enterprises.include? order_cycle.coordinator
|
||||
end
|
||||
can [:for_order_cycle], Enterprise
|
||||
can [:for_order_cycle], EnterpriseFee
|
||||
end
|
||||
|
||||
def add_order_management_abilities(user)
|
||||
@@ -125,17 +144,29 @@ class AbilityDecorator
|
||||
end
|
||||
can [:admin, :bulk_management], Spree::Order if user.admin? || user.enterprises.any?(&:is_distributor)
|
||||
can [:admin, :create], Spree::LineItem
|
||||
can [:destroy], Spree::LineItem do |item|
|
||||
user.admin? || user.enterprises.include?(order.distributor) || user == order.order_cycle.manager
|
||||
end
|
||||
|
||||
can [:admin, :index, :read, :create, :edit, :update, :fire], Spree::Payment
|
||||
can [:admin, :index, :read, :create, :edit, :update, :fire], Spree::Shipment
|
||||
can [:admin, :index, :read, :create, :edit, :update, :fire], Spree::Adjustment
|
||||
can [:admin, :index, :read, :create, :edit, :update, :fire], Spree::ReturnAuthorization
|
||||
can [:destroy], Spree::Adjustment do |adjustment|
|
||||
# Sharing code with destroying a line item. This should be unified and probably applied for other actions as well.
|
||||
binding.pry
|
||||
if user.admin?
|
||||
true
|
||||
elsif adjustment.adjustable.instance_of? Spree::Order
|
||||
order = adjustment.adjustable
|
||||
user.enterprises.include?(order.distributor) || user == order.order_cycle.manager
|
||||
elsif adjustment.adjustable.instance_of? Spree::LineItem
|
||||
order = adjustment.adjustable.order
|
||||
user.enterprises.include?(order.distributor) || user == order.order_cycle.manager
|
||||
end
|
||||
end
|
||||
|
||||
can [:create], OrderCycle
|
||||
can [:admin, :index, :read, :edit, :update, :bulk_update, :clone], OrderCycle do |order_cycle|
|
||||
user.enterprises.include? order_cycle.coordinator
|
||||
end
|
||||
can [:for_order_cycle], Enterprise
|
||||
|
||||
can [:admin, :index, :read, :create, :edit, :update], ExchangeVariant
|
||||
can [:admin, :index, :read, :create, :edit, :update], Exchange
|
||||
|
||||
@@ -26,6 +26,7 @@ Spree::LineItem.class_eval do
|
||||
def price_with_adjustments
|
||||
# EnterpriseFee#create_locked_adjustment applies adjustments on line items to their parent order,
|
||||
# so line_item.adjustments returns an empty array
|
||||
return 0 if quantity == 0
|
||||
(price + order.adjustments.where(source_id: id).sum(&:amount) / quantity).round(2)
|
||||
end
|
||||
|
||||
|
||||
@@ -103,13 +103,17 @@ Spree::Order.class_eval do
|
||||
def add_variant(variant, quantity = 1, max_quantity = nil, currency = nil)
|
||||
line_items(:reload)
|
||||
current_item = find_line_item_by_variant(variant)
|
||||
if current_item
|
||||
Bugsnag.notify(RuntimeError.new("Order populator weirdness"), {
|
||||
|
||||
# Notify bugsnag if we get line items with a quantity of zero
|
||||
if quantity == 0
|
||||
Bugsnag.notify(RuntimeError.new("Zero Quantity Line Item"), {
|
||||
current_item: current_item.as_json,
|
||||
line_items: line_items.map(&:id),
|
||||
reloaded: line_items(:reload).map(&:id),
|
||||
variant: variant.as_json
|
||||
})
|
||||
end
|
||||
|
||||
if current_item
|
||||
current_item.quantity = quantity
|
||||
current_item.max_quantity = max_quantity
|
||||
|
||||
@@ -194,20 +198,37 @@ Spree::Order.class_eval do
|
||||
end
|
||||
end
|
||||
|
||||
# Does this order have shipments that can be shipped?
|
||||
def ready_to_ship?
|
||||
self.shipments.any?{|s| s.can_ship?}
|
||||
end
|
||||
|
||||
# Ship all pending orders
|
||||
def ship
|
||||
self.shipments.each do |s|
|
||||
s.ship if s.can_ship?
|
||||
end
|
||||
end
|
||||
|
||||
def available_shipping_methods(display_on = nil)
|
||||
Spree::ShippingMethod.all_available(self, display_on)
|
||||
end
|
||||
|
||||
def shipping_tax
|
||||
adjustments(:reload).shipping.sum &:included_tax
|
||||
end
|
||||
|
||||
def enterprise_fee_tax
|
||||
adjustments(:reload).enterprise_fee.sum &:included_tax
|
||||
end
|
||||
|
||||
def total_tax
|
||||
(adjustments + price_adjustments).sum &:included_tax
|
||||
end
|
||||
|
||||
# Overrride of Spree method, that allows us to send separate confirmation emails to user and shop owners
|
||||
def deliver_order_confirmation_email
|
||||
begin
|
||||
Spree::OrderMailer.confirm_email_for_customer(self.id).deliver
|
||||
Spree::OrderMailer.confirm_email_for_shop(self.id).deliver
|
||||
rescue Exception => e
|
||||
Bugsnag.notify(e)
|
||||
logger.error("#{e.class.name}: #{e.message}")
|
||||
logger.error(e.backtrace * "\n")
|
||||
end
|
||||
Delayed::Job.enqueue ConfirmOrderJob.new(id)
|
||||
end
|
||||
|
||||
|
||||
|
||||
52
app/models/spree/payment_decorator.rb
Normal file
@@ -0,0 +1,52 @@
|
||||
module Spree
|
||||
Payment.class_eval do
|
||||
# Pin payments lacks void and credit methods, but it does have refund
|
||||
# Here we swap credit out for refund and remove void as a possible action
|
||||
def actions_with_pin_payment_adaptations
|
||||
actions = actions_without_pin_payment_adaptations
|
||||
if payment_method.is_a? Gateway::Pin
|
||||
actions << 'refund' if actions.include? 'credit'
|
||||
actions.reject! { |a| ['credit', 'void'].include? a }
|
||||
end
|
||||
actions
|
||||
end
|
||||
alias_method_chain :actions, :pin_payment_adaptations
|
||||
|
||||
|
||||
def refund!(refund_amount=nil)
|
||||
protect_from_connection_error do
|
||||
check_environment
|
||||
|
||||
refund_amount = calculate_refund_amount(refund_amount)
|
||||
|
||||
if payment_method.payment_profiles_supported?
|
||||
response = payment_method.refund((refund_amount * 100).round, source, response_code, gateway_options)
|
||||
else
|
||||
response = payment_method.refund((refund_amount * 100).round, response_code, gateway_options)
|
||||
end
|
||||
|
||||
record_response(response)
|
||||
|
||||
if response.success?
|
||||
self.class.create({ :order => order,
|
||||
:source => self,
|
||||
:payment_method => payment_method,
|
||||
:amount => refund_amount.abs * -1,
|
||||
:response_code => response.authorization,
|
||||
:state => 'completed' }, :without_protection => true)
|
||||
else
|
||||
gateway_error(response)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def calculate_refund_amount(refund_amount=nil)
|
||||
refund_amount ||= credit_allowed >= order.outstanding_balance.abs ? order.outstanding_balance.abs : credit_allowed.abs
|
||||
refund_amount.to_f
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -18,14 +18,16 @@ Spree::Product.class_eval do
|
||||
delegate_belongs_to :master, :unit_value, :unit_description
|
||||
delegate :images_attributes=, :display_as=, to: :master
|
||||
|
||||
attr_accessible :supplier_id, :primary_taxon_id, :distributor_ids, :product_distributions_attributes, :group_buy, :group_buy_unit_size
|
||||
attr_accessible :variant_unit, :variant_unit_scale, :variant_unit_name, :unit_value, :unit_description, :notes, :images_attributes, :display_as
|
||||
attr_accessible :supplier_id, :primary_taxon_id, :distributor_ids, :product_distributions_attributes
|
||||
attr_accessible :group_buy, :group_buy_unit_size, :unit_description, :notes, :images_attributes, :display_as
|
||||
attr_accessible :variant_unit, :variant_unit_scale, :variant_unit_name, :unit_value
|
||||
attr_accessible :inherits_properties, :sku
|
||||
|
||||
validates_associated :master, message: "^Price and On Hand must be valid"
|
||||
validates_presence_of :supplier
|
||||
validates :primary_taxon, presence: { message: "^Product Category can't be blank" }
|
||||
validates :tax_category_id, presence: { message: "^Tax Category can't be blank" }, if: "Spree::Config.products_require_tax_category"
|
||||
|
||||
|
||||
validates_presence_of :variant_unit, if: :has_variants?
|
||||
validates_presence_of :variant_unit_scale,
|
||||
if: -> p { %w(weight volume).include? p.variant_unit }
|
||||
@@ -106,19 +108,21 @@ Spree::Product.class_eval do
|
||||
|
||||
# -- Methods
|
||||
|
||||
def properties_h
|
||||
def properties_including_inherited
|
||||
# Product properties override producer properties
|
||||
ps = supplier.producer_properties.inject(product_properties) do |properties, property|
|
||||
if properties.find { |p| p.property.presentation == property.property.presentation }
|
||||
properties
|
||||
else
|
||||
properties + [property]
|
||||
ps = product_properties.all
|
||||
|
||||
if inherits_properties
|
||||
supplier.producer_properties.each do |producer_property|
|
||||
unless ps.find { |product_property| product_property.property.presentation == producer_property.property.presentation }
|
||||
ps << producer_property
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ps.
|
||||
sort_by { |pp| pp.position }.
|
||||
map { |pp| {presentation: pp.property.presentation, value: pp.value} }
|
||||
map { |pp| {id: pp.property.id, name: pp.property.presentation, value: pp.value} }
|
||||
end
|
||||
|
||||
def in_distributor?(distributor)
|
||||
|
||||
@@ -3,7 +3,11 @@ module Spree
|
||||
def ensure_correct_adjustment_with_included_tax
|
||||
ensure_correct_adjustment_without_included_tax
|
||||
|
||||
adjustment.set_included_tax! Config.shipping_tax_rate if Config.shipment_inc_vat
|
||||
if Config.shipment_inc_vat && (order.distributor.nil? || order.distributor.charges_sales_tax)
|
||||
adjustment.set_included_tax! Config.shipping_tax_rate
|
||||
else
|
||||
adjustment.set_included_tax! 0
|
||||
end
|
||||
end
|
||||
|
||||
alias_method_chain :ensure_correct_adjustment, :included_tax
|
||||
|
||||