mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-12 18:36:49 +00:00
Compare commits
173 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df7dd557b5 | ||
|
|
88508c254b | ||
|
|
8f682a6d07 | ||
|
|
c5e8ac6fd1 | ||
|
|
3e2d31d432 | ||
|
|
4ce7525748 | ||
|
|
7cc1c97c53 | ||
|
|
ccfe6bc0b3 | ||
|
|
5e2fbcb874 | ||
|
|
5b22cce950 | ||
|
|
fec81b7ed4 | ||
|
|
f2f3bbd3ed | ||
|
|
83e3c6815d | ||
|
|
3f71655bd1 | ||
|
|
662aaf75bf | ||
|
|
f7890bd94d | ||
|
|
6a45e8be3b | ||
|
|
c75738893e | ||
|
|
074d5715e7 | ||
|
|
87d5ffeee2 | ||
|
|
9a03a58d9e | ||
|
|
ae93d02c9c | ||
|
|
d8a7570a61 | ||
|
|
a293ea54f9 | ||
|
|
33b9d45f43 | ||
|
|
0a2ce30bb6 | ||
|
|
1a0ef85030 | ||
|
|
983ba92dea | ||
|
|
487247f6e7 | ||
|
|
05c9a189c8 | ||
|
|
43a1cf7779 | ||
|
|
12dad2468d | ||
|
|
8f17df0e45 | ||
|
|
8e9845be12 | ||
|
|
3991199c30 | ||
|
|
8f05c69696 | ||
|
|
f3f0f37716 | ||
|
|
850d65958b | ||
|
|
488fc2d60e | ||
|
|
a10eb0d0c7 | ||
|
|
9e59dead07 | ||
|
|
d3fca565a3 | ||
|
|
f971958042 | ||
|
|
3e06220b7f | ||
|
|
3694321f66 | ||
|
|
24a48a9b33 | ||
|
|
bb13ec0e02 | ||
|
|
d3189e333b | ||
|
|
a9fb10b0ca | ||
|
|
3186b703a2 | ||
|
|
e46d61075e | ||
|
|
4e78fa19a3 | ||
|
|
31ea8540ea | ||
|
|
d27ef76ead | ||
|
|
5129e31f21 | ||
|
|
c5d031a6d7 | ||
|
|
c7d3b9ee1a | ||
|
|
62a7a0db7c | ||
|
|
f8c74e8b92 | ||
|
|
e53fff8e31 | ||
|
|
ba19db3ccf | ||
|
|
04297d928e | ||
|
|
1d357af708 | ||
|
|
6a666dd7ec | ||
|
|
f705926c72 | ||
|
|
7ae315a1cb | ||
|
|
836f568b8e | ||
|
|
043e67fd9d | ||
|
|
6ca56cbb94 | ||
|
|
63cf128f86 | ||
|
|
1f8b4d185b | ||
|
|
c7ac0f7d91 | ||
|
|
8a37b4e918 | ||
|
|
19e55428b8 | ||
|
|
8d8c2f04d8 | ||
|
|
bec10be233 | ||
|
|
2382de946f | ||
|
|
fc34c9c804 | ||
|
|
0f5d51423b | ||
|
|
91e3ddb93c | ||
|
|
8cfce57730 | ||
|
|
9c9431ca7f | ||
|
|
3a3f427a8d | ||
|
|
b5a95e73dc | ||
|
|
9cf6124df3 | ||
|
|
46abc2fc42 | ||
|
|
0a6686b592 | ||
|
|
55423d2df1 | ||
|
|
e9746ebc9b | ||
|
|
505f33a3f7 | ||
|
|
1d4d7d064b | ||
|
|
a4d3cc5417 | ||
|
|
3080454b25 | ||
|
|
cd13ab4f77 | ||
|
|
9880c45313 | ||
|
|
5afb2bb8f9 | ||
|
|
aefa06b67d | ||
|
|
7d84803bad | ||
|
|
fee64a5764 | ||
|
|
34ef8a1deb | ||
|
|
c055a3c594 | ||
|
|
a0c40607ec | ||
|
|
25a2732253 | ||
|
|
97401ca370 | ||
|
|
71320aa977 | ||
|
|
8e4b729351 | ||
|
|
07eac918a3 | ||
|
|
cfa96c7615 | ||
|
|
5655b0b7a5 | ||
|
|
34120730cd | ||
|
|
31735d3d10 | ||
|
|
ba3a595af2 | ||
|
|
6e4638b12d | ||
|
|
145fed09a1 | ||
|
|
8736254f12 | ||
|
|
2c8d313c77 | ||
|
|
243e1ccd93 | ||
|
|
ac66bf4871 | ||
|
|
64d4e405dd | ||
|
|
aacc36ea44 | ||
|
|
ef22168349 | ||
|
|
43248aee99 | ||
|
|
a19e697556 | ||
|
|
5103ce64ba | ||
|
|
d5310452b6 | ||
|
|
47c28e65a7 | ||
|
|
6b97872a25 | ||
|
|
7a6d930706 | ||
|
|
7c5dcd6a90 | ||
|
|
6106f1b469 | ||
|
|
59af447739 | ||
|
|
d502705362 | ||
|
|
5ae13d6156 | ||
|
|
c46b858563 | ||
|
|
5e0a5654ff | ||
|
|
58a79e9b0c | ||
|
|
ee482d520c | ||
|
|
3d025bb709 | ||
|
|
52ebe2c495 | ||
|
|
fd0cc93e68 | ||
|
|
2a645d04ae | ||
|
|
b7bd21e498 | ||
|
|
873937db47 | ||
|
|
e64a86f5be | ||
|
|
ad76e66944 | ||
|
|
216125c7a1 | ||
|
|
d6802d9ae5 | ||
|
|
58917fe378 | ||
|
|
2786791c39 | ||
|
|
e2b0770c35 | ||
|
|
b34d9da8e5 | ||
|
|
e388e82d50 | ||
|
|
dd155532f8 | ||
|
|
63ba5d13a3 | ||
|
|
fa2addd025 | ||
|
|
77b78f5bbb | ||
|
|
bcc2ef99fd | ||
|
|
a4d10ab4e0 | ||
|
|
ff0d2bc983 | ||
|
|
cbfb896ca4 | ||
|
|
59ca8f4513 | ||
|
|
0d99d9d18f | ||
|
|
573ba9c8d4 | ||
|
|
98143ffe5b | ||
|
|
32acba05a3 | ||
|
|
6247bd2541 | ||
|
|
03764881c8 | ||
|
|
ec74396659 | ||
|
|
192d4993a1 | ||
|
|
9cb5ac95ff | ||
|
|
076c64f7b0 | ||
|
|
7da595afbd | ||
|
|
01569c2550 |
9
Gemfile
9
Gemfile
@@ -1,13 +1,13 @@
|
||||
source 'http://rubygems.org'
|
||||
ruby "1.9.3"
|
||||
|
||||
gem 'rails', '3.2.8'
|
||||
gem 'rails', '3.2.11'
|
||||
|
||||
gem 'pg'
|
||||
gem 'spree', :git => 'git://github.com/spree/spree.git', :branch => '1-1-stable'
|
||||
gem 'spree_i18n', :git => 'git://github.com/spree/spree_i18n.git'
|
||||
gem 'spree_paypal_express', :git => 'git://github.com/eaterprises/spree_paypal_express.git', :branch => '1-1-stable'
|
||||
gem 'spree_last_address', :git => 'git://github.com/dancinglightning/spree-last-address.git'
|
||||
gem 'spree_last_address', :git => 'git://github.com/eaterprises/spree-last-address.git'
|
||||
|
||||
gem 'comfortable_mexican_sofa'
|
||||
|
||||
@@ -17,11 +17,14 @@ gem 'simple_form', :git => 'git://github.com/RohanM/simple_form.git'
|
||||
|
||||
gem 'unicorn'
|
||||
gem 'bugsnag'
|
||||
gem 'newrelic_rpm'
|
||||
gem 'spree_heroku', :git => 'git://github.com/eaterprises/spree-heroku.git'
|
||||
gem 'haml'
|
||||
gem 'aws-sdk'
|
||||
gem 'db2fog'
|
||||
gem 'andand'
|
||||
gem 'truncate_html'
|
||||
gem 'representative_view'
|
||||
|
||||
# Gems used only for assets and not required
|
||||
# in production environments by default.
|
||||
@@ -38,6 +41,7 @@ end
|
||||
gem 'jquery-rails'
|
||||
|
||||
|
||||
|
||||
group :test, :development do
|
||||
# Pretty printed test output
|
||||
gem 'turn', '~> 0.8.3', :require => false
|
||||
@@ -50,5 +54,6 @@ group :test, :development do
|
||||
gem 'spork', '~> 1.0rc'
|
||||
gem 'pry-debugger'
|
||||
gem 'awesome_print'
|
||||
gem "letter_opener"
|
||||
end
|
||||
|
||||
|
||||
210
Gemfile.lock
210
Gemfile.lock
@@ -6,13 +6,6 @@ GIT
|
||||
actionpack (~> 3.0)
|
||||
activemodel (~> 3.0)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/dancinglightning/spree-last-address.git
|
||||
revision: f5ed71a5482fbc16da559737903bb46fe032c150
|
||||
specs:
|
||||
spree_last_address (1.1.0)
|
||||
spree_core (>= 1.1)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/eaterprises/spree-heroku.git
|
||||
revision: a1e07bf7a22fc0c07a1be9148f477d20b557dbf6
|
||||
@@ -21,6 +14,13 @@ GIT
|
||||
aws-sdk (~> 1.3.4)
|
||||
spree_core (>= 0.70.0)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/eaterprises/spree-last-address.git
|
||||
revision: f5ed71a5482fbc16da559737903bb46fe032c150
|
||||
specs:
|
||||
spree_last_address (1.1.0)
|
||||
spree_core (>= 1.1)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/eaterprises/spree_paypal_express.git
|
||||
revision: 7dd46e6e549d82c4d603f685a7cb7fbb4af0d973
|
||||
@@ -32,28 +32,28 @@ GIT
|
||||
|
||||
GIT
|
||||
remote: git://github.com/spree/spree.git
|
||||
revision: 46691e075129fd3d7b59e296d73149a9066c1b9d
|
||||
revision: 11dcee754d6c07897eabd26db3e7bcb14ffb595d
|
||||
branch: 1-1-stable
|
||||
specs:
|
||||
spree (1.1.3)
|
||||
spree_api (= 1.1.3)
|
||||
spree_auth (= 1.1.3)
|
||||
spree_cmd (= 1.1.3)
|
||||
spree_core (= 1.1.3)
|
||||
spree_dash (= 1.1.3)
|
||||
spree_promo (= 1.1.3)
|
||||
spree_sample (= 1.1.3)
|
||||
spree_api (1.1.3)
|
||||
spree (1.1.6.beta)
|
||||
spree_api (= 1.1.6.beta)
|
||||
spree_auth (= 1.1.6.beta)
|
||||
spree_cmd (= 1.1.6.beta)
|
||||
spree_core (= 1.1.6.beta)
|
||||
spree_dash (= 1.1.6.beta)
|
||||
spree_promo (= 1.1.6.beta)
|
||||
spree_sample (= 1.1.6.beta)
|
||||
spree_api (1.1.6.beta)
|
||||
rabl (= 0.6.5)
|
||||
spree_auth (= 1.1.3)
|
||||
spree_core (= 1.1.3)
|
||||
spree_auth (1.1.3)
|
||||
spree_auth (= 1.1.6.beta)
|
||||
spree_core (= 1.1.6.beta)
|
||||
spree_auth (1.1.6.beta)
|
||||
cancan (= 1.6.7)
|
||||
devise (~> 2.0.0)
|
||||
spree_core (= 1.1.3)
|
||||
spree_cmd (1.1.3)
|
||||
spree_core (= 1.1.6.beta)
|
||||
spree_cmd (1.1.6.beta)
|
||||
thor (>= 0.14.6)
|
||||
spree_core (1.1.3)
|
||||
spree_core (1.1.6.beta)
|
||||
activemerchant (= 1.28.0)
|
||||
acts_as_list (= 0.1.4)
|
||||
aws-sdk (~> 1.3.4)
|
||||
@@ -62,21 +62,22 @@ GIT
|
||||
highline (= 1.6.11)
|
||||
jquery-rails (~> 2.0)
|
||||
kaminari (= 0.13.0)
|
||||
money (= 5.0.0)
|
||||
nested_set (= 1.7.0)
|
||||
paperclip (~> 2.8)
|
||||
rails (~> 3.2.8)
|
||||
rails (~> 3.2.11)
|
||||
ransack (~> 0.6.0)
|
||||
state_machine (= 1.1.2)
|
||||
stringex (~> 1.3.2)
|
||||
spree_dash (1.1.3)
|
||||
spree_dash (1.1.6.beta)
|
||||
httparty (~> 0.8.1)
|
||||
spree_auth (= 1.1.3)
|
||||
spree_core (= 1.1.3)
|
||||
spree_promo (1.1.3)
|
||||
spree_auth (= 1.1.3)
|
||||
spree_core (= 1.1.3)
|
||||
spree_sample (1.1.3)
|
||||
spree_core (= 1.1.3)
|
||||
spree_auth (= 1.1.6.beta)
|
||||
spree_core (= 1.1.6.beta)
|
||||
spree_promo (1.1.6.beta)
|
||||
spree_auth (= 1.1.6.beta)
|
||||
spree_core (= 1.1.6.beta)
|
||||
spree_sample (1.1.6.beta)
|
||||
spree_core (= 1.1.6.beta)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/spree/spree_i18n.git
|
||||
@@ -89,19 +90,19 @@ GIT
|
||||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
actionmailer (3.2.8)
|
||||
actionpack (= 3.2.8)
|
||||
actionmailer (3.2.11)
|
||||
actionpack (= 3.2.11)
|
||||
mail (~> 2.4.4)
|
||||
actionpack (3.2.8)
|
||||
activemodel (= 3.2.8)
|
||||
activesupport (= 3.2.8)
|
||||
actionpack (3.2.11)
|
||||
activemodel (= 3.2.11)
|
||||
activesupport (= 3.2.11)
|
||||
builder (~> 3.0.0)
|
||||
erubis (~> 2.7.0)
|
||||
journey (~> 1.0.4)
|
||||
rack (~> 1.4.0)
|
||||
rack-cache (~> 1.2)
|
||||
rack-test (~> 0.6.1)
|
||||
sprockets (~> 2.1.3)
|
||||
sprockets (~> 2.2.1)
|
||||
active_link_to (1.0.0)
|
||||
active_utils (1.0.5)
|
||||
activesupport (>= 2.3.11)
|
||||
@@ -114,18 +115,18 @@ GEM
|
||||
json (>= 1.5.1)
|
||||
money
|
||||
nokogiri
|
||||
activemodel (3.2.8)
|
||||
activesupport (= 3.2.8)
|
||||
activemodel (3.2.11)
|
||||
activesupport (= 3.2.11)
|
||||
builder (~> 3.0.0)
|
||||
activerecord (3.2.8)
|
||||
activemodel (= 3.2.8)
|
||||
activesupport (= 3.2.8)
|
||||
activerecord (3.2.11)
|
||||
activemodel (= 3.2.11)
|
||||
activesupport (= 3.2.11)
|
||||
arel (~> 3.0.2)
|
||||
tzinfo (~> 0.3.29)
|
||||
activeresource (3.2.8)
|
||||
activemodel (= 3.2.8)
|
||||
activesupport (= 3.2.8)
|
||||
activesupport (3.2.8)
|
||||
activeresource (3.2.11)
|
||||
activemodel (= 3.2.11)
|
||||
activesupport (= 3.2.11)
|
||||
activesupport (3.2.11)
|
||||
i18n (~> 0.6)
|
||||
multi_json (~> 1.0)
|
||||
acts_as_list (0.1.4)
|
||||
@@ -140,21 +141,24 @@ GEM
|
||||
nokogiri (>= 1.4.4)
|
||||
uuidtools (~> 2.1)
|
||||
bcrypt-ruby (3.0.1)
|
||||
bugsnag (1.2.4)
|
||||
httparty (>= 0.5, < 1.0)
|
||||
bugsnag (1.2.12)
|
||||
httparty (>= 0.6, < 1.0)
|
||||
multi_json (~> 1.0)
|
||||
builder (3.0.4)
|
||||
cancan (1.6.7)
|
||||
capybara (1.1.3)
|
||||
capybara (2.0.2)
|
||||
mime-types (>= 1.16)
|
||||
nokogiri (>= 1.3.3)
|
||||
rack (>= 1.0.0)
|
||||
rack-test (>= 0.5.4)
|
||||
selenium-webdriver (~> 2.0)
|
||||
xpath (~> 0.1.4)
|
||||
xpath (~> 1.0.0)
|
||||
childprocess (0.3.6)
|
||||
ffi (~> 1.0, >= 1.0.6)
|
||||
cocaine (0.4.2)
|
||||
climate_control (0.0.3)
|
||||
activesupport (>= 3.0)
|
||||
cocaine (0.5.1)
|
||||
climate_control (>= 0.0.3, < 1.0)
|
||||
coderay (1.0.7)
|
||||
coffee-rails (3.2.2)
|
||||
coffee-script (>= 2.2.0)
|
||||
@@ -169,6 +173,10 @@ GEM
|
||||
paperclip (>= 2.3.0)
|
||||
rails (>= 3.0.0)
|
||||
database_cleaner (0.7.1)
|
||||
db2fog (0.7.0)
|
||||
activerecord (~> 3.0)
|
||||
fog (~> 1.0)
|
||||
rails (~> 3.0)
|
||||
debugger (1.1.4)
|
||||
columnize (>= 0.3.1)
|
||||
debugger-linecache (~> 1.1.1)
|
||||
@@ -179,13 +187,14 @@ GEM
|
||||
deface (0.9.1)
|
||||
nokogiri (~> 1.5.0)
|
||||
rails (~> 3.1)
|
||||
devise (2.0.4)
|
||||
devise (2.0.5)
|
||||
bcrypt-ruby (~> 3.0)
|
||||
orm_adapter (~> 0.0.3)
|
||||
railties (~> 3.1)
|
||||
warden (~> 1.1.1)
|
||||
diff-lcs (1.1.3)
|
||||
erubis (2.7.0)
|
||||
excon (0.16.2)
|
||||
execjs (1.4.0)
|
||||
multi_json (~> 1.0)
|
||||
factory_girl (3.3.0)
|
||||
@@ -196,7 +205,18 @@ GEM
|
||||
faker (1.0.1)
|
||||
i18n (~> 0.4)
|
||||
ffaker (1.12.1)
|
||||
ffi (1.1.5)
|
||||
ffi (1.7.0)
|
||||
fog (1.5.0)
|
||||
builder
|
||||
excon (~> 0.14)
|
||||
formatador (~> 0.2.0)
|
||||
mime-types
|
||||
multi_json (~> 1.0)
|
||||
net-scp (~> 1.0.4)
|
||||
net-ssh (>= 2.1.3)
|
||||
nokogiri (~> 1.5.0)
|
||||
ruby-hmac
|
||||
formatador (0.2.3)
|
||||
haml (3.1.6)
|
||||
highline (1.6.11)
|
||||
hike (1.2.1)
|
||||
@@ -205,33 +225,42 @@ GEM
|
||||
multi_xml
|
||||
i18n (0.6.1)
|
||||
journey (1.0.4)
|
||||
jquery-rails (2.1.3)
|
||||
railties (>= 3.1.0, < 5.0)
|
||||
thor (~> 0.14)
|
||||
json (1.7.5)
|
||||
jquery-rails (2.2.1)
|
||||
railties (>= 3.0, < 5.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
json (1.7.7)
|
||||
kaminari (0.13.0)
|
||||
actionpack (>= 3.0.0)
|
||||
activesupport (>= 3.0.0)
|
||||
railties (>= 3.0.0)
|
||||
kgio (2.7.4)
|
||||
launchy (2.1.2)
|
||||
addressable (~> 2.3)
|
||||
letter_opener (1.0.0)
|
||||
launchy (>= 2.0.4)
|
||||
libv8 (3.3.10.4)
|
||||
libwebsocket (0.1.5)
|
||||
libwebsocket (0.1.7.1)
|
||||
addressable
|
||||
websocket
|
||||
mail (2.4.4)
|
||||
i18n (>= 0.4.0)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
method_source (0.8)
|
||||
mime-types (1.19)
|
||||
mime-types (1.21)
|
||||
money (5.0.0)
|
||||
i18n (~> 0.4)
|
||||
json
|
||||
multi_json (1.3.6)
|
||||
multi_xml (0.5.1)
|
||||
multi_json (1.5.1)
|
||||
multi_xml (0.5.3)
|
||||
nested_set (1.7.0)
|
||||
activerecord (>= 3.0.0)
|
||||
railties (>= 3.0.0)
|
||||
nokogiri (1.5.5)
|
||||
net-scp (1.0.4)
|
||||
net-ssh (>= 1.99.1)
|
||||
net-ssh (2.5.2)
|
||||
newrelic_rpm (3.6.0.83)
|
||||
nokogiri (1.5.6)
|
||||
orm_adapter (0.0.7)
|
||||
paperclip (2.8.0)
|
||||
activerecord (>= 2.3.0)
|
||||
@@ -252,36 +281,44 @@ GEM
|
||||
rabl (0.6.5)
|
||||
activesupport (>= 2.3.14)
|
||||
multi_json (~> 1.0)
|
||||
rack (1.4.1)
|
||||
rack (1.4.5)
|
||||
rack-cache (1.2)
|
||||
rack (>= 0.4)
|
||||
rack-ssl (1.3.2)
|
||||
rack-ssl (1.3.3)
|
||||
rack
|
||||
rack-test (0.6.2)
|
||||
rack (>= 1.0)
|
||||
rails (3.2.8)
|
||||
actionmailer (= 3.2.8)
|
||||
actionpack (= 3.2.8)
|
||||
activerecord (= 3.2.8)
|
||||
activeresource (= 3.2.8)
|
||||
activesupport (= 3.2.8)
|
||||
rails (3.2.11)
|
||||
actionmailer (= 3.2.11)
|
||||
actionpack (= 3.2.11)
|
||||
activerecord (= 3.2.11)
|
||||
activeresource (= 3.2.11)
|
||||
activesupport (= 3.2.11)
|
||||
bundler (~> 1.0)
|
||||
railties (= 3.2.8)
|
||||
railties (3.2.8)
|
||||
actionpack (= 3.2.8)
|
||||
activesupport (= 3.2.8)
|
||||
railties (= 3.2.11)
|
||||
railties (3.2.11)
|
||||
actionpack (= 3.2.11)
|
||||
activesupport (= 3.2.11)
|
||||
rack-ssl (~> 1.3.2)
|
||||
rake (>= 0.8.7)
|
||||
rdoc (~> 3.4)
|
||||
thor (>= 0.14.6, < 2.0)
|
||||
raindrops (0.9.0)
|
||||
rake (0.9.2.2)
|
||||
rake (10.0.3)
|
||||
ransack (0.6.0)
|
||||
actionpack (~> 3.0)
|
||||
activerecord (~> 3.0)
|
||||
polyamorous (~> 0.5.0)
|
||||
rdoc (3.12)
|
||||
rdoc (3.12.1)
|
||||
json (~> 1.4)
|
||||
representative (1.0.5)
|
||||
activesupport (>= 2.2.2)
|
||||
builder (>= 2.1.2)
|
||||
i18n (>= 0.4.1)
|
||||
nokogiri (>= 1.4.2)
|
||||
representative_view (1.2.2)
|
||||
actionpack (> 2.3.0, < 4.0.0)
|
||||
representative (~> 1.0.2)
|
||||
rspec (2.10.0)
|
||||
rspec-core (~> 2.10.0)
|
||||
rspec-expectations (~> 2.10.0)
|
||||
@@ -295,13 +332,14 @@ GEM
|
||||
activesupport (>= 3.0)
|
||||
railties (>= 3.0)
|
||||
rspec (~> 2.10.0)
|
||||
ruby-hmac (0.4.0)
|
||||
rubyzip (0.9.9)
|
||||
sass (3.1.19)
|
||||
sass-rails (3.2.5)
|
||||
railties (~> 3.2.0)
|
||||
sass (>= 3.1.10)
|
||||
tilt (~> 1.3)
|
||||
selenium-webdriver (2.25.0)
|
||||
selenium-webdriver (2.27.2)
|
||||
childprocess (>= 0.2.5)
|
||||
libwebsocket (~> 0.1.3)
|
||||
multi_json (~> 1.0)
|
||||
@@ -310,15 +348,16 @@ GEM
|
||||
activesupport (>= 3.0.0)
|
||||
slop (3.3.3)
|
||||
spork (1.0.0rc3)
|
||||
sprockets (2.1.3)
|
||||
sprockets (2.2.2)
|
||||
hike (~> 1.2)
|
||||
multi_json (~> 1.0)
|
||||
rack (~> 1.0)
|
||||
tilt (~> 1.1, != 1.3.0)
|
||||
state_machine (1.1.2)
|
||||
stringex (1.3.3)
|
||||
therubyracer (0.10.1)
|
||||
libv8 (~> 3.3.10)
|
||||
thor (0.16.0)
|
||||
thor (0.17.0)
|
||||
tilt (1.3.3)
|
||||
treetop (1.4.12)
|
||||
polyglot
|
||||
@@ -326,7 +365,7 @@ GEM
|
||||
truncate_html (0.5.5)
|
||||
turn (0.8.3)
|
||||
ansi
|
||||
tzinfo (0.3.34)
|
||||
tzinfo (0.3.35)
|
||||
uglifier (1.2.4)
|
||||
execjs (>= 0.3.0)
|
||||
multi_json (>= 1.0.2)
|
||||
@@ -337,7 +376,8 @@ GEM
|
||||
uuidtools (2.1.3)
|
||||
warden (1.1.1)
|
||||
rack (>= 1.0)
|
||||
xpath (0.1.4)
|
||||
websocket (1.0.6)
|
||||
xpath (1.0.0)
|
||||
nokogiri (~> 1.3)
|
||||
|
||||
PLATFORMS
|
||||
@@ -352,13 +392,17 @@ DEPENDENCIES
|
||||
coffee-rails (~> 3.2.1)
|
||||
comfortable_mexican_sofa
|
||||
database_cleaner (= 0.7.1)
|
||||
db2fog
|
||||
factory_girl_rails
|
||||
faker
|
||||
haml
|
||||
jquery-rails
|
||||
letter_opener
|
||||
newrelic_rpm
|
||||
pg
|
||||
pry-debugger
|
||||
rails (= 3.2.8)
|
||||
rails (= 3.2.11)
|
||||
representative_view
|
||||
rspec-rails
|
||||
sass-rails (~> 3.2.3)
|
||||
shoulda-matchers
|
||||
|
||||
661
LICENCE.txt
Normal file
661
LICENCE.txt
Normal file
@@ -0,0 +1,661 @@
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU Affero General Public License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
@@ -85,4 +85,4 @@ speak to Andrew Spinks.
|
||||
|
||||
## Licence
|
||||
|
||||
TODO
|
||||
Copyright (c) 2012 Eaterprises, released under the AGPL licence.
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
|
||||
//= require jquery
|
||||
//= require jquery_ujs
|
||||
//= require jquery-ui
|
||||
//= require shared/jquery-ui-timepicker-addon
|
||||
//= require shared/angular
|
||||
//= require shared/angular-resource
|
||||
//= require admin/spree_core
|
||||
//= require admin/spree_auth
|
||||
//= require admin/spree_promo
|
||||
|
||||
56
app/assets/javascripts/admin/enterprise_fees.js
Normal file
56
app/assets/javascripts/admin/enterprise_fees.js
Normal file
@@ -0,0 +1,56 @@
|
||||
function AdminEnterpriseFeesCtrl($scope, $http) {
|
||||
$http.get('/admin/enterprise_fees.json').success(function(data) {
|
||||
$scope.enterprise_fees = data;
|
||||
|
||||
// TODO: Angular 1.1.0 will have a means to reset a form to its pristine state, which
|
||||
// would avoid the need to save off original calculator types for comparison.
|
||||
for(i in $scope.enterprise_fees) {
|
||||
$scope.enterprise_fees[i].orig_calculator_type = $scope.enterprise_fees[i].calculator_type;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
angular.module('enterprise_fees', [])
|
||||
.directive('ngBindHtmlUnsafeCompiled', function($compile) {
|
||||
return function(scope, element, attrs) {
|
||||
scope.$watch(attrs.ngBindHtmlUnsafeCompiled, function(value) {
|
||||
element.html($compile(value)(scope));
|
||||
});
|
||||
}
|
||||
})
|
||||
.directive('spreeDeleteResource', function() {
|
||||
return function(scope, element, attrs) {
|
||||
if(scope.enterprise_fee.id) {
|
||||
var url = "/admin/enterprise_fees/" + scope.enterprise_fee.id
|
||||
var html = '<a href="'+url+'" class="delete-resource" data-confirm="Are you sure?"><img alt="Delete" src="/assets/admin/icons/delete.png" /> Delete</a>';
|
||||
element.append(html);
|
||||
}
|
||||
}
|
||||
})
|
||||
.directive('spreeEnsureCalculatorPreferencesMatchType', function() {
|
||||
// Hide calculator preference fields when calculator type changed
|
||||
// Fixes 'Enterprise fee is not found' error when changing calculator type
|
||||
// See spree/core/app/assets/javascripts/admin/calculator.js
|
||||
|
||||
// Note: For some reason, DOM --> model bindings aren't working here, so
|
||||
// we use element.val() instead of querying the model itself.
|
||||
|
||||
return function(scope, element, attrs) {
|
||||
scope.$watch(function(scope) {
|
||||
//return scope.enterprise_fee.calculator_type;
|
||||
return element.val();
|
||||
}, function(value) {
|
||||
var settings = element.parent().parent().find("div.calculator-settings");
|
||||
|
||||
// scope.enterprise_fee.calculator_type == scope.enterprise_fee.orig_calculator_type
|
||||
if(element.val() == scope.enterprise_fee.orig_calculator_type) {
|
||||
settings.show();
|
||||
settings.find("input").prop("disabled", false);
|
||||
} else {
|
||||
settings.hide();
|
||||
settings.find("input").prop("disabled", true);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
225
app/assets/javascripts/admin/order_cycle.js.erb.coffee
Normal file
225
app/assets/javascripts/admin/order_cycle.js.erb.coffee
Normal file
@@ -0,0 +1,225 @@
|
||||
app = angular.module('order_cycle', ['ngResource'])
|
||||
|
||||
app.controller 'AdminCreateOrderCycleCtrl', ($scope, OrderCycle, Enterprise) ->
|
||||
$scope.enterprises = Enterprise.index()
|
||||
$scope.supplied_products = Enterprise.supplied_products
|
||||
|
||||
$scope.order_cycle = OrderCycle.order_cycle
|
||||
|
||||
$scope.exchangeSelectedVariants = (exchange) ->
|
||||
OrderCycle.exchangeSelectedVariants(exchange)
|
||||
|
||||
$scope.enterpriseTotalVariants = (enterprise) ->
|
||||
Enterprise.totalVariants(enterprise)
|
||||
|
||||
$scope.productSuppliedToOrderCycle = (product) ->
|
||||
OrderCycle.productSuppliedToOrderCycle(product)
|
||||
|
||||
$scope.variantSuppliedToOrderCycle = (variant) ->
|
||||
OrderCycle.variantSuppliedToOrderCycle(variant)
|
||||
|
||||
$scope.incomingExchangesVariants = ->
|
||||
OrderCycle.incomingExchangesVariants()
|
||||
|
||||
$scope.toggleProducts = ($event, exchange) ->
|
||||
$event.preventDefault()
|
||||
OrderCycle.toggleProducts(exchange)
|
||||
|
||||
$scope.addSupplier = ($event) ->
|
||||
$event.preventDefault()
|
||||
OrderCycle.addSupplier($scope.new_supplier_id)
|
||||
|
||||
$scope.addDistributor = ($event) ->
|
||||
$event.preventDefault()
|
||||
OrderCycle.addDistributor($scope.new_distributor_id)
|
||||
|
||||
$scope.submit = ->
|
||||
OrderCycle.create()
|
||||
|
||||
|
||||
app.controller 'AdminEditOrderCycleCtrl', ($scope, $location, OrderCycle, Enterprise) ->
|
||||
$scope.enterprises = Enterprise.index()
|
||||
$scope.supplied_products = Enterprise.supplied_products
|
||||
|
||||
order_cycle_id = $location.absUrl().match(/\/admin\/order_cycles\/(\d+)/)[1]
|
||||
$scope.order_cycle = OrderCycle.load(order_cycle_id)
|
||||
|
||||
$scope.exchangeSelectedVariants = (exchange) ->
|
||||
OrderCycle.exchangeSelectedVariants(exchange)
|
||||
|
||||
$scope.enterpriseTotalVariants = (enterprise) ->
|
||||
Enterprise.totalVariants(enterprise)
|
||||
|
||||
$scope.productSuppliedToOrderCycle = (product) ->
|
||||
OrderCycle.productSuppliedToOrderCycle(product)
|
||||
|
||||
$scope.variantSuppliedToOrderCycle = (variant) ->
|
||||
OrderCycle.variantSuppliedToOrderCycle(variant)
|
||||
|
||||
$scope.incomingExchangesVariants = ->
|
||||
OrderCycle.incomingExchangesVariants()
|
||||
|
||||
$scope.toggleProducts = ($event, exchange) ->
|
||||
$event.preventDefault()
|
||||
OrderCycle.toggleProducts(exchange)
|
||||
|
||||
$scope.addSupplier = ($event) ->
|
||||
$event.preventDefault()
|
||||
OrderCycle.addSupplier($scope.new_supplier_id)
|
||||
|
||||
$scope.addDistributor = ($event) ->
|
||||
$event.preventDefault()
|
||||
OrderCycle.addDistributor($scope.new_distributor_id)
|
||||
|
||||
$scope.submit = ->
|
||||
OrderCycle.update()
|
||||
|
||||
|
||||
app.config ($httpProvider) ->
|
||||
$httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content')
|
||||
|
||||
app.factory 'OrderCycle', ($resource, $window) ->
|
||||
OrderCycle = $resource '/admin/order_cycles/:order_cycle_id.json', {}, {
|
||||
'index': { method: 'GET', isArray: true}
|
||||
'create': { method: 'POST'}
|
||||
'update': { method: 'PUT'}}
|
||||
|
||||
{
|
||||
order_cycle:
|
||||
incoming_exchanges: []
|
||||
outgoing_exchanges: []
|
||||
|
||||
exchangeSelectedVariants: (exchange) ->
|
||||
numActiveVariants = 0
|
||||
numActiveVariants++ for id, active of exchange.variants when active
|
||||
numActiveVariants
|
||||
|
||||
toggleProducts: (exchange) ->
|
||||
exchange.showProducts = !exchange.showProducts
|
||||
|
||||
addSupplier: (new_supplier_id) ->
|
||||
this.order_cycle.incoming_exchanges.push({enterprise_id: new_supplier_id, active: true, variants: {}})
|
||||
|
||||
addDistributor: (new_distributor_id) ->
|
||||
this.order_cycle.outgoing_exchanges.push({enterprise_id: new_distributor_id, active: true, variants: {}})
|
||||
|
||||
productSuppliedToOrderCycle: (product) ->
|
||||
product_variant_ids = (variant.id for variant in product.variants)
|
||||
variant_ids = [product.master_id].concat(product_variant_ids)
|
||||
incomingExchangesVariants = this.incomingExchangesVariants()
|
||||
|
||||
# TODO: This is an O(n^2) implementation of set intersection and thus is slooow.
|
||||
# Use a better algorithm if needed.
|
||||
# Also, incomingExchangesVariants is called every time, when it only needs to be
|
||||
# called once per change to incoming variants. Some sort of caching?
|
||||
ids = (variant_id for variant_id in variant_ids when incomingExchangesVariants.indexOf(variant_id) != -1)
|
||||
ids.length > 0
|
||||
|
||||
variantSuppliedToOrderCycle: (variant) ->
|
||||
this.incomingExchangesVariants().indexOf(variant.id) != -1
|
||||
|
||||
incomingExchangesVariants: ->
|
||||
variant_ids = []
|
||||
|
||||
for exchange in this.order_cycle.incoming_exchanges
|
||||
variant_ids.push(parseInt(id)) for id, active of exchange.variants when active
|
||||
variant_ids
|
||||
|
||||
load: (order_cycle_id) ->
|
||||
service = this
|
||||
|
||||
OrderCycle.get {order_cycle_id: order_cycle_id}, (oc) ->
|
||||
angular.extend(service.order_cycle, oc)
|
||||
service.order_cycle.incoming_exchanges = []
|
||||
service.order_cycle.outgoing_exchanges = []
|
||||
for exchange in service.order_cycle.exchanges
|
||||
if exchange.sender_id == service.order_cycle.coordinator_id
|
||||
angular.extend(exchange, {enterprise_id: exchange.receiver_id, active: true})
|
||||
delete(exchange.sender_id)
|
||||
service.order_cycle.outgoing_exchanges.push(exchange)
|
||||
|
||||
else if exchange.receiver_id == service.order_cycle.coordinator_id
|
||||
angular.extend(exchange, {enterprise_id: exchange.sender_id, active: true})
|
||||
delete(exchange.receiver_id)
|
||||
service.order_cycle.incoming_exchanges.push(exchange)
|
||||
|
||||
else
|
||||
console.log('Exchange between two enterprises, neither of which is coordinator!')
|
||||
|
||||
delete(service.order_cycle.exchanges)
|
||||
|
||||
this.order_cycle
|
||||
|
||||
create: ->
|
||||
this.removeInactiveExchanges()
|
||||
|
||||
oc = new OrderCycle({order_cycle: this.order_cycle})
|
||||
oc.$create (data) ->
|
||||
if data['success']
|
||||
$window.location = '/admin/order_cycles'
|
||||
else
|
||||
console.log('fail')
|
||||
|
||||
update: ->
|
||||
this.removeInactiveExchanges()
|
||||
|
||||
oc = new OrderCycle({order_cycle: this.order_cycle})
|
||||
oc.$update {order_cycle_id: this.order_cycle.id}, (data) ->
|
||||
if data['success']
|
||||
$window.location = '/admin/order_cycles'
|
||||
else
|
||||
console.log('fail')
|
||||
|
||||
removeInactiveExchanges: ->
|
||||
this.order_cycle.incoming_exchanges =
|
||||
(exchange for exchange in this.order_cycle.incoming_exchanges when exchange.active)
|
||||
this.order_cycle.outgoing_exchanges =
|
||||
(exchange for exchange in this.order_cycle.outgoing_exchanges when exchange.active)
|
||||
}
|
||||
|
||||
app.factory 'Enterprise', ($resource) ->
|
||||
Enterprise = $resource('/admin/enterprises/:enterprise_id.json', {}, {'index': {method: 'GET', isArray: true}})
|
||||
|
||||
{
|
||||
Enterprise: Enterprise
|
||||
enterprises: {}
|
||||
supplied_products: []
|
||||
|
||||
index: ->
|
||||
service = this
|
||||
|
||||
Enterprise.index (data) ->
|
||||
for enterprise in data
|
||||
service.enterprises[enterprise.id] = enterprise
|
||||
|
||||
for product in enterprise.supplied_products
|
||||
service.supplied_products.push(product)
|
||||
|
||||
this.enterprises
|
||||
|
||||
totalVariants: (enterprise) ->
|
||||
numVariants = 0
|
||||
|
||||
counts = for product in enterprise.supplied_products
|
||||
numVariants += if product.variants.length == 0 then 1 else product.variants.length
|
||||
|
||||
numVariants
|
||||
}
|
||||
|
||||
|
||||
app.directive 'datetimepicker', ['$parse', ($parse) ->
|
||||
(scope, element, attrs) ->
|
||||
# using $parse instead of scope[attrs.datetimepicker] for cases
|
||||
# where attrs.datetimepicker is 'foo.bar.lol'
|
||||
$(element).datetimepicker
|
||||
dateFormat: 'yy-mm-dd'
|
||||
timeFormat: 'HH:mm:ss'
|
||||
showOn: "button"
|
||||
buttonImage: "<%= asset_path 'datepicker/cal.gif' %>"
|
||||
buttonImageOnly: true
|
||||
stepMinute: 15
|
||||
onSelect: (dateText, inst) ->
|
||||
scope.$apply ->
|
||||
parsed = $parse(attrs.datetimepicker)
|
||||
parsed.assign(scope, dateText)
|
||||
]
|
||||
14
app/assets/javascripts/admin/util.js.erb
Normal file
14
app/assets/javascripts/admin/util.js.erb
Normal file
@@ -0,0 +1,14 @@
|
||||
$(document).ready(function() {
|
||||
$('.datetimepicker').datetimepicker({
|
||||
dateFormat: Spree.translations.date_picker,
|
||||
dayNames: Spree.translations.abbr_day_names,
|
||||
dayNamesMin: Spree.translations.abbr_day_names,
|
||||
monthNames: Spree.translations.month_names,
|
||||
prevText: Spree.translations.previous,
|
||||
nextText: Spree.translations.next,
|
||||
showOn: "button",
|
||||
buttonImage: "<%= asset_path 'datepicker/cal.gif' %>",
|
||||
buttonImageOnly: true,
|
||||
stepMinute: 15
|
||||
});
|
||||
});
|
||||
1741
app/assets/javascripts/shared/angular-mocks.js
vendored
Normal file
1741
app/assets/javascripts/shared/angular-mocks.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
10
app/assets/javascripts/shared/angular-resource.js
vendored
Normal file
10
app/assets/javascripts/shared/angular-resource.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
AngularJS v1.0.3
|
||||
(c) 2010-2012 Google, Inc. http://angularjs.org
|
||||
License: MIT
|
||||
*/
|
||||
(function(A,e,w){'use strict';e.module("ngResource",["ng"]).factory("$resource",["$http","$parse",function(x,y){function k(a,f){return encodeURIComponent(a).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(f?null:/%20/g,"+")}function t(a,f){this.template=a+="#";this.defaults=f||{};var b=this.urlParams={};l(a.split(/\W/),function(d){d&&a.match(RegExp("[^\\\\]:"+d+"\\W"))&&(b[d]=!0)});this.template=a.replace(/\\:/g,":")}function u(a,f,b){function d(b,c){var a=
|
||||
{},c=i({},f,c);l(c,function(o,c){var d;o.charAt&&o.charAt(0)=="@"?(d=o.substr(1),d=y(d)(b)):d=o;a[c]=d});return a}function h(a){v(a||{},this)}var e=new t(a),b=i({},z,b);l(b,function(g,c){var k=g.method=="POST"||g.method=="PUT"||g.method=="PATCH";h[c]=function(a,b,c,f){var s={},j,m=p,q=null;switch(arguments.length){case 4:q=f,m=c;case 3:case 2:if(r(b)){if(r(a)){m=a;q=b;break}m=b;q=c}else{s=a;j=b;m=c;break}case 1:r(a)?m=a:k?j=a:s=a;break;case 0:break;default:throw"Expected between 0-4 arguments [params, data, success, error], got "+
|
||||
arguments.length+" arguments.";}var n=this instanceof h?this:g.isArray?[]:new h(j);x({method:g.method,url:e.url(i({},d(j,g.params||{}),s)),data:j}).then(function(a){var b=a.data;if(b)g.isArray?(n.length=0,l(b,function(a){n.push(new h(a))})):v(b,n);(m||p)(n,a.headers)},q);return n};h.bind=function(c){return u(a,i({},f,c),b)};h.prototype["$"+c]=function(a,b,f){var g=d(this),e=p,j;switch(arguments.length){case 3:g=a;e=b;j=f;break;case 2:case 1:r(a)?(e=a,j=b):(g=a,e=b||p);case 0:break;default:throw"Expected between 1-3 arguments [params, success, error], got "+
|
||||
arguments.length+" arguments.";}h[c].call(this,g,k?this:w,e,j)}});return h}var z={get:{method:"GET"},save:{method:"POST"},query:{method:"GET",isArray:!0},remove:{method:"DELETE"},"delete":{method:"DELETE"}},p=e.noop,l=e.forEach,i=e.extend,v=e.copy,r=e.isFunction;t.prototype={url:function(a){var f=this,b=this.template,d,h,a=a||{};l(this.urlParams,function(g,c){d=a.hasOwnProperty(c)?a[c]:f.defaults[c];e.isDefined(d)&&d!==null?(h=k(d,!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+"),
|
||||
b=b.replace(RegExp(":"+c+"(\\W)","g"),h+"$1")):b=b.replace(RegExp("/?:"+c+"(\\W)","g"),"$1")});var b=b.replace(/\/?#$/,""),i=[];l(a,function(a,b){f.urlParams[b]||i.push(k(b)+"="+k(a))});i.sort();b=b.replace(/\/*$/,"");return b+(i.length?"?"+i.join("&"):"")}};return u}])})(window,window.angular);
|
||||
159
app/assets/javascripts/shared/angular.js
vendored
Normal file
159
app/assets/javascripts/shared/angular.js
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
AngularJS v1.0.3
|
||||
(c) 2010-2012 Google, Inc. http://angularjs.org
|
||||
License: MIT
|
||||
*/
|
||||
(function(U,ca,p){'use strict';function m(b,a,c){var d;if(b)if(N(b))for(d in b)d!="prototype"&&d!="length"&&d!="name"&&b.hasOwnProperty(d)&&a.call(c,b[d],d);else if(b.forEach&&b.forEach!==m)b.forEach(a,c);else if(L(b)&&wa(b.length))for(d=0;d<b.length;d++)a.call(c,b[d],d);else for(d in b)b.hasOwnProperty(d)&&a.call(c,b[d],d);return b}function lb(b){var a=[],c;for(c in b)b.hasOwnProperty(c)&&a.push(c);return a.sort()}function ec(b,a,c){for(var d=lb(b),e=0;e<d.length;e++)a.call(c,b[d[e]],d[e]);return d}
|
||||
function mb(b){return function(a,c){b(c,a)}}function xa(){for(var b=Z.length,a;b;){b--;a=Z[b].charCodeAt(0);if(a==57)return Z[b]="A",Z.join("");if(a==90)Z[b]="0";else return Z[b]=String.fromCharCode(a+1),Z.join("")}Z.unshift("0");return Z.join("")}function x(b){m(arguments,function(a){a!==b&&m(a,function(a,d){b[d]=a})});return b}function G(b){return parseInt(b,10)}function ya(b,a){return x(new (x(function(){},{prototype:b})),a)}function D(){}function ma(b){return b}function I(b){return function(){return b}}
|
||||
function t(b){return typeof b=="undefined"}function v(b){return typeof b!="undefined"}function L(b){return b!=null&&typeof b=="object"}function F(b){return typeof b=="string"}function wa(b){return typeof b=="number"}function na(b){return Sa.apply(b)=="[object Date]"}function J(b){return Sa.apply(b)=="[object Array]"}function N(b){return typeof b=="function"}function oa(b){return b&&b.document&&b.location&&b.alert&&b.setInterval}function R(b){return F(b)?b.replace(/^\s*/,"").replace(/\s*$/,""):b}function fc(b){return b&&
|
||||
(b.nodeName||b.bind&&b.find)}function Ta(b,a,c){var d=[];m(b,function(b,g,i){d.push(a.call(c,b,g,i))});return d}function gc(b,a){var c=0,d;if(J(b)||F(b))return b.length;else if(L(b))for(d in b)(!a||b.hasOwnProperty(d))&&c++;return c}function za(b,a){if(b.indexOf)return b.indexOf(a);for(var c=0;c<b.length;c++)if(a===b[c])return c;return-1}function Ua(b,a){var c=za(b,a);c>=0&&b.splice(c,1);return a}function V(b,a){if(oa(b)||b&&b.$evalAsync&&b.$watch)throw B("Can't copy Window or Scope");if(a){if(b===
|
||||
a)throw B("Can't copy equivalent objects or arrays");if(J(b)){for(;a.length;)a.pop();for(var c=0;c<b.length;c++)a.push(V(b[c]))}else for(c in m(a,function(b,c){delete a[c]}),b)a[c]=V(b[c])}else(a=b)&&(J(b)?a=V(b,[]):na(b)?a=new Date(b.getTime()):L(b)&&(a=V(b,{})));return a}function hc(b,a){var a=a||{},c;for(c in b)b.hasOwnProperty(c)&&c.substr(0,2)!=="$$"&&(a[c]=b[c]);return a}function ha(b,a){if(b===a)return!0;if(b===null||a===null)return!1;if(b!==b&&a!==a)return!0;var c=typeof b,d;if(c==typeof a&&
|
||||
c=="object")if(J(b)){if((c=b.length)==a.length){for(d=0;d<c;d++)if(!ha(b[d],a[d]))return!1;return!0}}else if(na(b))return na(a)&&b.getTime()==a.getTime();else{if(b&&b.$evalAsync&&b.$watch||a&&a.$evalAsync&&a.$watch||oa(b)||oa(a))return!1;c={};for(d in b){if(d.charAt(0)!=="$"&&!N(b[d])&&!ha(b[d],a[d]))return!1;c[d]=!0}for(d in a)if(!c[d]&&d.charAt(0)!=="$"&&!N(a[d]))return!1;return!0}return!1}function Va(b,a){var c=arguments.length>2?ia.call(arguments,2):[];return N(a)&&!(a instanceof RegExp)?c.length?
|
||||
function(){return arguments.length?a.apply(b,c.concat(ia.call(arguments,0))):a.apply(b,c)}:function(){return arguments.length?a.apply(b,arguments):a.call(b)}:a}function ic(b,a){var c=a;/^\$+/.test(b)?c=p:oa(a)?c="$WINDOW":a&&ca===a?c="$DOCUMENT":a&&a.$evalAsync&&a.$watch&&(c="$SCOPE");return c}function da(b,a){return JSON.stringify(b,ic,a?" ":null)}function nb(b){return F(b)?JSON.parse(b):b}function Wa(b){b&&b.length!==0?(b=E(""+b),b=!(b=="f"||b=="0"||b=="false"||b=="no"||b=="n"||b=="[]")):b=!1;
|
||||
return b}function pa(b){b=u(b).clone();try{b.html("")}catch(a){}return u("<div>").append(b).html().match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,function(a,b){return"<"+E(b)})}function Xa(b){var a={},c,d;m((b||"").split("&"),function(b){b&&(c=b.split("="),d=decodeURIComponent(c[0]),a[d]=v(c[1])?decodeURIComponent(c[1]):!0)});return a}function ob(b){var a=[];m(b,function(b,d){a.push(Ya(d,!0)+(b===!0?"":"="+Ya(b,!0)))});return a.length?a.join("&"):""}function Za(b){return Ya(b,!0).replace(/%26/gi,"&").replace(/%3D/gi,
|
||||
"=").replace(/%2B/gi,"+")}function Ya(b,a){return encodeURIComponent(b).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(a?null:/%20/g,"+")}function jc(b,a){function c(a){a&&d.push(a)}var d=[b],e,g,i=["ng:app","ng-app","x-ng-app","data-ng-app"],f=/\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;m(i,function(a){i[a]=!0;c(ca.getElementById(a));a=a.replace(":","\\:");b.querySelectorAll&&(m(b.querySelectorAll("."+a),c),m(b.querySelectorAll("."+a+"\\:"),c),m(b.querySelectorAll("["+
|
||||
a+"]"),c))});m(d,function(a){if(!e){var b=f.exec(" "+a.className+" ");b?(e=a,g=(b[2]||"").replace(/\s+/g,",")):m(a.attributes,function(b){if(!e&&i[b.name])e=a,g=b.value})}});e&&a(e,g?[g]:[])}function pb(b,a){b=u(b);a=a||[];a.unshift(["$provide",function(a){a.value("$rootElement",b)}]);a.unshift("ng");var c=qb(a);c.invoke(["$rootScope","$rootElement","$compile","$injector",function(a,b,c,i){a.$apply(function(){b.data("$injector",i);c(b)(a)})}]);return c}function $a(b,a){a=a||"_";return b.replace(kc,
|
||||
function(b,d){return(d?a:"")+b.toLowerCase()})}function qa(b,a,c){if(!b)throw new B("Argument '"+(a||"?")+"' is "+(c||"required"));return b}function ra(b,a,c){c&&J(b)&&(b=b[b.length-1]);qa(N(b),a,"not a function, got "+(b&&typeof b=="object"?b.constructor.name||"Object":typeof b));return b}function lc(b){function a(a,b,e){return a[b]||(a[b]=e())}return a(a(b,"angular",Object),"module",function(){var b={};return function(d,e,g){e&&b.hasOwnProperty(d)&&(b[d]=null);return a(b,d,function(){function a(c,
|
||||
d,e){return function(){b[e||"push"]([c,d,arguments]);return j}}if(!e)throw B("No module: "+d);var b=[],c=[],k=a("$injector","invoke"),j={_invokeQueue:b,_runBlocks:c,requires:e,name:d,provider:a("$provide","provider"),factory:a("$provide","factory"),service:a("$provide","service"),value:a("$provide","value"),constant:a("$provide","constant","unshift"),filter:a("$filterProvider","register"),controller:a("$controllerProvider","register"),directive:a("$compileProvider","directive"),config:k,run:function(a){c.push(a);
|
||||
return this}};g&&k(g);return j})}})}function rb(b){return b.replace(mc,function(a,b,d,e){return e?d.toUpperCase():d}).replace(nc,"Moz$1")}function ab(b,a){function c(){var e;for(var b=[this],c=a,i,f,h,k,j,l;b.length;){i=b.shift();f=0;for(h=i.length;f<h;f++){k=u(i[f]);c?k.triggerHandler("$destroy"):c=!c;j=0;for(e=(l=k.children()).length,k=e;j<k;j++)b.push(ja(l[j]))}}return d.apply(this,arguments)}var d=ja.fn[b],d=d.$original||d;c.$original=d;ja.fn[b]=c}function Q(b){if(b instanceof Q)return b;if(!(this instanceof
|
||||
Q)){if(F(b)&&b.charAt(0)!="<")throw B("selectors not implemented");return new Q(b)}if(F(b)){var a=ca.createElement("div");a.innerHTML="<div> </div>"+b;a.removeChild(a.firstChild);bb(this,a.childNodes);this.remove()}else bb(this,b)}function cb(b){return b.cloneNode(!0)}function sa(b){sb(b);for(var a=0,b=b.childNodes||[];a<b.length;a++)sa(b[a])}function tb(b,a,c){var d=$(b,"events");$(b,"handle")&&(t(a)?m(d,function(a,c){db(b,c,a);delete d[c]}):t(c)?(db(b,a,d[a]),delete d[a]):Ua(d[a],c))}function sb(b){var a=
|
||||
b[Aa],c=Ba[a];c&&(c.handle&&(c.events.$destroy&&c.handle({},"$destroy"),tb(b)),delete Ba[a],b[Aa]=p)}function $(b,a,c){var d=b[Aa],d=Ba[d||-1];if(v(c))d||(b[Aa]=d=++oc,d=Ba[d]={}),d[a]=c;else return d&&d[a]}function ub(b,a,c){var d=$(b,"data"),e=v(c),g=!e&&v(a),i=g&&!L(a);!d&&!i&&$(b,"data",d={});if(e)d[a]=c;else if(g)if(i)return d&&d[a];else x(d,a);else return d}function Ca(b,a){return(" "+b.className+" ").replace(/[\n\t]/g," ").indexOf(" "+a+" ")>-1}function vb(b,a){a&&m(a.split(" "),function(a){b.className=
|
||||
R((" "+b.className+" ").replace(/[\n\t]/g," ").replace(" "+R(a)+" "," "))})}function wb(b,a){a&&m(a.split(" "),function(a){if(!Ca(b,a))b.className=R(b.className+" "+R(a))})}function bb(b,a){if(a)for(var a=!a.nodeName&&v(a.length)&&!oa(a)?a:[a],c=0;c<a.length;c++)b.push(a[c])}function xb(b,a){return Da(b,"$"+(a||"ngController")+"Controller")}function Da(b,a,c){b=u(b);for(b[0].nodeType==9&&(b=b.find("html"));b.length;){if(c=b.data(a))return c;b=b.parent()}}function yb(b,a){var c=Ea[a.toLowerCase()];
|
||||
return c&&zb[b.nodeName]&&c}function pc(b,a){var c=function(c,e){if(!c.preventDefault)c.preventDefault=function(){c.returnValue=!1};if(!c.stopPropagation)c.stopPropagation=function(){c.cancelBubble=!0};if(!c.target)c.target=c.srcElement||ca;if(t(c.defaultPrevented)){var g=c.preventDefault;c.preventDefault=function(){c.defaultPrevented=!0;g.call(c)};c.defaultPrevented=!1}c.isDefaultPrevented=function(){return c.defaultPrevented};m(a[e||c.type],function(a){a.call(b,c)});aa<=8?(c.preventDefault=null,
|
||||
c.stopPropagation=null,c.isDefaultPrevented=null):(delete c.preventDefault,delete c.stopPropagation,delete c.isDefaultPrevented)};c.elem=b;return c}function ga(b){var a=typeof b,c;if(a=="object"&&b!==null)if(typeof(c=b.$$hashKey)=="function")c=b.$$hashKey();else{if(c===p)c=b.$$hashKey=xa()}else c=b;return a+":"+c}function Fa(b){m(b,this.put,this)}function eb(){}function Ab(b){var a,c;if(typeof b=="function"){if(!(a=b.$inject))a=[],c=b.toString().replace(qc,""),c=c.match(rc),m(c[1].split(sc),function(b){b.replace(tc,
|
||||
function(b,c,d){a.push(d)})}),b.$inject=a}else J(b)?(c=b.length-1,ra(b[c],"fn"),a=b.slice(0,c)):ra(b,"fn",!0);return a}function qb(b){function a(a){return function(b,c){if(L(b))m(b,mb(a));else return a(b,c)}}function c(a,b){N(b)&&(b=l.instantiate(b));if(!b.$get)throw B("Provider "+a+" must define $get factory method.");return j[a+f]=b}function d(a,b){return c(a,{$get:b})}function e(a){var b=[];m(a,function(a){if(!k.get(a))if(k.put(a,!0),F(a)){var c=ta(a);b=b.concat(e(c.requires)).concat(c._runBlocks);
|
||||
try{for(var d=c._invokeQueue,c=0,f=d.length;c<f;c++){var h=d[c],g=h[0]=="$injector"?l:l.get(h[0]);g[h[1]].apply(g,h[2])}}catch(n){throw n.message&&(n.message+=" from "+a),n;}}else if(N(a))try{b.push(l.invoke(a))}catch(i){throw i.message&&(i.message+=" from "+a),i;}else if(J(a))try{b.push(l.invoke(a))}catch(j){throw j.message&&(j.message+=" from "+String(a[a.length-1])),j;}else ra(a,"module")});return b}function g(a,b){function c(d){if(typeof d!=="string")throw B("Service name expected");if(a.hasOwnProperty(d)){if(a[d]===
|
||||
i)throw B("Circular dependency: "+h.join(" <- "));return a[d]}else try{return h.unshift(d),a[d]=i,a[d]=b(d)}finally{h.shift()}}function d(a,b,e){var f=[],k=Ab(a),g,n,i;n=0;for(g=k.length;n<g;n++)i=k[n],f.push(e&&e.hasOwnProperty(i)?e[i]:c(i,h));a.$inject||(a=a[g]);switch(b?-1:f.length){case 0:return a();case 1:return a(f[0]);case 2:return a(f[0],f[1]);case 3:return a(f[0],f[1],f[2]);case 4:return a(f[0],f[1],f[2],f[3]);case 5:return a(f[0],f[1],f[2],f[3],f[4]);case 6:return a(f[0],f[1],f[2],f[3],
|
||||
f[4],f[5]);case 7:return a(f[0],f[1],f[2],f[3],f[4],f[5],f[6]);case 8:return a(f[0],f[1],f[2],f[3],f[4],f[5],f[6],f[7]);case 9:return a(f[0],f[1],f[2],f[3],f[4],f[5],f[6],f[7],f[8]);case 10:return a(f[0],f[1],f[2],f[3],f[4],f[5],f[6],f[7],f[8],f[9]);default:return a.apply(b,f)}}return{invoke:d,instantiate:function(a,b){var c=function(){},e;c.prototype=(J(a)?a[a.length-1]:a).prototype;c=new c;e=d(a,c,b);return L(e)?e:c},get:c,annotate:Ab}}var i={},f="Provider",h=[],k=new Fa,j={$provide:{provider:a(c),
|
||||
factory:a(d),service:a(function(a,b){return d(a,["$injector",function(a){return a.instantiate(b)}])}),value:a(function(a,b){return d(a,I(b))}),constant:a(function(a,b){j[a]=b;o[a]=b}),decorator:function(a,b){var c=l.get(a+f),d=c.$get;c.$get=function(){var a=r.invoke(d,c);return r.invoke(b,null,{$delegate:a})}}}},l=g(j,function(){throw B("Unknown provider: "+h.join(" <- "));}),o={},r=o.$injector=g(o,function(a){a=l.get(a+f);return r.invoke(a.$get,a)});m(e(b),function(a){r.invoke(a||D)});return r}function uc(){var b=
|
||||
!0;this.disableAutoScrolling=function(){b=!1};this.$get=["$window","$location","$rootScope",function(a,c,d){function e(a){var b=null;m(a,function(a){!b&&E(a.nodeName)==="a"&&(b=a)});return b}function g(){var b=c.hash(),d;b?(d=i.getElementById(b))?d.scrollIntoView():(d=e(i.getElementsByName(b)))?d.scrollIntoView():b==="top"&&a.scrollTo(0,0):a.scrollTo(0,0)}var i=a.document;b&&d.$watch(function(){return c.hash()},function(){d.$evalAsync(g)});return g}]}function vc(b,a,c,d){function e(a){try{a.apply(null,
|
||||
ia.call(arguments,1))}finally{if(n--,n===0)for(;w.length;)try{w.pop()()}catch(b){c.error(b)}}}function g(a,b){(function ea(){m(q,function(a){a()});s=b(ea,a)})()}function i(){O!=f.url()&&(O=f.url(),m(A,function(a){a(f.url())}))}var f=this,h=a[0],k=b.location,j=b.history,l=b.setTimeout,o=b.clearTimeout,r={};f.isMock=!1;var n=0,w=[];f.$$completeOutstandingRequest=e;f.$$incOutstandingRequestCount=function(){n++};f.notifyWhenNoOutstandingRequests=function(a){m(q,function(a){a()});n===0?a():w.push(a)};
|
||||
var q=[],s;f.addPollFn=function(a){t(s)&&g(100,l);q.push(a);return a};var O=k.href,C=a.find("base");f.url=function(a,b){if(a){if(O!=a)return O=a,d.history?b?j.replaceState(null,"",a):(j.pushState(null,"",a),C.attr("href",C.attr("href"))):b?k.replace(a):k.href=a,f}else return k.href.replace(/%27/g,"'")};var A=[],K=!1;f.onUrlChange=function(a){K||(d.history&&u(b).bind("popstate",i),d.hashchange?u(b).bind("hashchange",i):f.addPollFn(i),K=!0);A.push(a);return a};f.baseHref=function(){var a=C.attr("href");
|
||||
return a?a.replace(/^https?\:\/\/[^\/]*/,""):a};var W={},y="",M=f.baseHref();f.cookies=function(a,b){var d,e,f,k;if(a)if(b===p)h.cookie=escape(a)+"=;path="+M+";expires=Thu, 01 Jan 1970 00:00:00 GMT";else{if(F(b))d=(h.cookie=escape(a)+"="+escape(b)+";path="+M).length+1,d>4096&&c.warn("Cookie '"+a+"' possibly not set or overflowed because it was too large ("+d+" > 4096 bytes)!"),W.length>20&&c.warn("Cookie '"+a+"' possibly not set or overflowed because too many cookies were already set ("+W.length+
|
||||
" > 20 )")}else{if(h.cookie!==y){y=h.cookie;d=y.split("; ");W={};for(f=0;f<d.length;f++)e=d[f],k=e.indexOf("="),k>0&&(W[unescape(e.substring(0,k))]=unescape(e.substring(k+1)))}return W}};f.defer=function(a,b){var c;n++;c=l(function(){delete r[c];e(a)},b||0);r[c]=!0;return c};f.defer.cancel=function(a){return r[a]?(delete r[a],o(a),e(D),!0):!1}}function wc(){this.$get=["$window","$log","$sniffer","$document",function(b,a,c,d){return new vc(b,d,a,c)}]}function xc(){this.$get=function(){function b(b,
|
||||
d){function e(a){if(a!=l){if(o){if(o==a)o=a.n}else o=a;g(a.n,a.p);g(a,l);l=a;l.n=null}}function g(a,b){if(a!=b){if(a)a.p=b;if(b)b.n=a}}if(b in a)throw B("cacheId "+b+" taken");var i=0,f=x({},d,{id:b}),h={},k=d&&d.capacity||Number.MAX_VALUE,j={},l=null,o=null;return a[b]={put:function(a,b){var c=j[a]||(j[a]={key:a});e(c);t(b)||(a in h||i++,h[a]=b,i>k&&this.remove(o.key))},get:function(a){var b=j[a];if(b)return e(b),h[a]},remove:function(a){var b=j[a];if(b){if(b==l)l=b.p;if(b==o)o=b.n;g(b.n,b.p);delete j[a];
|
||||
delete h[a];i--}},removeAll:function(){h={};i=0;j={};l=o=null},destroy:function(){j=f=h=null;delete a[b]},info:function(){return x({},f,{size:i})}}}var a={};b.info=function(){var b={};m(a,function(a,e){b[e]=a.info()});return b};b.get=function(b){return a[b]};return b}}function yc(){this.$get=["$cacheFactory",function(b){return b("templates")}]}function Bb(b){var a={},c="Directive",d=/^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,e=/(([\d\w\-_]+)(?:\:([^;]+))?;?)/,g="Template must have exactly one root element. was: ";
|
||||
this.directive=function f(d,e){F(d)?(qa(e,"directive"),a.hasOwnProperty(d)||(a[d]=[],b.factory(d+c,["$injector","$exceptionHandler",function(b,c){var e=[];m(a[d],function(a){try{var f=b.invoke(a);if(N(f))f={compile:I(f)};else if(!f.compile&&f.link)f.compile=I(f.link);f.priority=f.priority||0;f.name=f.name||d;f.require=f.require||f.controller&&f.name;f.restrict=f.restrict||"A";e.push(f)}catch(k){c(k)}});return e}])),a[d].push(e)):m(d,mb(f));return this};this.$get=["$injector","$interpolate","$exceptionHandler",
|
||||
"$http","$templateCache","$parse","$controller","$rootScope",function(b,h,k,j,l,o,r,n){function w(a,b,c){a instanceof u||(a=u(a));m(a,function(b,c){b.nodeType==3&&(a[c]=u(b).wrap("<span></span>").parent()[0])});var d=s(a,b,a,c);return function(b,c){qa(b,"scope");var e=c?ua.clone.call(a):a;e.data("$scope",b);q(e,"ng-scope");c&&c(e,b);d&&d(b,e,e);return e}}function q(a,b){try{a.addClass(b)}catch(c){}}function s(a,b,c,d){function e(a,c,d,k){for(var g,h,j,n,o,l=0,r=0,q=f.length;l<q;r++)j=c[r],g=f[l++],
|
||||
h=f[l++],g?(g.scope?(n=a.$new(L(g.scope)),u(j).data("$scope",n)):n=a,(o=g.transclude)||!k&&b?g(h,n,j,d,function(b){return function(c){var d=a.$new();return b(d,c).bind("$destroy",Va(d,d.$destroy))}}(o||b)):g(h,n,j,p,k)):h&&h(a,j.childNodes,p,k)}for(var f=[],k,g,h,j=0;j<a.length;j++)g=new ea,k=O(a[j],[],g,d),g=(k=k.length?C(k,a[j],g,b,c):null)&&k.terminal||!a[j].childNodes.length?null:s(a[j].childNodes,k?k.transclude:b),f.push(k),f.push(g),h=h||k||g;return h?e:null}function O(a,b,c,f){var k=c.$attr,
|
||||
g;switch(a.nodeType){case 1:A(b,fa(Cb(a).toLowerCase()),"E",f);var h,j,n;g=a.attributes;for(var o=0,l=g&&g.length;o<l;o++)if(h=g[o],h.specified)j=h.name,n=fa(j.toLowerCase()),k[n]=j,c[n]=h=R(aa&&j=="href"?decodeURIComponent(a.getAttribute(j,2)):h.value),yb(a,n)&&(c[n]=!0),X(a,b,h,n),A(b,n,"A",f);a=a.className;if(F(a)&&a!=="")for(;g=e.exec(a);)n=fa(g[2]),A(b,n,"C",f)&&(c[n]=R(g[3])),a=a.substr(g.index+g[0].length);break;case 3:H(b,a.nodeValue);break;case 8:try{if(g=d.exec(a.nodeValue))n=fa(g[1]),A(b,
|
||||
n,"M",f)&&(c[n]=R(g[2]))}catch(r){}}b.sort(y);return b}function C(a,b,c,d,e){function f(a,b){if(a)a.require=z.require,l.push(a);if(b)b.require=z.require,ba.push(b)}function h(a,b){var c,d="data",e=!1;if(F(a)){for(;(c=a.charAt(0))=="^"||c=="?";)a=a.substr(1),c=="^"&&(d="inheritedData"),e=e||c=="?";c=b[d]("$"+a+"Controller");if(!c&&!e)throw B("No controller: "+a);}else J(a)&&(c=[],m(a,function(a){c.push(h(a,b))}));return c}function j(a,d,e,f,g){var n,q,w,K,s;n=b===e?c:hc(c,new ea(u(e),c.$attr));q=n.$$element;
|
||||
if(C){var zc=/^\s*([@=&])\s*(\w*)\s*$/,O=d.$parent||d;m(C.scope,function(a,b){var c=a.match(zc)||[],e=c[2]||b,f,g,k;switch(c[1]){case "@":n.$observe(e,function(a){d[b]=a});n.$$observers[e].$$scope=O;break;case "=":g=o(n[e]);k=g.assign||function(){f=d[b]=g(O);throw B(Db+n[e]+" (directive: "+C.name+")");};f=d[b]=g(O);d.$watch(function(){var a=g(O);a!==d[b]&&(a!==f?f=d[b]=a:k(O,a=f=d[b]));return a});break;case "&":g=o(n[e]);d[b]=function(a){return g(O,a)};break;default:throw B("Invalid isolate scope definition for directive "+
|
||||
C.name+": "+a);}})}t&&m(t,function(a){var b={$scope:d,$element:q,$attrs:n,$transclude:g};s=a.controller;s=="@"&&(s=n[a.name]);q.data("$"+a.name+"Controller",r(s,b))});f=0;for(w=l.length;f<w;f++)try{K=l[f],K(d,q,n,K.require&&h(K.require,q))}catch(y){k(y,pa(q))}a&&a(d,e.childNodes,p,g);f=0;for(w=ba.length;f<w;f++)try{K=ba[f],K(d,q,n,K.require&&h(K.require,q))}catch(Ha){k(Ha,pa(q))}}for(var n=-Number.MAX_VALUE,l=[],ba=[],s=null,C=null,A=null,y=c.$$element=u(b),z,H,X,D,v=d,t,x,Y,E=0,G=a.length;E<G;E++){z=
|
||||
a[E];X=p;if(n>z.priority)break;if(Y=z.scope)M("isolated scope",C,z,y),L(Y)&&(q(y,"ng-isolate-scope"),C=z),q(y,"ng-scope"),s=s||z;H=z.name;if(Y=z.controller)t=t||{},M("'"+H+"' controller",t[H],z,y),t[H]=z;if(Y=z.transclude)M("transclusion",D,z,y),D=z,n=z.priority,Y=="element"?(X=u(b),y=c.$$element=u("<\!-- "+H+": "+c[H]+" --\>"),b=y[0],Ga(e,u(X[0]),b),v=w(X,d,n)):(X=u(cb(b)).contents(),y.html(""),v=w(X,d));if(Y=z.template)if(M("template",A,z,y),A=z,Y=Ha(Y),z.replace){X=u("<div>"+R(Y)+"</div>").contents();
|
||||
b=X[0];if(X.length!=1||b.nodeType!==1)throw new B(g+Y);Ga(e,y,b);H={$attr:{}};a=a.concat(O(b,a.splice(E+1,a.length-(E+1)),H));K(c,H);G=a.length}else y.html(Y);if(z.templateUrl)M("template",A,z,y),A=z,j=W(a.splice(E,a.length-E),j,y,c,e,z.replace,v),G=a.length;else if(z.compile)try{x=z.compile(y,c,v),N(x)?f(null,x):x&&f(x.pre,x.post)}catch(I){k(I,pa(y))}if(z.terminal)j.terminal=!0,n=Math.max(n,z.priority)}j.scope=s&&s.scope;j.transclude=D&&v;return j}function A(d,e,g,h){var j=!1;if(a.hasOwnProperty(e))for(var n,
|
||||
e=b.get(e+c),o=0,l=e.length;o<l;o++)try{if(n=e[o],(h===p||h>n.priority)&&n.restrict.indexOf(g)!=-1)d.push(n),j=!0}catch(r){k(r)}return j}function K(a,b){var c=b.$attr,d=a.$attr,e=a.$$element;m(a,function(d,e){e.charAt(0)!="$"&&(b[e]&&(d+=(e==="style"?";":" ")+b[e]),a.$set(e,d,!0,c[e]))});m(b,function(b,f){f=="class"?(q(e,b),a["class"]=(a["class"]?a["class"]+" ":"")+b):f=="style"?e.attr("style",e.attr("style")+";"+b):f.charAt(0)!="$"&&!a.hasOwnProperty(f)&&(a[f]=b,d[f]=c[f])})}function W(a,b,c,d,e,
|
||||
f,k){var h=[],n,o,r=c[0],q=a.shift(),w=x({},q,{controller:null,templateUrl:null,transclude:null,scope:null});c.html("");j.get(q.templateUrl,{cache:l}).success(function(j){var l,q,j=Ha(j);if(f){q=u("<div>"+R(j)+"</div>").contents();l=q[0];if(q.length!=1||l.nodeType!==1)throw new B(g+j);j={$attr:{}};Ga(e,c,l);O(l,a,j);K(d,j)}else l=r,c.html(j);a.unshift(w);n=C(a,c,d,k);for(o=s(c.contents(),k);h.length;){var ba=h.pop(),j=h.pop();q=h.pop();var y=h.pop(),m=l;q!==r&&(m=cb(l),Ga(j,u(q),m));n(function(){b(o,
|
||||
y,m,e,ba)},y,m,e,ba)}h=null}).error(function(a,b,c,d){throw B("Failed to load template: "+d.url);});return function(a,c,d,e,f){h?(h.push(c),h.push(d),h.push(e),h.push(f)):n(function(){b(o,c,d,e,f)},c,d,e,f)}}function y(a,b){return b.priority-a.priority}function M(a,b,c,d){if(b)throw B("Multiple directives ["+b.name+", "+c.name+"] asking for "+a+" on: "+pa(d));}function H(a,b){var c=h(b,!0);c&&a.push({priority:0,compile:I(function(a,b){var d=b.parent(),e=d.data("$binding")||[];e.push(c);q(d.data("$binding",
|
||||
e),"ng-binding");a.$watch(c,function(a){b[0].nodeValue=a})})})}function X(a,b,c,d){var e=h(c,!0);e&&b.push({priority:100,compile:I(function(a,b,c){b=c.$$observers||(c.$$observers={});d==="class"&&(e=h(c[d],!0));c[d]=p;(b[d]||(b[d]=[])).$$inter=!0;(c.$$observers&&c.$$observers[d].$$scope||a).$watch(e,function(a){c.$set(d,a)})})})}function Ga(a,b,c){var d=b[0],e=d.parentNode,f,g;if(a){f=0;for(g=a.length;f<g;f++)if(a[f]==d){a[f]=c;break}}e&&e.replaceChild(c,d);c[u.expando]=d[u.expando];b[0]=c}var ea=
|
||||
function(a,b){this.$$element=a;this.$attr=b||{}};ea.prototype={$normalize:fa,$set:function(a,b,c,d){var e=yb(this.$$element[0],a),f=this.$$observers;e&&(this.$$element.prop(a,b),d=e);this[a]=b;d?this.$attr[a]=d:(d=this.$attr[a])||(this.$attr[a]=d=$a(a,"-"));c!==!1&&(b===null||b===p?this.$$element.removeAttr(d):this.$$element.attr(d,b));f&&m(f[a],function(a){try{a(b)}catch(c){k(c)}})},$observe:function(a,b){var c=this,d=c.$$observers||(c.$$observers={}),e=d[a]||(d[a]=[]);e.push(b);n.$evalAsync(function(){e.$$inter||
|
||||
b(c[a])});return b}};var D=h.startSymbol(),ba=h.endSymbol(),Ha=D=="{{"||ba=="}}"?ma:function(a){return a.replace(/\{\{/g,D).replace(/}}/g,ba)};return w}]}function fa(b){return rb(b.replace(Ac,""))}function Bc(){var b={};this.register=function(a,c){L(a)?x(b,a):b[a]=c};this.$get=["$injector","$window",function(a,c){return function(d,e){if(F(d)){var g=d,d=b.hasOwnProperty(g)?b[g]:fb(e.$scope,g,!0)||fb(c,g,!0);ra(d,g,!0)}return a.instantiate(d,e)}}]}function Cc(){this.$get=["$window",function(b){return u(b.document)}]}
|
||||
function Dc(){this.$get=["$log",function(b){return function(a,c){b.error.apply(b,arguments)}}]}function Ec(){var b="{{",a="}}";this.startSymbol=function(a){return a?(b=a,this):b};this.endSymbol=function(b){return b?(a=b,this):a};this.$get=["$parse",function(c){function d(d,f){for(var h,k,j=0,l=[],o=d.length,r=!1,n=[];j<o;)(h=d.indexOf(b,j))!=-1&&(k=d.indexOf(a,h+e))!=-1?(j!=h&&l.push(d.substring(j,h)),l.push(j=c(r=d.substring(h+e,k))),j.exp=r,j=k+g,r=!0):(j!=o&&l.push(d.substring(j)),j=o);if(!(o=
|
||||
l.length))l.push(""),o=1;if(!f||r)return n.length=o,j=function(a){for(var b=0,c=o,d;b<c;b++){if(typeof(d=l[b])=="function")d=d(a),d==null||d==p?d="":typeof d!="string"&&(d=da(d));n[b]=d}return n.join("")},j.exp=d,j.parts=l,j}var e=b.length,g=a.length;d.startSymbol=function(){return b};d.endSymbol=function(){return a};return d}]}function Eb(b){for(var b=b.split("/"),a=b.length;a--;)b[a]=Za(b[a]);return b.join("/")}function va(b,a){var c=Fb.exec(b),c={protocol:c[1],host:c[3],port:G(c[5])||Gb[c[1]]||
|
||||
null,path:c[6]||"/",search:c[8],hash:c[10]};if(a)a.$$protocol=c.protocol,a.$$host=c.host,a.$$port=c.port;return c}function ka(b,a,c){return b+"://"+a+(c==Gb[b]?"":":"+c)}function Fc(b,a,c){var d=va(b);return decodeURIComponent(d.path)!=a||t(d.hash)||d.hash.indexOf(c)!==0?b:ka(d.protocol,d.host,d.port)+a.substr(0,a.lastIndexOf("/"))+d.hash.substr(c.length)}function Gc(b,a,c){var d=va(b);if(decodeURIComponent(d.path)==a)return b;else{var e=d.search&&"?"+d.search||"",g=d.hash&&"#"+d.hash||"",i=a.substr(0,
|
||||
a.lastIndexOf("/")),f=d.path.substr(i.length);if(d.path.indexOf(i)!==0)throw B('Invalid url "'+b+'", missing path prefix "'+i+'" !');return ka(d.protocol,d.host,d.port)+a+"#"+c+f+e+g}}function gb(b,a,c){a=a||"";this.$$parse=function(b){var c=va(b,this);if(c.path.indexOf(a)!==0)throw B('Invalid url "'+b+'", missing path prefix "'+a+'" !');this.$$path=decodeURIComponent(c.path.substr(a.length));this.$$search=Xa(c.search);this.$$hash=c.hash&&decodeURIComponent(c.hash)||"";this.$$compose()};this.$$compose=
|
||||
function(){var b=ob(this.$$search),c=this.$$hash?"#"+Za(this.$$hash):"";this.$$url=Eb(this.$$path)+(b?"?"+b:"")+c;this.$$absUrl=ka(this.$$protocol,this.$$host,this.$$port)+a+this.$$url};this.$$rewriteAppUrl=function(a){if(a.indexOf(c)==0)return a};this.$$parse(b)}function Ia(b,a,c){var d;this.$$parse=function(b){var c=va(b,this);if(c.hash&&c.hash.indexOf(a)!==0)throw B('Invalid url "'+b+'", missing hash prefix "'+a+'" !');d=c.path+(c.search?"?"+c.search:"");c=Hc.exec((c.hash||"").substr(a.length));
|
||||
this.$$path=c[1]?(c[1].charAt(0)=="/"?"":"/")+decodeURIComponent(c[1]):"";this.$$search=Xa(c[3]);this.$$hash=c[5]&&decodeURIComponent(c[5])||"";this.$$compose()};this.$$compose=function(){var b=ob(this.$$search),c=this.$$hash?"#"+Za(this.$$hash):"";this.$$url=Eb(this.$$path)+(b?"?"+b:"")+c;this.$$absUrl=ka(this.$$protocol,this.$$host,this.$$port)+d+(this.$$url?"#"+a+this.$$url:"")};this.$$rewriteAppUrl=function(a){if(a.indexOf(c)==0)return a};this.$$parse(b)}function Hb(b,a,c,d){Ia.apply(this,arguments);
|
||||
this.$$rewriteAppUrl=function(b){if(b.indexOf(c)==0)return c+d+"#"+a+b.substr(c.length)}}function Ja(b){return function(){return this[b]}}function Ib(b,a){return function(c){if(t(c))return this[b];this[b]=a(c);this.$$compose();return this}}function Ic(){var b="",a=!1;this.hashPrefix=function(a){return v(a)?(b=a,this):b};this.html5Mode=function(b){return v(b)?(a=b,this):a};this.$get=["$rootScope","$browser","$sniffer","$rootElement",function(c,d,e,g){function i(a){c.$broadcast("$locationChangeSuccess",
|
||||
f.absUrl(),a)}var f,h,k,j=d.url(),l=va(j);a?(h=d.baseHref()||"/",k=h.substr(0,h.lastIndexOf("/")),l=ka(l.protocol,l.host,l.port)+k+"/",f=e.history?new gb(Fc(j,h,b),k,l):new Hb(Gc(j,h,b),b,l,h.substr(k.length+1))):(l=ka(l.protocol,l.host,l.port)+(l.path||"")+(l.search?"?"+l.search:"")+"#"+b+"/",f=new Ia(j,b,l));g.bind("click",function(a){if(!a.ctrlKey&&!(a.metaKey||a.which==2)){for(var b=u(a.target);E(b[0].nodeName)!=="a";)if(b[0]===g[0]||!(b=b.parent())[0])return;var d=b.prop("href"),e=f.$$rewriteAppUrl(d);
|
||||
d&&!b.attr("target")&&e&&(f.$$parse(e),c.$apply(),a.preventDefault(),U.angular["ff-684208-preventDefault"]=!0)}});f.absUrl()!=j&&d.url(f.absUrl(),!0);d.onUrlChange(function(a){f.absUrl()!=a&&(c.$evalAsync(function(){var b=f.absUrl();f.$$parse(a);i(b)}),c.$$phase||c.$digest())});var o=0;c.$watch(function(){var a=d.url(),b=f.$$replace;if(!o||a!=f.absUrl())o++,c.$evalAsync(function(){c.$broadcast("$locationChangeStart",f.absUrl(),a).defaultPrevented?f.$$parse(a):(d.url(f.absUrl(),b),i(a))});f.$$replace=
|
||||
!1;return o});return f}]}function Jc(){this.$get=["$window",function(b){function a(a){a instanceof B&&(a.stack?a=a.message&&a.stack.indexOf(a.message)===-1?"Error: "+a.message+"\n"+a.stack:a.stack:a.sourceURL&&(a=a.message+"\n"+a.sourceURL+":"+a.line));return a}function c(c){var e=b.console||{},g=e[c]||e.log||D;return g.apply?function(){var b=[];m(arguments,function(c){b.push(a(c))});return g.apply(e,b)}:function(a,b){g(a,b)}}return{log:c("log"),warn:c("warn"),info:c("info"),error:c("error")}}]}function Kc(b,
|
||||
a){function c(a){return a.indexOf(q)!=-1}function d(){return n+1<b.length?b.charAt(n+1):!1}function e(a){return"0"<=a&&a<="9"}function g(a){return a==" "||a=="\r"||a=="\t"||a=="\n"||a=="\u000b"||a=="\u00a0"}function i(a){return"a"<=a&&a<="z"||"A"<=a&&a<="Z"||"_"==a||a=="$"}function f(a){return a=="-"||a=="+"||e(a)}function h(a,c,d){d=d||n;throw B("Lexer Error: "+a+" at column"+(v(c)?"s "+c+"-"+n+" ["+b.substring(c,d)+"]":" "+d)+" in expression ["+b+"].");}function k(){for(var a="",c=n;n<b.length;){var k=
|
||||
E(b.charAt(n));if(k=="."||e(k))a+=k;else{var g=d();if(k=="e"&&f(g))a+=k;else if(f(k)&&g&&e(g)&&a.charAt(a.length-1)=="e")a+=k;else if(f(k)&&(!g||!e(g))&&a.charAt(a.length-1)=="e")h("Invalid exponent");else break}n++}a*=1;o.push({index:c,text:a,json:!0,fn:function(){return a}})}function j(){for(var c="",d=n,f,k,h;n<b.length;){var j=b.charAt(n);if(j=="."||i(j)||e(j))j=="."&&(f=n),c+=j;else break;n++}if(f)for(k=n;k<b.length;){j=b.charAt(k);if(j=="("){h=c.substr(f-d+1);c=c.substr(0,f-d);n=k;break}if(g(j))k++;
|
||||
else break}d={index:d,text:c};if(Ka.hasOwnProperty(c))d.fn=d.json=Ka[c];else{var l=Jb(c,a);d.fn=x(function(a,b){return l(a,b)},{assign:function(a,b){return Kb(a,c,b)}})}o.push(d);h&&(o.push({index:f,text:".",json:!1}),o.push({index:f+1,text:h,json:!1}))}function l(a){var c=n;n++;for(var d="",e=a,f=!1;n<b.length;){var k=b.charAt(n);e+=k;if(f)k=="u"?(k=b.substring(n+1,n+5),k.match(/[\da-f]{4}/i)||h("Invalid unicode escape [\\u"+k+"]"),n+=4,d+=String.fromCharCode(parseInt(k,16))):(f=Lc[k],d+=f?f:k),
|
||||
f=!1;else if(k=="\\")f=!0;else if(k==a){n++;o.push({index:c,text:e,string:d,json:!0,fn:function(){return d}});return}else d+=k;n++}h("Unterminated quote",c)}for(var o=[],r,n=0,w=[],q,s=":";n<b.length;){q=b.charAt(n);if(c("\"'"))l(q);else if(e(q)||c(".")&&e(d()))k();else if(i(q)){if(j(),"{,".indexOf(s)!=-1&&w[0]=="{"&&(r=o[o.length-1]))r.json=r.text.indexOf(".")==-1}else if(c("(){}[].,;:"))o.push({index:n,text:q,json:":[,".indexOf(s)!=-1&&c("{[")||c("}]:,")}),c("{[")&&w.unshift(q),c("}]")&&w.shift(),
|
||||
n++;else if(g(q)){n++;continue}else{var m=q+d(),C=Ka[q],A=Ka[m];A?(o.push({index:n,text:m,fn:A}),n+=2):C?(o.push({index:n,text:q,fn:C,json:"[,:".indexOf(s)!=-1&&c("+-")}),n+=1):h("Unexpected next character ",n,n+1)}s=q}return o}function Mc(b,a,c,d){function e(a,c){throw B("Syntax Error: Token '"+c.text+"' "+a+" at column "+(c.index+1)+" of the expression ["+b+"] starting at ["+b.substring(c.index)+"].");}function g(){if(M.length===0)throw B("Unexpected end of expression: "+b);return M[0]}function i(a,
|
||||
b,c,d){if(M.length>0){var e=M[0],f=e.text;if(f==a||f==b||f==c||f==d||!a&&!b&&!c&&!d)return e}return!1}function f(b,c,d,f){return(b=i(b,c,d,f))?(a&&!b.json&&e("is not valid json",b),M.shift(),b):!1}function h(a){f(a)||e("is unexpected, expecting ["+a+"]",i())}function k(a,b){return function(c,d){return a(c,d,b)}}function j(a,b,c){return function(d,e){return b(d,e,a,c)}}function l(){for(var a=[];;)if(M.length>0&&!i("}",")",";","]")&&a.push(v()),!f(";"))return a.length==1?a[0]:function(b,c){for(var d,
|
||||
e=0;e<a.length;e++){var f=a[e];f&&(d=f(b,c))}return d}}function o(){for(var a=f(),b=c(a.text),d=[];;)if(a=f(":"))d.push(H());else{var e=function(a,c,e){for(var e=[e],f=0;f<d.length;f++)e.push(d[f](a,c));return b.apply(a,e)};return function(){return e}}}function r(){for(var a=n(),b;;)if(b=f("||"))a=j(a,b.fn,n());else return a}function n(){var a=w(),b;if(b=f("&&"))a=j(a,b.fn,n());return a}function w(){var a=q(),b;if(b=f("==","!="))a=j(a,b.fn,w());return a}function q(){var a;a=s();for(var b;b=f("+",
|
||||
"-");)a=j(a,b.fn,s());if(b=f("<",">","<=",">="))a=j(a,b.fn,q());return a}function s(){for(var a=m(),b;b=f("*","/","%");)a=j(a,b.fn,m());return a}function m(){var a;return f("+")?C():(a=f("-"))?j(W,a.fn,m()):(a=f("!"))?k(a.fn,m()):C()}function C(){var a;if(f("("))a=v(),h(")");else if(f("["))a=A();else if(f("{"))a=K();else{var b=f();(a=b.fn)||e("not a primary expression",b)}for(var c;b=f("(","[",".");)b.text==="("?(a=u(a,c),c=null):b.text==="["?(c=a,a=ea(a)):b.text==="."?(c=a,a=t(a)):e("IMPOSSIBLE");
|
||||
return a}function A(){var a=[];if(g().text!="]"){do a.push(H());while(f(","))}h("]");return function(b,c){for(var d=[],e=0;e<a.length;e++)d.push(a[e](b,c));return d}}function K(){var a=[];if(g().text!="}"){do{var b=f(),b=b.string||b.text;h(":");var c=H();a.push({key:b,value:c})}while(f(","))}h("}");return function(b,c){for(var d={},e=0;e<a.length;e++){var f=a[e],k=f.value(b,c);d[f.key]=k}return d}}var W=I(0),y,M=Kc(b,d),H=function(){var a=r(),c,d;return(d=f("="))?(a.assign||e("implies assignment but ["+
|
||||
b.substring(0,d.index)+"] can not be assigned to",d),c=r(),function(b,d){return a.assign(b,c(b,d),d)}):a},u=function(a,b){var c=[];if(g().text!=")"){do c.push(H());while(f(","))}h(")");return function(d,e){for(var f=[],k=b?b(d,e):d,h=0;h<c.length;h++)f.push(c[h](d,e));h=a(d,e)||D;return h.apply?h.apply(k,f):h(f[0],f[1],f[2],f[3],f[4])}},t=function(a){var b=f().text,c=Jb(b,d);return x(function(b,d){return c(a(b,d),d)},{assign:function(c,d,e){return Kb(a(c,e),b,d)}})},ea=function(a){var b=H();h("]");
|
||||
return x(function(c,d){var e=a(c,d),f=b(c,d),k;if(!e)return p;if((e=e[f])&&e.then){k=e;if(!("$$v"in e))k.$$v=p,k.then(function(a){k.$$v=a});e=e.$$v}return e},{assign:function(c,d,e){return a(c,e)[b(c,e)]=d}})},v=function(){for(var a=H(),b;;)if(b=f("|"))a=j(a,b.fn,o());else return a};a?(H=r,u=t=ea=v=function(){e("is not valid json",{text:b,index:0})},y=C()):y=l();M.length!==0&&e("is an unexpected token",M[0]);return y}function Kb(b,a,c){for(var a=a.split("."),d=0;a.length>1;d++){var e=a.shift(),g=
|
||||
b[e];g||(g={},b[e]=g);b=g}return b[a.shift()]=c}function fb(b,a,c){if(!a)return b;for(var a=a.split("."),d,e=b,g=a.length,i=0;i<g;i++)d=a[i],b&&(b=(e=b)[d]);return!c&&N(b)?Va(e,b):b}function Lb(b,a,c,d,e){return function(g,i){var f=i&&i.hasOwnProperty(b)?i:g,h;if(f===null||f===p)return f;if((f=f[b])&&f.then){if(!("$$v"in f))h=f,h.$$v=p,h.then(function(a){h.$$v=a});f=f.$$v}if(!a||f===null||f===p)return f;if((f=f[a])&&f.then){if(!("$$v"in f))h=f,h.$$v=p,h.then(function(a){h.$$v=a});f=f.$$v}if(!c||f===
|
||||
null||f===p)return f;if((f=f[c])&&f.then){if(!("$$v"in f))h=f,h.$$v=p,h.then(function(a){h.$$v=a});f=f.$$v}if(!d||f===null||f===p)return f;if((f=f[d])&&f.then){if(!("$$v"in f))h=f,h.$$v=p,h.then(function(a){h.$$v=a});f=f.$$v}if(!e||f===null||f===p)return f;if((f=f[e])&&f.then){if(!("$$v"in f))h=f,h.$$v=p,h.then(function(a){h.$$v=a});f=f.$$v}return f}}function Jb(b,a){if(hb.hasOwnProperty(b))return hb[b];var c=b.split("."),d=c.length,e;if(a)e=d<6?Lb(c[0],c[1],c[2],c[3],c[4]):function(a,b){var e=0,
|
||||
k;do k=Lb(c[e++],c[e++],c[e++],c[e++],c[e++])(a,b),b=p,a=k;while(e<d);return k};else{var g="var l, fn, p;\n";m(c,function(a,b){g+="if(s === null || s === undefined) return s;\nl=s;\ns="+(b?"s":'((k&&k.hasOwnProperty("'+a+'"))?k:s)')+'["'+a+'"];\nif (s && s.then) {\n if (!("$$v" in s)) {\n p=s;\n p.$$v = undefined;\n p.then(function(v) {p.$$v=v;});\n}\n s=s.$$v\n}\n'});g+="return s;";e=Function("s","k",g);e.toString=function(){return g}}return hb[b]=e}function Nc(){var b={};this.$get=["$filter","$sniffer",
|
||||
function(a,c){return function(d){switch(typeof d){case "string":return b.hasOwnProperty(d)?b[d]:b[d]=Mc(d,!1,a,c.csp);case "function":return d;default:return D}}}]}function Oc(){this.$get=["$rootScope","$exceptionHandler",function(b,a){return Pc(function(a){b.$evalAsync(a)},a)}]}function Pc(b,a){function c(a){return a}function d(a){return i(a)}var e=function(){var f=[],h,k;return k={resolve:function(a){if(f){var c=f;f=p;h=g(a);c.length&&b(function(){for(var a,b=0,d=c.length;b<d;b++)a=c[b],h.then(a[0],
|
||||
a[1])})}},reject:function(a){k.resolve(i(a))},promise:{then:function(b,k){var g=e(),i=function(d){try{g.resolve((b||c)(d))}catch(e){a(e),g.reject(e)}},n=function(b){try{g.resolve((k||d)(b))}catch(c){a(c),g.reject(c)}};f?f.push([i,n]):h.then(i,n);return g.promise}}}},g=function(a){return a&&a.then?a:{then:function(c){var d=e();b(function(){d.resolve(c(a))});return d.promise}}},i=function(a){return{then:function(c,k){var g=e();b(function(){g.resolve((k||d)(a))});return g.promise}}};return{defer:e,reject:i,
|
||||
when:function(f,h,k){var j=e(),l,o=function(b){try{return(h||c)(b)}catch(d){return a(d),i(d)}},r=function(b){try{return(k||d)(b)}catch(c){return a(c),i(c)}};b(function(){g(f).then(function(a){l||(l=!0,j.resolve(g(a).then(o,r)))},function(a){l||(l=!0,j.resolve(r(a)))})});return j.promise},all:function(a){var b=e(),c=a.length,d=[];c?m(a,function(a,e){g(a).then(function(a){e in d||(d[e]=a,--c||b.resolve(d))},function(a){e in d||b.reject(a)})}):b.resolve(d);return b.promise}}}function Qc(){var b={};this.when=
|
||||
function(a,c){b[a]=x({reloadOnSearch:!0},c);if(a){var d=a[a.length-1]=="/"?a.substr(0,a.length-1):a+"/";b[d]={redirectTo:a}}return this};this.otherwise=function(a){this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache",function(a,c,d,e,g,i,f){function h(){var b=k(),h=r.current;if(b&&h&&b.$route===h.$route&&ha(b.pathParams,h.pathParams)&&!b.reloadOnSearch&&!o)h.params=b.params,V(h.params,d),a.$broadcast("$routeUpdate",h);else if(b||
|
||||
h)o=!1,a.$broadcast("$routeChangeStart",b,h),(r.current=b)&&b.redirectTo&&(F(b.redirectTo)?c.path(j(b.redirectTo,b.params)).search(b.params).replace():c.url(b.redirectTo(b.pathParams,c.path(),c.search())).replace()),e.when(b).then(function(){if(b){var a=[],c=[],d;m(b.resolve||{},function(b,d){a.push(d);c.push(F(b)?g.get(b):g.invoke(b))});if(!v(d=b.template))if(v(d=b.templateUrl))d=i.get(d,{cache:f}).then(function(a){return a.data});v(d)&&(a.push("$template"),c.push(d));return e.all(c).then(function(b){var c=
|
||||
{};m(b,function(b,d){c[a[d]]=b});return c})}}).then(function(c){if(b==r.current){if(b)b.locals=c,V(b.params,d);a.$broadcast("$routeChangeSuccess",b,h)}},function(c){b==r.current&&a.$broadcast("$routeChangeError",b,h,c)})}function k(){var a,d;m(b,function(b,e){if(!d&&(a=l(c.path(),e)))d=ya(b,{params:x({},c.search(),a),pathParams:a}),d.$route=b});return d||b[null]&&ya(b[null],{params:{},pathParams:{}})}function j(a,b){var c=[];m((a||"").split(":"),function(a,d){if(d==0)c.push(a);else{var e=a.match(/(\w+)(.*)/),
|
||||
f=e[1];c.push(b[f]);c.push(e[2]||"");delete b[f]}});return c.join("")}var l=function(a,b){var c="^"+b.replace(/([\.\\\(\)\^\$])/g,"\\$1")+"$",d=[],e={};m(b.split(/\W/),function(a){if(a){var b=RegExp(":"+a+"([\\W])");c.match(b)&&(c=c.replace(b,"([^\\/]*)$1"),d.push(a))}});var f=a.match(RegExp(c));f&&m(d,function(a,b){e[a]=f[b+1]});return f?e:null},o=!1,r={routes:b,reload:function(){o=!0;a.$evalAsync(h)}};a.$on("$locationChangeSuccess",h);return r}]}function Rc(){this.$get=I({})}function Sc(){var b=
|
||||
10;this.digestTtl=function(a){arguments.length&&(b=a);return b};this.$get=["$injector","$exceptionHandler","$parse",function(a,c,d){function e(){this.$id=xa();this.$$phase=this.$parent=this.$$watchers=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null;this["this"]=this.$root=this;this.$$asyncQueue=[];this.$$listeners={}}function g(a){if(h.$$phase)throw B(h.$$phase+" already in progress");h.$$phase=a}function i(a,b){var c=d(a);ra(c,b);return c}function f(){}e.prototype={$new:function(a){if(N(a))throw B("API-CHANGE: Use $controller to instantiate controllers.");
|
||||
a?(a=new e,a.$root=this.$root):(a=function(){},a.prototype=this,a=new a,a.$id=xa());a["this"]=a;a.$$listeners={};a.$parent=this;a.$$asyncQueue=[];a.$$watchers=a.$$nextSibling=a.$$childHead=a.$$childTail=null;a.$$prevSibling=this.$$childTail;this.$$childHead?this.$$childTail=this.$$childTail.$$nextSibling=a:this.$$childHead=this.$$childTail=a;return a},$watch:function(a,b,c){var d=i(a,"watch"),e=this.$$watchers,g={fn:b,last:f,get:d,exp:a,eq:!!c};if(!N(b)){var h=i(b||D,"listener");g.fn=function(a,b,
|
||||
c){h(c)}}if(!e)e=this.$$watchers=[];e.unshift(g);return function(){Ua(e,g)}},$digest:function(){var a,d,e,i,r,n,m,q=b,s,p=[],C,A;g("$digest");do{m=!1;s=this;do{for(r=s.$$asyncQueue;r.length;)try{s.$eval(r.shift())}catch(K){c(K)}if(i=s.$$watchers)for(n=i.length;n--;)try{if(a=i[n],(d=a.get(s))!==(e=a.last)&&!(a.eq?ha(d,e):typeof d=="number"&&typeof e=="number"&&isNaN(d)&&isNaN(e)))m=!0,a.last=a.eq?V(d):d,a.fn(d,e===f?d:e,s),q<5&&(C=4-q,p[C]||(p[C]=[]),A=N(a.exp)?"fn: "+(a.exp.name||a.exp.toString()):
|
||||
a.exp,A+="; newVal: "+da(d)+"; oldVal: "+da(e),p[C].push(A))}catch(W){c(W)}if(!(i=s.$$childHead||s!==this&&s.$$nextSibling))for(;s!==this&&!(i=s.$$nextSibling);)s=s.$parent}while(s=i);if(m&&!q--)throw h.$$phase=null,B(b+" $digest() iterations reached. Aborting!\nWatchers fired in the last 5 iterations: "+da(p));}while(m||r.length);h.$$phase=null},$destroy:function(){if(h!=this){var a=this.$parent;this.$broadcast("$destroy");if(a.$$childHead==this)a.$$childHead=this.$$nextSibling;if(a.$$childTail==
|
||||
this)a.$$childTail=this.$$prevSibling;if(this.$$prevSibling)this.$$prevSibling.$$nextSibling=this.$$nextSibling;if(this.$$nextSibling)this.$$nextSibling.$$prevSibling=this.$$prevSibling;this.$parent=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null}},$eval:function(a,b){return d(a)(this,b)},$evalAsync:function(a){this.$$asyncQueue.push(a)},$apply:function(a){try{return g("$apply"),this.$eval(a)}catch(b){c(b)}finally{h.$$phase=null;try{h.$digest()}catch(d){throw c(d),d;}}},
|
||||
$on:function(a,b){var c=this.$$listeners[a];c||(this.$$listeners[a]=c=[]);c.push(b);return function(){c[za(c,b)]=null}},$emit:function(a,b){var d=[],e,f=this,g=!1,h={name:a,targetScope:f,stopPropagation:function(){g=!0},preventDefault:function(){h.defaultPrevented=!0},defaultPrevented:!1},i=[h].concat(ia.call(arguments,1)),m,p;do{e=f.$$listeners[a]||d;h.currentScope=f;m=0;for(p=e.length;m<p;m++)if(e[m])try{if(e[m].apply(null,i),g)return h}catch(C){c(C)}else e.splice(m,1),m--,p--;f=f.$parent}while(f);
|
||||
return h},$broadcast:function(a,b){var d=this,e=this,f={name:a,targetScope:this,preventDefault:function(){f.defaultPrevented=!0},defaultPrevented:!1},g=[f].concat(ia.call(arguments,1)),h,i;do{d=e;f.currentScope=d;e=d.$$listeners[a]||[];h=0;for(i=e.length;h<i;h++)if(e[h])try{e[h].apply(null,g)}catch(m){c(m)}else e.splice(h,1),h--,i--;if(!(e=d.$$childHead||d!==this&&d.$$nextSibling))for(;d!==this&&!(e=d.$$nextSibling);)d=d.$parent}while(d=e);return f}};var h=new e;return h}]}function Tc(){this.$get=
|
||||
["$window",function(b){var a={},c=G((/android (\d+)/.exec(E(b.navigator.userAgent))||[])[1]);return{history:!(!b.history||!b.history.pushState||c<4),hashchange:"onhashchange"in b&&(!b.document.documentMode||b.document.documentMode>7),hasEvent:function(c){if(c=="input"&&aa==9)return!1;if(t(a[c])){var e=b.document.createElement("div");a[c]="on"+c in e}return a[c]},csp:!1}}]}function Uc(){this.$get=I(U)}function Mb(b){var a={},c,d,e;if(!b)return a;m(b.split("\n"),function(b){e=b.indexOf(":");c=E(R(b.substr(0,
|
||||
e)));d=R(b.substr(e+1));c&&(a[c]?a[c]+=", "+d:a[c]=d)});return a}function Nb(b){var a=L(b)?b:p;return function(c){a||(a=Mb(b));return c?a[E(c)]||null:a}}function Ob(b,a,c){if(N(c))return c(b,a);m(c,function(c){b=c(b,a)});return b}function Vc(){var b=/^\s*(\[|\{[^\{])/,a=/[\}\]]\s*$/,c=/^\)\]\}',?\n/,d=this.defaults={transformResponse:[function(d){F(d)&&(d=d.replace(c,""),b.test(d)&&a.test(d)&&(d=nb(d,!0)));return d}],transformRequest:[function(a){return L(a)&&Sa.apply(a)!=="[object File]"?da(a):a}],
|
||||
headers:{common:{Accept:"application/json, text/plain, */*","X-Requested-With":"XMLHttpRequest"},post:{"Content-Type":"application/json;charset=utf-8"},put:{"Content-Type":"application/json;charset=utf-8"}}},e=this.responseInterceptors=[];this.$get=["$httpBackend","$browser","$cacheFactory","$rootScope","$q","$injector",function(a,b,c,h,k,j){function l(a){function c(a){var b=x({},a,{data:Ob(a.data,a.headers,f)});return 200<=a.status&&a.status<300?b:k.reject(b)}a.method=la(a.method);var e=a.transformRequest||
|
||||
d.transformRequest,f=a.transformResponse||d.transformResponse,h=d.headers,h=x({"X-XSRF-TOKEN":b.cookies()["XSRF-TOKEN"]},h.common,h[E(a.method)],a.headers),e=Ob(a.data,Nb(h),e),g;t(a.data)&&delete h["Content-Type"];g=o(a,e,h);g=g.then(c,c);m(w,function(a){g=a(g)});g.success=function(b){g.then(function(c){b(c.data,c.status,c.headers,a)});return g};g.error=function(b){g.then(null,function(c){b(c.data,c.status,c.headers,a)});return g};return g}function o(b,c,d){function e(a,b,c){m&&(200<=a&&a<300?m.put(w,
|
||||
[a,b,Mb(c)]):m.remove(w));f(b,a,c);h.$apply()}function f(a,c,d){c=Math.max(c,0);(200<=c&&c<300?j.resolve:j.reject)({data:a,status:c,headers:Nb(d),config:b})}function i(){var a=za(l.pendingRequests,b);a!==-1&&l.pendingRequests.splice(a,1)}var j=k.defer(),o=j.promise,m,p,w=r(b.url,b.params);l.pendingRequests.push(b);o.then(i,i);b.cache&&b.method=="GET"&&(m=L(b.cache)?b.cache:n);if(m)if(p=m.get(w))if(p.then)return p.then(i,i),p;else J(p)?f(p[1],p[0],V(p[2])):f(p,200,{});else m.put(w,o);p||a(b.method,
|
||||
w,c,e,d,b.timeout,b.withCredentials);return o}function r(a,b){if(!b)return a;var c=[];ec(b,function(a,b){a==null||a==p||(L(a)&&(a=da(a)),c.push(encodeURIComponent(b)+"="+encodeURIComponent(a)))});return a+(a.indexOf("?")==-1?"?":"&")+c.join("&")}var n=c("$http"),w=[];m(e,function(a){w.push(F(a)?j.get(a):j.invoke(a))});l.pendingRequests=[];(function(a){m(arguments,function(a){l[a]=function(b,c){return l(x(c||{},{method:a,url:b}))}})})("get","delete","head","jsonp");(function(a){m(arguments,function(a){l[a]=
|
||||
function(b,c,d){return l(x(d||{},{method:a,url:b,data:c}))}})})("post","put");l.defaults=d;return l}]}function Wc(){this.$get=["$browser","$window","$document",function(b,a,c){return Xc(b,Yc,b.defer,a.angular.callbacks,c[0],a.location.protocol.replace(":",""))}]}function Xc(b,a,c,d,e,g){function i(a,b){var c=e.createElement("script"),d=function(){e.body.removeChild(c);b&&b()};c.type="text/javascript";c.src=a;aa?c.onreadystatechange=function(){/loaded|complete/.test(c.readyState)&&d()}:c.onload=c.onerror=
|
||||
d;e.body.appendChild(c)}return function(e,h,k,j,l,o,r){function n(a,c,d,e){c=(h.match(Fb)||["",g])[1]=="file"?d?200:404:c;a(c==1223?204:c,d,e);b.$$completeOutstandingRequest(D)}b.$$incOutstandingRequestCount();h=h||b.url();if(E(e)=="jsonp"){var p="_"+(d.counter++).toString(36);d[p]=function(a){d[p].data=a};i(h.replace("JSON_CALLBACK","angular.callbacks."+p),function(){d[p].data?n(j,200,d[p].data):n(j,-2);delete d[p]})}else{var q=new a;q.open(e,h,!0);m(l,function(a,b){a&&q.setRequestHeader(b,a)});
|
||||
var s;q.onreadystatechange=function(){q.readyState==4&&n(j,s||q.status,q.responseText,q.getAllResponseHeaders())};if(r)q.withCredentials=!0;q.send(k||"");o>0&&c(function(){s=-1;q.abort()},o)}}}function Zc(){this.$get=function(){return{id:"en-us",NUMBER_FORMATS:{DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{minInt:1,minFrac:0,maxFrac:3,posPre:"",posSuf:"",negPre:"-",negSuf:"",gSize:3,lgSize:3},{minInt:1,minFrac:2,maxFrac:2,posPre:"\u00a4",posSuf:"",negPre:"(\u00a4",negSuf:")",gSize:3,lgSize:3}],CURRENCY_SYM:"$"},
|
||||
DATETIME_FORMATS:{MONTH:"January,February,March,April,May,June,July,August,September,October,November,December".split(","),SHORTMONTH:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec".split(","),DAY:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday".split(","),SHORTDAY:"Sun,Mon,Tue,Wed,Thu,Fri,Sat".split(","),AMPMS:["AM","PM"],medium:"MMM d, y h:mm:ss a","short":"M/d/yy h:mm a",fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",mediumDate:"MMM d, y",shortDate:"M/d/yy",mediumTime:"h:mm:ss a",
|
||||
shortTime:"h:mm a"},pluralCat:function(b){return b===1?"one":"other"}}}}function $c(){this.$get=["$rootScope","$browser","$q","$exceptionHandler",function(b,a,c,d){function e(e,f,h){var k=c.defer(),j=k.promise,l=v(h)&&!h,f=a.defer(function(){try{k.resolve(e())}catch(a){k.reject(a),d(a)}l||b.$apply()},f),h=function(){delete g[j.$$timeoutId]};j.$$timeoutId=f;g[f]=k;j.then(h,h);return j}var g={};e.cancel=function(b){return b&&b.$$timeoutId in g?(g[b.$$timeoutId].reject("canceled"),a.defer.cancel(b.$$timeoutId)):
|
||||
!1};return e}]}function Pb(b){function a(a,e){return b.factory(a+c,e)}var c="Filter";this.register=a;this.$get=["$injector",function(a){return function(b){return a.get(b+c)}}];a("currency",Qb);a("date",Rb);a("filter",ad);a("json",bd);a("limitTo",cd);a("lowercase",dd);a("number",Sb);a("orderBy",Tb);a("uppercase",ed)}function ad(){return function(b,a){if(!(b instanceof Array))return b;var c=[];c.check=function(a){for(var b=0;b<c.length;b++)if(!c[b](a))return!1;return!0};var d=function(a,b){if(b.charAt(0)===
|
||||
"!")return!d(a,b.substr(1));switch(typeof a){case "boolean":case "number":case "string":return(""+a).toLowerCase().indexOf(b)>-1;case "object":for(var c in a)if(c.charAt(0)!=="$"&&d(a[c],b))return!0;return!1;case "array":for(c=0;c<a.length;c++)if(d(a[c],b))return!0;return!1;default:return!1}};switch(typeof a){case "boolean":case "number":case "string":a={$:a};case "object":for(var e in a)e=="$"?function(){var b=(""+a[e]).toLowerCase();b&&c.push(function(a){return d(a,b)})}():function(){var b=e,f=
|
||||
(""+a[e]).toLowerCase();f&&c.push(function(a){return d(fb(a,b),f)})}();break;case "function":c.push(a);break;default:return b}for(var g=[],i=0;i<b.length;i++){var f=b[i];c.check(f)&&g.push(f)}return g}}function Qb(b){var a=b.NUMBER_FORMATS;return function(b,d){if(t(d))d=a.CURRENCY_SYM;return Ub(b,a.PATTERNS[1],a.GROUP_SEP,a.DECIMAL_SEP,2).replace(/\u00A4/g,d)}}function Sb(b){var a=b.NUMBER_FORMATS;return function(b,d){return Ub(b,a.PATTERNS[0],a.GROUP_SEP,a.DECIMAL_SEP,d)}}function Ub(b,a,c,d,e){if(isNaN(b)||
|
||||
!isFinite(b))return"";var g=b<0,b=Math.abs(b),i=b+"",f="",h=[],k=!1;if(i.indexOf("e")!==-1){var j=i.match(/([\d\.]+)e(-?)(\d+)/);j&&j[2]=="-"&&j[3]>e+1?i="0":(f=i,k=!0)}if(!k){i=(i.split(Vb)[1]||"").length;t(e)&&(e=Math.min(Math.max(a.minFrac,i),a.maxFrac));var i=Math.pow(10,e),b=Math.round(b*i)/i,b=(""+b).split(Vb),i=b[0],b=b[1]||"",k=0,j=a.lgSize,l=a.gSize;if(i.length>=j+l)for(var k=i.length-j,o=0;o<k;o++)(k-o)%l===0&&o!==0&&(f+=c),f+=i.charAt(o);for(o=k;o<i.length;o++)(i.length-o)%j===0&&o!==0&&
|
||||
(f+=c),f+=i.charAt(o);for(;b.length<e;)b+="0";e&&(f+=d+b.substr(0,e))}h.push(g?a.negPre:a.posPre);h.push(f);h.push(g?a.negSuf:a.posSuf);return h.join("")}function ib(b,a,c){var d="";b<0&&(d="-",b=-b);for(b=""+b;b.length<a;)b="0"+b;c&&(b=b.substr(b.length-a));return d+b}function P(b,a,c,d){return function(e){e=e["get"+b]();if(c>0||e>-c)e+=c;e===0&&c==-12&&(e=12);return ib(e,a,d)}}function La(b,a){return function(c,d){var e=c["get"+b](),g=la(a?"SHORT"+b:b);return d[g][e]}}function Rb(b){function a(a){var b;
|
||||
if(b=a.match(c)){var a=new Date(0),g=0,i=0;b[9]&&(g=G(b[9]+b[10]),i=G(b[9]+b[11]));a.setUTCFullYear(G(b[1]),G(b[2])-1,G(b[3]));a.setUTCHours(G(b[4]||0)-g,G(b[5]||0)-i,G(b[6]||0),G(b[7]||0))}return a}var c=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;return function(c,e){var g="",i=[],f,h,e=e||"mediumDate",e=b.DATETIME_FORMATS[e]||e;F(c)&&(c=fd.test(c)?G(c):a(c));wa(c)&&(c=new Date(c));if(!na(c))return c;for(;e;)(h=gd.exec(e))?(i=i.concat(ia.call(h,
|
||||
1)),e=i.pop()):(i.push(e),e=null);m(i,function(a){f=hd[a];g+=f?f(c,b.DATETIME_FORMATS):a.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return g}}function bd(){return function(b){return da(b,!0)}}function cd(){return function(b,a){if(!(b instanceof Array))return b;var a=G(a),c=[],d,e;if(!b||!(b instanceof Array))return c;a>b.length?a=b.length:a<-b.length&&(a=-b.length);a>0?(d=0,e=a):(d=b.length+a,e=b.length);for(;d<e;d++)c.push(b[d]);return c}}function Tb(b){return function(a,c,d){function e(a,b){return Wa(b)?
|
||||
function(b,c){return a(c,b)}:a}if(!(a instanceof Array))return a;if(!c)return a;for(var c=J(c)?c:[c],c=Ta(c,function(a){var c=!1,d=a||ma;if(F(a)){if(a.charAt(0)=="+"||a.charAt(0)=="-")c=a.charAt(0)=="-",a=a.substring(1);d=b(a)}return e(function(a,b){var c;c=d(a);var e=d(b),f=typeof c,g=typeof e;f==g?(f=="string"&&(c=c.toLowerCase()),f=="string"&&(e=e.toLowerCase()),c=c===e?0:c<e?-1:1):c=f<g?-1:1;return c},c)}),g=[],i=0;i<a.length;i++)g.push(a[i]);return g.sort(e(function(a,b){for(var d=0;d<c.length;d++){var e=
|
||||
c[d](a,b);if(e!==0)return e}return 0},d))}}function S(b){N(b)&&(b={link:b});b.restrict=b.restrict||"AC";return I(b)}function Wb(b,a){function c(a,c){c=c?"-"+$a(c,"-"):"";b.removeClass((a?Ma:Na)+c).addClass((a?Na:Ma)+c)}var d=this,e=b.parent().controller("form")||Oa,g=0,i=d.$error={};d.$name=a.name;d.$dirty=!1;d.$pristine=!0;d.$valid=!0;d.$invalid=!1;e.$addControl(d);b.addClass(Pa);c(!0);d.$addControl=function(a){a.$name&&!d.hasOwnProperty(a.$name)&&(d[a.$name]=a)};d.$removeControl=function(a){a.$name&&
|
||||
d[a.$name]===a&&delete d[a.$name];m(i,function(b,c){d.$setValidity(c,!0,a)})};d.$setValidity=function(a,b,k){var j=i[a];if(b){if(j&&(Ua(j,k),!j.length)){g--;if(!g)c(b),d.$valid=!0,d.$invalid=!1;i[a]=!1;c(!0,a);e.$setValidity(a,!0,d)}}else{g||c(b);if(j){if(za(j,k)!=-1)return}else i[a]=j=[],g++,c(!1,a),e.$setValidity(a,!1,d);j.push(k);d.$valid=!1;d.$invalid=!0}};d.$setDirty=function(){b.removeClass(Pa).addClass(Xb);d.$dirty=!0;d.$pristine=!1;e.$setDirty()}}function T(b){return t(b)||b===""||b===null||
|
||||
b!==b}function Qa(b,a,c,d,e,g){var i=function(){var c=R(a.val());d.$viewValue!==c&&b.$apply(function(){d.$setViewValue(c)})};if(e.hasEvent("input"))a.bind("input",i);else{var f;a.bind("keydown",function(a){a=a.keyCode;a===91||15<a&&a<19||37<=a&&a<=40||f||(f=g.defer(function(){i();f=null}))});a.bind("change",i)}d.$render=function(){a.val(T(d.$viewValue)?"":d.$viewValue)};var h=c.ngPattern,k=function(a,b){return T(b)||a.test(b)?(d.$setValidity("pattern",!0),b):(d.$setValidity("pattern",!1),p)};h&&(h.match(/^\/(.*)\/$/)?
|
||||
(h=RegExp(h.substr(1,h.length-2)),e=function(a){return k(h,a)}):e=function(a){var c=b.$eval(h);if(!c||!c.test)throw new B("Expected "+h+" to be a RegExp but was "+c);return k(c,a)},d.$formatters.push(e),d.$parsers.push(e));if(c.ngMinlength){var j=G(c.ngMinlength),e=function(a){return!T(a)&&a.length<j?(d.$setValidity("minlength",!1),p):(d.$setValidity("minlength",!0),a)};d.$parsers.push(e);d.$formatters.push(e)}if(c.ngMaxlength){var l=G(c.ngMaxlength),c=function(a){return!T(a)&&a.length>l?(d.$setValidity("maxlength",
|
||||
!1),p):(d.$setValidity("maxlength",!0),a)};d.$parsers.push(c);d.$formatters.push(c)}}function jb(b,a){b="ngClass"+b;return S(function(c,d,e){function g(b,d){if(a===!0||c.$index%2===a)d&&b!==d&&i(d),f(b)}function i(a){L(a)&&!J(a)&&(a=Ta(a,function(a,b){if(a)return b}));d.removeClass(J(a)?a.join(" "):a)}function f(a){L(a)&&!J(a)&&(a=Ta(a,function(a,b){if(a)return b}));a&&d.addClass(J(a)?a.join(" "):a)}c.$watch(e[b],g,!0);e.$observe("class",function(){var a=c.$eval(e[b]);g(a,a)});b!=="ngClass"&&c.$watch("$index",
|
||||
function(d,g){var j=d%2;j!==g%2&&(j==a?f(c.$eval(e[b])):i(c.$eval(e[b])))})})}var E=function(b){return F(b)?b.toLowerCase():b},la=function(b){return F(b)?b.toUpperCase():b},B=U.Error,aa=G((/msie (\d+)/.exec(E(navigator.userAgent))||[])[1]),u,ja,ia=[].slice,Ra=[].push,Sa=Object.prototype.toString,Yb=U.angular||(U.angular={}),ta,Cb,Z=["0","0","0"];D.$inject=[];ma.$inject=[];Cb=aa<9?function(b){b=b.nodeName?b:b[0];return b.scopeName&&b.scopeName!="HTML"?la(b.scopeName+":"+b.nodeName):b.nodeName}:function(b){return b.nodeName?
|
||||
b.nodeName:b[0].nodeName};var kc=/[A-Z]/g,id={full:"1.0.3",major:1,minor:0,dot:3,codeName:"bouncy-thunder"},Ba=Q.cache={},Aa=Q.expando="ng-"+(new Date).getTime(),oc=1,Zb=U.document.addEventListener?function(b,a,c){b.addEventListener(a,c,!1)}:function(b,a,c){b.attachEvent("on"+a,c)},db=U.document.removeEventListener?function(b,a,c){b.removeEventListener(a,c,!1)}:function(b,a,c){b.detachEvent("on"+a,c)},mc=/([\:\-\_]+(.))/g,nc=/^moz([A-Z])/,ua=Q.prototype={ready:function(b){function a(){c||(c=!0,b())}
|
||||
var c=!1;this.bind("DOMContentLoaded",a);Q(U).bind("load",a)},toString:function(){var b=[];m(this,function(a){b.push(""+a)});return"["+b.join(", ")+"]"},eq:function(b){return b>=0?u(this[b]):u(this[this.length+b])},length:0,push:Ra,sort:[].sort,splice:[].splice},Ea={};m("multiple,selected,checked,disabled,readOnly,required".split(","),function(b){Ea[E(b)]=b});var zb={};m("input,select,option,textarea,button,form".split(","),function(b){zb[la(b)]=!0});m({data:ub,inheritedData:Da,scope:function(b){return Da(b,
|
||||
"$scope")},controller:xb,injector:function(b){return Da(b,"$injector")},removeAttr:function(b,a){b.removeAttribute(a)},hasClass:Ca,css:function(b,a,c){a=rb(a);if(v(c))b.style[a]=c;else{var d;aa<=8&&(d=b.currentStyle&&b.currentStyle[a],d===""&&(d="auto"));d=d||b.style[a];aa<=8&&(d=d===""?p:d);return d}},attr:function(b,a,c){var d=E(a);if(Ea[d])if(v(c))c?(b[a]=!0,b.setAttribute(a,d)):(b[a]=!1,b.removeAttribute(d));else return b[a]||(b.attributes.getNamedItem(a)||D).specified?d:p;else if(v(c))b.setAttribute(a,
|
||||
c);else if(b.getAttribute)return b=b.getAttribute(a,2),b===null?p:b},prop:function(b,a,c){if(v(c))b[a]=c;else return b[a]},text:x(aa<9?function(b,a){if(b.nodeType==1){if(t(a))return b.innerText;b.innerText=a}else{if(t(a))return b.nodeValue;b.nodeValue=a}}:function(b,a){if(t(a))return b.textContent;b.textContent=a},{$dv:""}),val:function(b,a){if(t(a))return b.value;b.value=a},html:function(b,a){if(t(a))return b.innerHTML;for(var c=0,d=b.childNodes;c<d.length;c++)sa(d[c]);b.innerHTML=a}},function(b,
|
||||
a){Q.prototype[a]=function(a,d){var e,g;if((b.length==2&&b!==Ca&&b!==xb?a:d)===p)if(L(a)){for(e=0;e<this.length;e++)if(b===ub)b(this[e],a);else for(g in a)b(this[e],g,a[g]);return this}else{if(this.length)return b(this[0],a,d)}else{for(e=0;e<this.length;e++)b(this[e],a,d);return this}return b.$dv}});m({removeData:sb,dealoc:sa,bind:function a(c,d,e){var g=$(c,"events"),i=$(c,"handle");g||$(c,"events",g={});i||$(c,"handle",i=pc(c,g));m(d.split(" "),function(d){var h=g[d];if(!h){if(d=="mouseenter"||
|
||||
d=="mouseleave"){var k=0;g.mouseenter=[];g.mouseleave=[];a(c,"mouseover",function(a){k++;k==1&&i(a,"mouseenter")});a(c,"mouseout",function(a){k--;k==0&&i(a,"mouseleave")})}else Zb(c,d,i),g[d]=[];h=g[d]}h.push(e)})},unbind:tb,replaceWith:function(a,c){var d,e=a.parentNode;sa(a);m(new Q(c),function(c){d?e.insertBefore(c,d.nextSibling):e.replaceChild(c,a);d=c})},children:function(a){var c=[];m(a.childNodes,function(a){a.nodeName!="#text"&&c.push(a)});return c},contents:function(a){return a.childNodes},
|
||||
append:function(a,c){m(new Q(c),function(c){a.nodeType===1&&a.appendChild(c)})},prepend:function(a,c){if(a.nodeType===1){var d=a.firstChild;m(new Q(c),function(c){d?a.insertBefore(c,d):(a.appendChild(c),d=c)})}},wrap:function(a,c){var c=u(c)[0],d=a.parentNode;d&&d.replaceChild(c,a);c.appendChild(a)},remove:function(a){sa(a);var c=a.parentNode;c&&c.removeChild(a)},after:function(a,c){var d=a,e=a.parentNode;m(new Q(c),function(a){e.insertBefore(a,d.nextSibling);d=a})},addClass:wb,removeClass:vb,toggleClass:function(a,
|
||||
c,d){t(d)&&(d=!Ca(a,c));(d?wb:vb)(a,c)},parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},next:function(a){return a.nextSibling},find:function(a,c){return a.getElementsByTagName(c)},clone:cb,triggerHandler:function(a,c){var d=($(a,"events")||{})[c];m(d,function(c){c.call(a,null)})}},function(a,c){Q.prototype[c]=function(c,e){for(var g,i=0;i<this.length;i++)g==p?(g=a(this[i],c,e),g!==p&&(g=u(g))):bb(g,a(this[i],c,e));return g==p?this:g}});Fa.prototype={put:function(a,c){this[ga(a)]=
|
||||
c},get:function(a){return this[ga(a)]},remove:function(a){var c=this[a=ga(a)];delete this[a];return c}};eb.prototype={push:function(a,c){var d=this[a=ga(a)];d?d.push(c):this[a]=[c]},shift:function(a){var c=this[a=ga(a)];if(c)return c.length==1?(delete this[a],c[0]):c.shift()},peek:function(a){if(a=this[ga(a)])return a[0]}};var rc=/^function\s*[^\(]*\(\s*([^\)]*)\)/m,sc=/,/,tc=/^\s*(_?)(\S+?)\1\s*$/,qc=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,Db="Non-assignable model expression: ";Bb.$inject=["$provide"];
|
||||
var Ac=/^(x[\:\-_]|data[\:\-_])/i,Fb=/^([^:]+):\/\/(\w+:{0,1}\w*@)?([\w\.-]*)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/,$b=/^([^\?#]*)?(\?([^#]*))?(#(.*))?$/,Hc=$b,Gb={http:80,https:443,ftp:21};gb.prototype={$$replace:!1,absUrl:Ja("$$absUrl"),url:function(a,c){if(t(a))return this.$$url;var d=$b.exec(a);d[1]&&this.path(decodeURIComponent(d[1]));if(d[2]||d[1])this.search(d[3]||"");this.hash(d[5]||"",c);return this},protocol:Ja("$$protocol"),host:Ja("$$host"),port:Ja("$$port"),path:Ib("$$path",function(a){return a.charAt(0)==
|
||||
"/"?a:"/"+a}),search:function(a,c){if(t(a))return this.$$search;v(c)?c===null?delete this.$$search[a]:this.$$search[a]=c:this.$$search=F(a)?Xa(a):a;this.$$compose();return this},hash:Ib("$$hash",ma),replace:function(){this.$$replace=!0;return this}};Ia.prototype=ya(gb.prototype);Hb.prototype=ya(Ia.prototype);var Ka={"null":function(){return null},"true":function(){return!0},"false":function(){return!1},undefined:D,"+":function(a,c,d,e){d=d(a,c);e=e(a,c);return v(d)?v(e)?d+e:d:v(e)?e:p},"-":function(a,
|
||||
c,d,e){d=d(a,c);e=e(a,c);return(v(d)?d:0)-(v(e)?e:0)},"*":function(a,c,d,e){return d(a,c)*e(a,c)},"/":function(a,c,d,e){return d(a,c)/e(a,c)},"%":function(a,c,d,e){return d(a,c)%e(a,c)},"^":function(a,c,d,e){return d(a,c)^e(a,c)},"=":D,"==":function(a,c,d,e){return d(a,c)==e(a,c)},"!=":function(a,c,d,e){return d(a,c)!=e(a,c)},"<":function(a,c,d,e){return d(a,c)<e(a,c)},">":function(a,c,d,e){return d(a,c)>e(a,c)},"<=":function(a,c,d,e){return d(a,c)<=e(a,c)},">=":function(a,c,d,e){return d(a,c)>=e(a,
|
||||
c)},"&&":function(a,c,d,e){return d(a,c)&&e(a,c)},"||":function(a,c,d,e){return d(a,c)||e(a,c)},"&":function(a,c,d,e){return d(a,c)&e(a,c)},"|":function(a,c,d,e){return e(a,c)(a,c,d(a,c))},"!":function(a,c,d){return!d(a,c)}},Lc={n:"\n",f:"\u000c",r:"\r",t:"\t",v:"\u000b","'":"'",'"':'"'},hb={},Yc=U.XMLHttpRequest||function(){try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(c){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(d){}throw new B("This browser does not support XMLHttpRequest.");
|
||||
};Pb.$inject=["$provide"];Qb.$inject=["$locale"];Sb.$inject=["$locale"];var Vb=".",hd={yyyy:P("FullYear",4),yy:P("FullYear",2,0,!0),y:P("FullYear",1),MMMM:La("Month"),MMM:La("Month",!0),MM:P("Month",2,1),M:P("Month",1,1),dd:P("Date",2),d:P("Date",1),HH:P("Hours",2),H:P("Hours",1),hh:P("Hours",2,-12),h:P("Hours",1,-12),mm:P("Minutes",2),m:P("Minutes",1),ss:P("Seconds",2),s:P("Seconds",1),EEEE:La("Day"),EEE:La("Day",!0),a:function(a,c){return a.getHours()<12?c.AMPMS[0]:c.AMPMS[1]},Z:function(a){a=a.getTimezoneOffset();
|
||||
return ib(a/60,2)+ib(Math.abs(a%60),2)}},gd=/((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,fd=/^\d+$/;Rb.$inject=["$locale"];var dd=I(E),ed=I(la);Tb.$inject=["$parse"];var jd=I({restrict:"E",compile:function(a,c){c.href||c.$set("href","");return function(a,c){c.bind("click",function(a){if(!c.attr("href"))return a.preventDefault(),!1})}}}),kb={};m(Ea,function(a,c){var d=fa("ng-"+c);kb[d]=function(){return{priority:100,compile:function(){return function(a,g,i){a.$watch(i[d],
|
||||
function(a){i.$set(c,!!a)})}}}}});m(["src","href"],function(a){var c=fa("ng-"+a);kb[c]=function(){return{priority:99,link:function(d,e,g){g.$observe(c,function(c){c&&(g.$set(a,c),aa&&e.prop(a,c))})}}}});var Oa={$addControl:D,$removeControl:D,$setValidity:D,$setDirty:D};Wb.$inject=["$element","$attrs","$scope"];var Ra=function(a){return["$timeout",function(c){var d={name:"form",restrict:"E",controller:Wb,compile:function(){return{pre:function(a,d,i,f){if(!i.action){var h=function(a){a.preventDefault?
|
||||
a.preventDefault():a.returnValue=!1};Zb(d[0],"submit",h);d.bind("$destroy",function(){c(function(){db(d[0],"submit",h)},0,!1)})}var k=d.parent().controller("form"),j=i.name||i.ngForm;j&&(a[j]=f);k&&d.bind("$destroy",function(){k.$removeControl(f);j&&(a[j]=p);x(f,Oa)})}}}};return a?x(V(d),{restrict:"EAC"}):d}]},kd=Ra(),ld=Ra(!0),md=/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/,nd=/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/,od=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/,
|
||||
ac={text:Qa,number:function(a,c,d,e,g,i){Qa(a,c,d,e,g,i);e.$parsers.push(function(a){var c=T(a);return c||od.test(a)?(e.$setValidity("number",!0),a===""?null:c?a:parseFloat(a)):(e.$setValidity("number",!1),p)});e.$formatters.push(function(a){return T(a)?"":""+a});if(d.min){var f=parseFloat(d.min),a=function(a){return!T(a)&&a<f?(e.$setValidity("min",!1),p):(e.$setValidity("min",!0),a)};e.$parsers.push(a);e.$formatters.push(a)}if(d.max){var h=parseFloat(d.max),d=function(a){return!T(a)&&a>h?(e.$setValidity("max",
|
||||
!1),p):(e.$setValidity("max",!0),a)};e.$parsers.push(d);e.$formatters.push(d)}e.$formatters.push(function(a){return T(a)||wa(a)?(e.$setValidity("number",!0),a):(e.$setValidity("number",!1),p)})},url:function(a,c,d,e,g,i){Qa(a,c,d,e,g,i);a=function(a){return T(a)||md.test(a)?(e.$setValidity("url",!0),a):(e.$setValidity("url",!1),p)};e.$formatters.push(a);e.$parsers.push(a)},email:function(a,c,d,e,g,i){Qa(a,c,d,e,g,i);a=function(a){return T(a)||nd.test(a)?(e.$setValidity("email",!0),a):(e.$setValidity("email",
|
||||
!1),p)};e.$formatters.push(a);e.$parsers.push(a)},radio:function(a,c,d,e){t(d.name)&&c.attr("name",xa());c.bind("click",function(){c[0].checked&&a.$apply(function(){e.$setViewValue(d.value)})});e.$render=function(){c[0].checked=d.value==e.$viewValue};d.$observe("value",e.$render)},checkbox:function(a,c,d,e){var g=d.ngTrueValue,i=d.ngFalseValue;F(g)||(g=!0);F(i)||(i=!1);c.bind("click",function(){a.$apply(function(){e.$setViewValue(c[0].checked)})});e.$render=function(){c[0].checked=e.$viewValue};e.$formatters.push(function(a){return a===
|
||||
g});e.$parsers.push(function(a){return a?g:i})},hidden:D,button:D,submit:D,reset:D},bc=["$browser","$sniffer",function(a,c){return{restrict:"E",require:"?ngModel",link:function(d,e,g,i){i&&(ac[E(g.type)]||ac.text)(d,e,g,i,c,a)}}}],Na="ng-valid",Ma="ng-invalid",Pa="ng-pristine",Xb="ng-dirty",pd=["$scope","$exceptionHandler","$attrs","$element","$parse",function(a,c,d,e,g){function i(a,c){c=c?"-"+$a(c,"-"):"";e.removeClass((a?Ma:Na)+c).addClass((a?Na:Ma)+c)}this.$modelValue=this.$viewValue=Number.NaN;
|
||||
this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$pristine=!0;this.$dirty=!1;this.$valid=!0;this.$invalid=!1;this.$name=d.name;var f=g(d.ngModel),h=f.assign;if(!h)throw B(Db+d.ngModel+" ("+pa(e)+")");this.$render=D;var k=e.inheritedData("$formController")||Oa,j=0,l=this.$error={};e.addClass(Pa);i(!0);this.$setValidity=function(a,c){if(l[a]!==!c){if(c){if(l[a]&&j--,!j)i(!0),this.$valid=!0,this.$invalid=!1}else i(!1),this.$invalid=!0,this.$valid=!1,j++;l[a]=!c;i(c,a);k.$setValidity(a,
|
||||
c,this)}};this.$setViewValue=function(d){this.$viewValue=d;if(this.$pristine)this.$dirty=!0,this.$pristine=!1,e.removeClass(Pa).addClass(Xb),k.$setDirty();m(this.$parsers,function(a){d=a(d)});if(this.$modelValue!==d)this.$modelValue=d,h(a,d),m(this.$viewChangeListeners,function(a){try{a()}catch(d){c(d)}})};var o=this;a.$watch(function(){var c=f(a);if(o.$modelValue!==c){var d=o.$formatters,e=d.length;for(o.$modelValue=c;e--;)c=d[e](c);if(o.$viewValue!==c)o.$viewValue=c,o.$render()}})}],qd=function(){return{require:["ngModel",
|
||||
"^?form"],controller:pd,link:function(a,c,d,e){var g=e[0],i=e[1]||Oa;i.$addControl(g);c.bind("$destroy",function(){i.$removeControl(g)})}}},rd=I({require:"ngModel",link:function(a,c,d,e){e.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}),cc=function(){return{require:"?ngModel",link:function(a,c,d,e){if(e){d.required=!0;var g=function(a){if(d.required&&(T(a)||a===!1))e.$setValidity("required",!1);else return e.$setValidity("required",!0),a};e.$formatters.push(g);e.$parsers.unshift(g);
|
||||
d.$observe("required",function(){g(e.$viewValue)})}}}},sd=function(){return{require:"ngModel",link:function(a,c,d,e){var g=(a=/\/(.*)\//.exec(d.ngList))&&RegExp(a[1])||d.ngList||",";e.$parsers.push(function(a){var c=[];a&&m(a.split(g),function(a){a&&c.push(R(a))});return c});e.$formatters.push(function(a){return J(a)?a.join(", "):p})}}},td=/^(true|false|\d+)$/,ud=function(){return{priority:100,compile:function(a,c){return td.test(c.ngValue)?function(a,c,g){g.$set("value",a.$eval(g.ngValue))}:function(a,
|
||||
c,g){a.$watch(g.ngValue,function(a){g.$set("value",a,!1)})}}}},vd=S(function(a,c,d){c.addClass("ng-binding").data("$binding",d.ngBind);a.$watch(d.ngBind,function(a){c.text(a==p?"":a)})}),wd=["$interpolate",function(a){return function(c,d,e){c=a(d.attr(e.$attr.ngBindTemplate));d.addClass("ng-binding").data("$binding",c);e.$observe("ngBindTemplate",function(a){d.text(a)})}}],xd=[function(){return function(a,c,d){c.addClass("ng-binding").data("$binding",d.ngBindHtmlUnsafe);a.$watch(d.ngBindHtmlUnsafe,
|
||||
function(a){c.html(a||"")})}}],yd=jb("",!0),zd=jb("Odd",0),Ad=jb("Even",1),Bd=S({compile:function(a,c){c.$set("ngCloak",p);a.removeClass("ng-cloak")}}),Cd=[function(){return{scope:!0,controller:"@"}}],Dd=["$sniffer",function(a){return{priority:1E3,compile:function(){a.csp=!0}}}],dc={};m("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave".split(" "),function(a){var c=fa("ng-"+a);dc[c]=["$parse",function(d){return function(e,g,i){var f=d(i[c]);g.bind(E(a),function(a){e.$apply(function(){f(e,
|
||||
{$event:a})})})}}]});var Ed=S(function(a,c,d){c.bind("submit",function(){a.$apply(d.ngSubmit)})}),Fd=["$http","$templateCache","$anchorScroll","$compile",function(a,c,d,e){return{restrict:"ECA",terminal:!0,compile:function(g,i){var f=i.ngInclude||i.src,h=i.onload||"",k=i.autoscroll;return function(g,i){var o=0,m,n=function(){m&&(m.$destroy(),m=null);i.html("")};g.$watch(f,function(f){var p=++o;f?a.get(f,{cache:c}).success(function(a){p===o&&(m&&m.$destroy(),m=g.$new(),i.html(a),e(i.contents())(m),
|
||||
v(k)&&(!k||g.$eval(k))&&d(),m.$emit("$includeContentLoaded"),g.$eval(h))}).error(function(){p===o&&n()}):n()})}}}}],Gd=S({compile:function(){return{pre:function(a,c,d){a.$eval(d.ngInit)}}}}),Hd=S({terminal:!0,priority:1E3}),Id=["$locale","$interpolate",function(a,c){var d=/{}/g;return{restrict:"EA",link:function(e,g,i){var f=i.count,h=g.attr(i.$attr.when),k=i.offset||0,j=e.$eval(h),l={},o=c.startSymbol(),r=c.endSymbol();m(j,function(a,e){l[e]=c(a.replace(d,o+f+"-"+k+r))});e.$watch(function(){var c=
|
||||
parseFloat(e.$eval(f));return isNaN(c)?"":(j[c]||(c=a.pluralCat(c-k)),l[c](e,g,!0))},function(a){g.text(a)})}}}],Jd=S({transclude:"element",priority:1E3,terminal:!0,compile:function(a,c,d){return function(a,c,i){var f=i.ngRepeat,i=f.match(/^\s*(.+)\s+in\s+(.*)\s*$/),h,k,j;if(!i)throw B("Expected ngRepeat in form of '_item_ in _collection_' but got '"+f+"'.");f=i[1];h=i[2];i=f.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);if(!i)throw B("'item' in 'item in collection' should be identifier or (key, value) but got '"+
|
||||
f+"'.");k=i[3]||i[1];j=i[2];var l=new eb;a.$watch(function(a){var e,f,i=a.$eval(h),m=gc(i,!0),p,u=new eb,C,A,v,t,y=c;if(J(i))v=i||[];else{v=[];for(C in i)i.hasOwnProperty(C)&&C.charAt(0)!="$"&&v.push(C);v.sort()}e=0;for(f=v.length;e<f;e++){C=i===v?e:v[e];A=i[C];if(t=l.shift(A)){p=t.scope;u.push(A,t);if(e!==t.index)t.index=e,y.after(t.element);y=t.element}else p=a.$new();p[k]=A;j&&(p[j]=C);p.$index=e;p.$first=e===0;p.$last=e===m-1;p.$middle=!(p.$first||p.$last);t||d(p,function(a){y.after(a);t={scope:p,
|
||||
element:y=a,index:e};u.push(A,t)})}for(C in l)if(l.hasOwnProperty(C))for(v=l[C];v.length;)A=v.pop(),A.element.remove(),A.scope.$destroy();l=u})}}}),Kd=S(function(a,c,d){a.$watch(d.ngShow,function(a){c.css("display",Wa(a)?"":"none")})}),Ld=S(function(a,c,d){a.$watch(d.ngHide,function(a){c.css("display",Wa(a)?"none":"")})}),Md=S(function(a,c,d){a.$watch(d.ngStyle,function(a,d){d&&a!==d&&m(d,function(a,d){c.css(d,"")});a&&c.css(a)},!0)}),Nd=I({restrict:"EA",compile:function(a,c){var d=c.ngSwitch||c.on,
|
||||
e={};a.data("ng-switch",e);return function(a,i){var f,h,k;a.$watch(d,function(d){h&&(k.$destroy(),h.remove(),h=k=null);if(f=e["!"+d]||e["?"])a.$eval(c.change),k=a.$new(),f(k,function(a){h=a;i.append(a)})})}}}),Od=S({transclude:"element",priority:500,compile:function(a,c,d){a=a.inheritedData("ng-switch");qa(a);a["!"+c.ngSwitchWhen]=d}}),Pd=S({transclude:"element",priority:500,compile:function(a,c,d){a=a.inheritedData("ng-switch");qa(a);a["?"]=d}}),Qd=S({controller:["$transclude","$element",function(a,
|
||||
c){a(function(a){c.append(a)})}]}),Rd=["$http","$templateCache","$route","$anchorScroll","$compile","$controller",function(a,c,d,e,g,i){return{restrict:"ECA",terminal:!0,link:function(a,c,k){function j(){var j=d.current&&d.current.locals,k=j&&j.$template;if(k){c.html(k);l&&(l.$destroy(),l=null);var k=g(c.contents()),p=d.current;l=p.scope=a.$new();if(p.controller)j.$scope=l,j=i(p.controller,j),c.contents().data("$ngControllerController",j);k(l);l.$emit("$viewContentLoaded");l.$eval(m);e()}else c.html(""),
|
||||
l&&(l.$destroy(),l=null)}var l,m=k.onload||"";a.$on("$routeChangeSuccess",j);j()}}}],Sd=["$templateCache",function(a){return{restrict:"E",terminal:!0,compile:function(c,d){d.type=="text/ng-template"&&a.put(d.id,c[0].text)}}}],Td=I({terminal:!0}),Ud=["$compile","$parse",function(a,c){var d=/^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*)$/,e={$setViewValue:D};return{restrict:"E",require:["select",
|
||||
"?ngModel"],controller:["$element","$scope","$attrs",function(a,c,d){var h=this,k={},j=e,l;h.databound=d.ngModel;h.init=function(a,c,d){j=a;l=d};h.addOption=function(c){k[c]=!0;j.$viewValue==c&&(a.val(c),l.parent()&&l.remove())};h.removeOption=function(a){this.hasOption(a)&&(delete k[a],j.$viewValue==a&&this.renderUnknownOption(a))};h.renderUnknownOption=function(c){c="? "+ga(c)+" ?";l.val(c);a.prepend(l);a.val(c);l.prop("selected",!0)};h.hasOption=function(a){return k.hasOwnProperty(a)};c.$on("$destroy",
|
||||
function(){h.renderUnknownOption=D})}],link:function(e,i,f,h){function k(a,c,d,e){d.$render=function(){var a=d.$viewValue;e.hasOption(a)?(A.parent()&&A.remove(),c.val(a),a===""&&s.prop("selected",!0)):t(a)&&s?c.val(""):e.renderUnknownOption(a)};c.bind("change",function(){a.$apply(function(){A.parent()&&A.remove();d.$setViewValue(c.val())})})}function j(a,c,d){var e;d.$render=function(){var a=new Fa(d.$viewValue);m(c.children(),function(c){c.selected=v(a.get(c.value))})};a.$watch(function(){ha(e,d.$viewValue)||
|
||||
(e=V(d.$viewValue),d.$render())});c.bind("change",function(){a.$apply(function(){var a=[];m(c.children(),function(c){c.selected&&a.push(c.value)});d.$setViewValue(a)})})}function l(e,f,g){function h(){var a={"":[]},c=[""],d,i,s,t,u;s=g.$modelValue;t=r(e)||[];var y=l?lb(t):t,A,w,x;w={};u=!1;var z,B;if(n)u=new Fa(s);else if(s===null||q)a[""].push({selected:s===null,id:"",label:""}),u=!0;for(x=0;A=y.length,x<A;x++){w[k]=t[l?w[l]=y[x]:x];d=m(e,w)||"";if(!(i=a[d]))i=a[d]=[],c.push(d);n?d=u.remove(o(e,
|
||||
w))!=p:(d=s===o(e,w),u=u||d);z=j(e,w);z=z===p?"":z;i.push({id:l?y[x]:x,label:z,selected:d})}!n&&!u&&a[""].unshift({id:"?",label:"",selected:!0});w=0;for(y=c.length;w<y;w++){d=c[w];i=a[d];if(v.length<=w)s={element:C.clone().attr("label",d),label:i.label},t=[s],v.push(t),f.append(s.element);else if(t=v[w],s=t[0],s.label!=d)s.element.attr("label",s.label=d);z=null;x=0;for(A=i.length;x<A;x++)if(d=i[x],u=t[x+1]){z=u.element;if(u.label!==d.label)z.text(u.label=d.label);if(u.id!==d.id)z.val(u.id=d.id);if(u.element.selected!==
|
||||
d.selected)z.prop("selected",u.selected=d.selected)}else d.id===""&&q?B=q:(B=D.clone()).val(d.id).attr("selected",d.selected).text(d.label),t.push({element:B,label:d.label,id:d.id,selected:d.selected}),z?z.after(B):s.element.append(B),z=B;for(x++;t.length>x;)t.pop().element.remove()}for(;v.length>w;)v.pop()[0].element.remove()}var i;if(!(i=w.match(d)))throw B("Expected ngOptions in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_' but got '"+w+"'.");var j=c(i[2]||i[1]),k=i[4]||
|
||||
i[6],l=i[5],m=c(i[3]||""),o=c(i[2]?i[1]:k),r=c(i[7]),v=[[{element:f,label:""}]];q&&(a(q)(e),q.removeClass("ng-scope"),q.remove());f.html("");f.bind("change",function(){e.$apply(function(){var a,c=r(e)||[],d={},h,i,j,m,q,s;if(n){i=[];m=0;for(s=v.length;m<s;m++){a=v[m];j=1;for(q=a.length;j<q;j++)if((h=a[j].element)[0].selected)h=h.val(),l&&(d[l]=h),d[k]=c[h],i.push(o(e,d))}}else h=f.val(),h=="?"?i=p:h==""?i=null:(d[k]=c[h],l&&(d[l]=h),i=o(e,d));g.$setViewValue(i)})});g.$render=h;e.$watch(h)}if(h[1]){for(var o=
|
||||
h[0],r=h[1],n=f.multiple,w=f.ngOptions,q=!1,s,D=u(ca.createElement("option")),C=u(ca.createElement("optgroup")),A=D.clone(),h=0,x=i.children(),E=x.length;h<E;h++)if(x[h].value==""){s=q=x.eq(h);break}o.init(r,q,A);if(n&&(f.required||f.ngRequired)){var y=function(a){r.$setValidity("required",!f.required||a&&a.length);return a};r.$parsers.push(y);r.$formatters.unshift(y);f.$observe("required",function(){y(r.$viewValue)})}w?l(e,i,r):n?j(e,i,r):k(e,i,r,o)}}}}],Vd=["$interpolate",function(a){var c={addOption:D,
|
||||
removeOption:D};return{restrict:"E",priority:100,compile:function(d,e){if(t(e.value)){var g=a(d.text(),!0);g||e.$set("value",d.text())}return function(a,d,e){var k=d.parent(),j=k.data("$selectController")||k.parent().data("$selectController");j&&j.databound?d.prop("selected",!1):j=c;g?a.$watch(g,function(a,c){e.$set("value",a);a!==c&&j.removeOption(c);j.addOption(a)}):j.addOption(e.value);d.bind("$destroy",function(){j.removeOption(e.value)})}}}}],Wd=I({restrict:"E",terminal:!0});(ja=U.jQuery)?(u=
|
||||
ja,x(ja.fn,{scope:ua.scope,controller:ua.controller,injector:ua.injector,inheritedData:ua.inheritedData}),ab("remove",!0),ab("empty"),ab("html")):u=Q;Yb.element=u;(function(a){x(a,{bootstrap:pb,copy:V,extend:x,equals:ha,element:u,forEach:m,injector:qb,noop:D,bind:Va,toJson:da,fromJson:nb,identity:ma,isUndefined:t,isDefined:v,isString:F,isFunction:N,isObject:L,isNumber:wa,isElement:fc,isArray:J,version:id,isDate:na,lowercase:E,uppercase:la,callbacks:{counter:0}});ta=lc(U);try{ta("ngLocale")}catch(c){ta("ngLocale",
|
||||
[]).provider("$locale",Zc)}ta("ng",["ngLocale"],["$provide",function(a){a.provider("$compile",Bb).directive({a:jd,input:bc,textarea:bc,form:kd,script:Sd,select:Ud,style:Wd,option:Vd,ngBind:vd,ngBindHtmlUnsafe:xd,ngBindTemplate:wd,ngClass:yd,ngClassEven:Ad,ngClassOdd:zd,ngCsp:Dd,ngCloak:Bd,ngController:Cd,ngForm:ld,ngHide:Ld,ngInclude:Fd,ngInit:Gd,ngNonBindable:Hd,ngPluralize:Id,ngRepeat:Jd,ngShow:Kd,ngSubmit:Ed,ngStyle:Md,ngSwitch:Nd,ngSwitchWhen:Od,ngSwitchDefault:Pd,ngOptions:Td,ngView:Rd,ngTransclude:Qd,
|
||||
ngModel:qd,ngList:sd,ngChange:rd,required:cc,ngRequired:cc,ngValue:ud}).directive(kb).directive(dc);a.provider({$anchorScroll:uc,$browser:wc,$cacheFactory:xc,$controller:Bc,$document:Cc,$exceptionHandler:Dc,$filter:Pb,$interpolate:Ec,$http:Vc,$httpBackend:Wc,$location:Ic,$log:Jc,$parse:Nc,$route:Qc,$routeParams:Rc,$rootScope:Sc,$q:Oc,$sniffer:Tc,$templateCache:yc,$timeout:$c,$window:Uc})}])})(Yb);u(ca).ready(function(){jc(ca,pb)})})(window,document);angular.element(document).find("head").append('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak{display:none;}ng\\:form{display:block;}</style>');
|
||||
9227
app/assets/javascripts/shared/jquery-1.8.0.js
vendored
Normal file
9227
app/assets/javascripts/shared/jquery-1.8.0.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1882
app/assets/javascripts/shared/jquery-ui-timepicker-addon.js
vendored
Normal file
1882
app/assets/javascripts/shared/jquery-ui-timepicker-addon.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,8 @@
|
||||
*= require admin/spree_auth
|
||||
*= require admin/spree_promo
|
||||
|
||||
*= require shared/jquery-ui-timepicker-addon
|
||||
|
||||
*= require_self
|
||||
*= require_tree .
|
||||
*/
|
||||
|
||||
@@ -12,3 +12,60 @@
|
||||
float: none;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
|
||||
#new_enterprise_fee_set input.search {
|
||||
float: right;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.ng .ng-invalid.ng-dirty {
|
||||
background-color: #fa787e;
|
||||
}
|
||||
|
||||
|
||||
form.order_cycle {
|
||||
h2 {
|
||||
margin-top: 2em;
|
||||
}
|
||||
.date-field {
|
||||
float: left;
|
||||
margin-right: 3em;
|
||||
}
|
||||
table.exchanges {
|
||||
tr td.active {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
tr.supplier td {
|
||||
border-bottom: 2px solid #C3D9FF;
|
||||
}
|
||||
|
||||
.exchange-product {
|
||||
float: left;
|
||||
overflow: auto;
|
||||
width: 18%;
|
||||
min-height: 7.5em;
|
||||
margin: 0 1% 1% 0;
|
||||
border: 1px solid #DAE7FF;
|
||||
padding: 5px;
|
||||
|
||||
.exchange-product-details {
|
||||
clear: both;
|
||||
margin-bottom: 1em;
|
||||
|
||||
.supplier {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.exchange-product-variant {
|
||||
float: left;
|
||||
margin-right: 2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
.actions {
|
||||
margin-top: 3em;
|
||||
}
|
||||
}
|
||||
|
||||
10
app/assets/stylesheets/shared/jquery-ui-timepicker-addon.css
Normal file
10
app/assets/stylesheets/shared/jquery-ui-timepicker-addon.css
Normal file
@@ -0,0 +1,10 @@
|
||||
.ui-timepicker-div .ui-widget-header { margin-bottom: 8px; }
|
||||
.ui-timepicker-div dl { text-align: left; }
|
||||
.ui-timepicker-div dl dt { height: 25px; margin-bottom: -25px; }
|
||||
.ui-timepicker-div dl dd { margin: 0 10px 10px 65px; }
|
||||
.ui-timepicker-div td { font-size: 90%; }
|
||||
.ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; }
|
||||
|
||||
.ui-timepicker-rtl{ direction: rtl; }
|
||||
.ui-timepicker-rtl dl { text-align: right; }
|
||||
.ui-timepicker-rtl dl dd { margin: 0 65px 10px 10px; }
|
||||
@@ -225,3 +225,13 @@ fieldset#product-distributor-details {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Alert for EFT Payment during checkout process */
|
||||
div#eft-payment-alert {
|
||||
border: 2px solid red;
|
||||
}
|
||||
|
||||
/* Cleared div for clearing previous floating elements */
|
||||
div.cleared {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
37
app/controllers/admin/enterprise_fees_controller.rb
Normal file
37
app/controllers/admin/enterprise_fees_controller.rb
Normal file
@@ -0,0 +1,37 @@
|
||||
module Admin
|
||||
class EnterpriseFeesController < ResourceController
|
||||
before_filter :load_enterprise_fee_set, :only => :index
|
||||
before_filter :load_data
|
||||
|
||||
def index
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json { @presented_collection = @collection.each_with_index.map { |ef, i| EnterpriseFeePresenter.new(self, ef, i) } }
|
||||
end
|
||||
end
|
||||
|
||||
def bulk_update
|
||||
@enterprise_fee_set = EnterpriseFeeSet.new(params[:enterprise_fee_set])
|
||||
if @enterprise_fee_set.save
|
||||
redirect_to main_app.admin_enterprise_fees_path, :notice => 'Your enterprise fees have been updated.'
|
||||
else
|
||||
render :index
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def load_enterprise_fee_set
|
||||
@enterprise_fee_set = EnterpriseFeeSet.new :collection => collection
|
||||
end
|
||||
|
||||
def load_data
|
||||
@calculators = EnterpriseFee.calculators.sort_by(&:name)
|
||||
end
|
||||
|
||||
def collection
|
||||
super.order('enterprise_id', 'fee_type', 'name') + (1..3).map { EnterpriseFee.new }
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -16,7 +16,7 @@ module Admin
|
||||
|
||||
private
|
||||
def load_enterprise_set
|
||||
@enterprise_set = EnterpriseSet.new :enterprises => collection
|
||||
@enterprise_set = EnterpriseSet.new :collection => collection
|
||||
end
|
||||
|
||||
def load_countries
|
||||
|
||||
70
app/controllers/admin/order_cycles_controller.rb
Normal file
70
app/controllers/admin/order_cycles_controller.rb
Normal file
@@ -0,0 +1,70 @@
|
||||
require 'open_food_web/order_cycle_form_applicator'
|
||||
|
||||
module Admin
|
||||
class OrderCyclesController < ResourceController
|
||||
before_filter :load_order_cycle_set, :only => :index
|
||||
|
||||
def show
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json
|
||||
end
|
||||
end
|
||||
|
||||
def new
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
@order_cycle = OrderCycle.new(params[:order_cycle])
|
||||
|
||||
respond_to do |format|
|
||||
if @order_cycle.save
|
||||
OpenFoodWeb::OrderCycleFormApplicator.new(@order_cycle).go!
|
||||
|
||||
flash[:notice] = 'Your order cycle has been created.'
|
||||
format.html { redirect_to admin_order_cycles_path }
|
||||
format.json { render :json => {:success => true} }
|
||||
else
|
||||
format.html
|
||||
format.json { render :json => {:success => false} }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
@order_cycle = OrderCycle.find params[:id]
|
||||
|
||||
respond_to do |format|
|
||||
if @order_cycle.update_attributes(params[:order_cycle])
|
||||
OpenFoodWeb::OrderCycleFormApplicator.new(@order_cycle).go!
|
||||
|
||||
flash[:notice] = 'Your order cycle has been updated.'
|
||||
format.html { redirect_to admin_order_cycles_path }
|
||||
format.json { render :json => {:success => true} }
|
||||
else
|
||||
format.html
|
||||
format.json { render :json => {:success => false} }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def bulk_update
|
||||
@order_cycle_set = OrderCycleSet.new(params[:order_cycle_set])
|
||||
if @order_cycle_set.save
|
||||
redirect_to main_app.admin_order_cycles_path, :notice => 'Order cycles have been updated.'
|
||||
else
|
||||
render :index
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def load_order_cycle_set
|
||||
@order_cycle_set = OrderCycleSet.new :collection => collection
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -14,4 +14,16 @@ class ApplicationController < ActionController::Base
|
||||
@distributors = Enterprise.is_distributor.with_distributed_active_products_on_hand.by_name
|
||||
end
|
||||
|
||||
# All render calls within the block will be performed with the specified format
|
||||
# Useful for rendering html within a JSON response, particularly if the specified
|
||||
# template or partial then goes on to render further partials without specifying
|
||||
# their format.
|
||||
def with_format(format, &block)
|
||||
old_formats = formats
|
||||
self.formats = [format]
|
||||
block.call
|
||||
self.formats = old_formats
|
||||
nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -26,28 +26,4 @@ class EnterprisesController < BaseController
|
||||
@searcher = Spree::Config.searcher_class.new(options)
|
||||
@products = @searcher.retrieve_products
|
||||
end
|
||||
|
||||
def select_distributor
|
||||
distributor = Enterprise.is_distributor.find params[:id]
|
||||
|
||||
order = current_order(true)
|
||||
|
||||
if order.can_change_distributor?
|
||||
order.distributor = distributor
|
||||
order.save!
|
||||
end
|
||||
|
||||
redirect_to distributor
|
||||
end
|
||||
|
||||
def deselect_distributor
|
||||
order = current_order(true)
|
||||
|
||||
if order.can_change_distributor?
|
||||
order.distributor = nil
|
||||
order.save!
|
||||
end
|
||||
|
||||
redirect_to root_path
|
||||
end
|
||||
end
|
||||
|
||||
@@ -99,7 +99,7 @@ Spree::Admin::ReportsController.class_eval do
|
||||
|
||||
columns = [ proc { |lis| lis.first.variant.product.supplier.name },
|
||||
proc { |lis| lis.first.variant.product.name },
|
||||
proc { |lis| lis.first.variant.product.group_buy_unit_size || 0.0 },
|
||||
proc { |lis| lis.first.variant.product.group_buy ? (lis.first.variant.product.group_buy_unit_size || 0.0) : "" },
|
||||
proc { |lis| lis.first.variant.options_text },
|
||||
proc { |lis| lis.first.variant.weight || 0 },
|
||||
proc { |lis| lis.sum { |li| li.quantity } },
|
||||
@@ -113,13 +113,13 @@ Spree::Admin::ReportsController.class_eval do
|
||||
sort_by: proc { |product| product.name },
|
||||
summary_columns: [ proc { |lis| lis.first.variant.product.supplier.name },
|
||||
proc { |lis| lis.first.variant.product.name },
|
||||
proc { |lis| lis.first.variant.product.group_buy_unit_size || 0.0 },
|
||||
proc { |lis| lis.first.variant.product.group_buy ? (lis.first.variant.product.group_buy_unit_size || 0.0) : "" },
|
||||
proc { |lis| "" },
|
||||
proc { |lis| "" },
|
||||
proc { |lis| lis.sum { |li| li.quantity * li.variant.weight || 0 } },
|
||||
proc { |lis| lis.sum { |li| (li.max_quantity || 0) * li.variant.weight || 0 } },
|
||||
proc { |lis| ( (lis.first.variant.product.group_buy_unit_size || 0).zero? ? 0 : ( lis.sum { |li| ( [li.max_quantity || 0, li.quantity || 0].max ) * li.variant.weight || 0 } / lis.first.variant.product.group_buy_unit_size ) ).floor },
|
||||
proc { |lis| lis.sum { |li| ( [li.max_quantity || 0, li.quantity || 0].max) * li.variant.weight || 0 } - ( ( (lis.first.variant.product.group_buy_unit_size || 0).zero? ? 0 : ( lis.sum { |li| ( [li.max_quantity || 0, li.quantity || 0].max) * li.variant.weight || 0 } / lis.first.variant.product.group_buy_unit_size ) ).floor * (lis.first.variant.product.group_buy_unit_size || 0) ) } ] },
|
||||
proc { |lis| lis.sum { |li| (li.quantity || 0) * (li.variant.weight || 0) } },
|
||||
proc { |lis| lis.sum { |li| (li.max_quantity || 0) * (li.variant.weight || 0) } },
|
||||
proc { |lis| ( (lis.first.variant.product.group_buy_unit_size || 0).zero? ? 0 : ( lis.sum { |li| ( [li.max_quantity || 0, li.quantity || 0].max ) * (li.variant.weight || 0) } / lis.first.variant.product.group_buy_unit_size ) ).floor },
|
||||
proc { |lis| lis.sum { |li| ( [li.max_quantity || 0, li.quantity || 0].max) * (li.variant.weight || 0) } - ( ( (lis.first.variant.product.group_buy_unit_size || 0).zero? ? 0 : ( lis.sum { |li| ( [li.max_quantity || 0, li.quantity || 0].max) * (li.variant.weight || 0) } / lis.first.variant.product.group_buy_unit_size ) ).floor * (lis.first.variant.product.group_buy_unit_size || 0) ) } ] },
|
||||
{ group_by: proc { |li| li.variant },
|
||||
sort_by: proc { |variant| variant.options_text } } ]
|
||||
|
||||
@@ -129,7 +129,7 @@ Spree::Admin::ReportsController.class_eval do
|
||||
|
||||
columns = [ proc { |lis| lis.first.order.bill_address.firstname + " " + lis.first.order.bill_address.lastname },
|
||||
proc { |lis| lis.first.variant.product.name },
|
||||
proc { |lis| lis.first.variant.product.group_buy_unit_size || 0.0 },
|
||||
proc { |lis| lis.first.variant.product.group_buy ? (lis.first.variant.product.group_buy_unit_size || 0.0) : "" },
|
||||
proc { |lis| lis.first.variant.options_text },
|
||||
proc { |lis| lis.first.variant.weight || 0 },
|
||||
proc { |lis| lis.sum { |li| li.quantity } },
|
||||
@@ -139,15 +139,15 @@ Spree::Admin::ReportsController.class_eval do
|
||||
|
||||
rules = [ { group_by: proc { |li| li.variant.product },
|
||||
sort_by: proc { |product| product.name },
|
||||
summary_columns: [ proc { |lis| lis.first.order.bill_address.firstname + " " + lis.first.order.bill_address.lastname },
|
||||
summary_columns: [ proc { |lis| "TOTAL" },
|
||||
proc { |lis| lis.first.variant.product.name },
|
||||
proc { |lis| lis.first.variant.product.group_buy_unit_size || 0.0 },
|
||||
proc { |lis| lis.first.variant.product.group_buy ? (lis.first.variant.product.group_buy_unit_size || 0.0) : "" },
|
||||
proc { |lis| "" },
|
||||
proc { |lis| "" },
|
||||
proc { |lis| lis.sum { |li| li.quantity * li.variant.weight || 0 } },
|
||||
proc { |lis| lis.sum { |li| (li.max_quantity || 0) * li.variant.weight || 0 } },
|
||||
proc { |lis| ( (lis.first.variant.product.group_buy_unit_size || 0).zero? ? 0 : ( lis.sum { |li| ( [li.max_quantity || 0, li.quantity || 0].max ) * li.variant.weight || 0 } / lis.first.variant.product.group_buy_unit_size ) ).floor * (lis.first.variant.product.group_buy_unit_size || 0) },
|
||||
proc { |lis| lis.sum { |li| ( [li.max_quantity || 0, li.quantity || 0].max ) * li.variant.weight || 0 } - ( ( (lis.first.variant.product.group_buy_unit_size || 0).zero? ? 0 : ( lis.sum { |li| ( [li.max_quantity || 0, li.quantity || 0].max ) * li.variant.weight || 0 } / lis.first.variant.product.group_buy_unit_size ) ).floor * (lis.first.variant.product.group_buy_unit_size || 0) ) } ] },
|
||||
proc { |lis| lis.sum { |li| li.quantity * (li.variant.weight || 0) } },
|
||||
proc { |lis| lis.sum { |li| (li.max_quantity || 0) * (li.variant.weight || 0) } },
|
||||
proc { |lis| ( (lis.first.variant.product.group_buy_unit_size || 0).zero? ? 0 : ( lis.sum { |li| ( [li.max_quantity || 0, li.quantity || 0].max ) * (li.variant.weight || 0) } / lis.first.variant.product.group_buy_unit_size ) ).floor * (lis.first.variant.product.group_buy_unit_size || 0) },
|
||||
proc { |lis| lis.sum { |li| ( [li.max_quantity || 0, li.quantity || 0].max ) * (li.variant.weight || 0) } - ( ( (lis.first.variant.product.group_buy_unit_size || 0).zero? ? 0 : ( lis.sum { |li| ( [li.max_quantity || 0, li.quantity || 0].max ) * (li.variant.weight || 0) } / lis.first.variant.product.group_buy_unit_size ) ).floor * (lis.first.variant.product.group_buy_unit_size || 0) ) } ] },
|
||||
{ group_by: proc { |li| li.variant },
|
||||
sort_by: proc { |variant| variant.options_text } },
|
||||
{ group_by: proc { |li| li.order },
|
||||
@@ -188,7 +188,7 @@ Spree::Admin::ReportsController.class_eval do
|
||||
|
||||
columns = [ proc { |lis| lis.first.variant.product.supplier.name },
|
||||
proc { |lis| lis.first.variant.product.name },
|
||||
proc { |lis| lis.first.variant.product.group_buy_unit_size || 0.0 },
|
||||
proc { |lis| lis.first.variant.product.group_buy ? (lis.first.variant.product.group_buy_unit_size || 0.0) : "" },
|
||||
proc { |lis| lis.first.variant.options_text },
|
||||
proc { |lis| lis.first.variant.weight || 0 },
|
||||
proc { |lis| lis.sum { |li| li.quantity } },
|
||||
@@ -202,13 +202,13 @@ Spree::Admin::ReportsController.class_eval do
|
||||
sort_by: proc { |product| product.name },
|
||||
summary_columns: [ proc { |lis| lis.first.variant.product.supplier.name },
|
||||
proc { |lis| lis.first.variant.product.name },
|
||||
proc { |lis| lis.first.variant.product.group_buy_unit_size || 0.0 },
|
||||
proc { |lis| lis.first.variant.product.group_buy ? (lis.first.variant.product.group_buy_unit_size || 0.0) : "" },
|
||||
proc { |lis| "" },
|
||||
proc { |lis| "" },
|
||||
proc { |lis| lis.sum { |li| li.quantity * li.variant.weight || 0 } },
|
||||
proc { |lis| lis.sum { |li| (li.max_quantity || 0) * li.variant.weight || 0 } },
|
||||
proc { |lis| ( (lis.first.variant.product.group_buy_unit_size || 0).zero? ? 0 : ( lis.sum { |li| ( [li.max_quantity || 0, li.quantity || 0].max ) * li.variant.weight || 0 } / lis.first.variant.product.group_buy_unit_size ) ).floor },
|
||||
proc { |lis| lis.sum { |li| ( [li.max_quantity || 0, li.quantity || 0].max ) * li.variant.weight || 0 } - ( ( (lis.first.variant.product.group_buy_unit_size || 0).zero? ? 0 : ( lis.sum { |li| ( [li.max_quantity || 0, li.quantity || 0].max ) * li.variant.weight || 0 } / lis.first.variant.product.group_buy_unit_size ) ).floor * (lis.first.variant.product.group_buy_unit_size || 0) ) } ] },
|
||||
proc { |lis| lis.sum { |li| li.quantity * (li.variant.weight || 0) } },
|
||||
proc { |lis| lis.sum { |li| (li.max_quantity || 0) * (li.variant.weight || 0) } },
|
||||
proc { |lis| ( (lis.first.variant.product.group_buy_unit_size || 0).zero? ? 0 : ( lis.sum { |li| ( [li.max_quantity || 0, li.quantity || 0].max ) * (li.variant.weight || 0) } / lis.first.variant.product.group_buy_unit_size ) ).floor },
|
||||
proc { |lis| lis.sum { |li| ( [li.max_quantity || 0, li.quantity || 0].max ) * (li.variant.weight || 0) } - ( ( (lis.first.variant.product.group_buy_unit_size || 0).zero? ? 0 : ( lis.sum { |li| ( [li.max_quantity || 0, li.quantity || 0].max ) * (li.variant.weight || 0) } / lis.first.variant.product.group_buy_unit_size ) ).floor * (lis.first.variant.product.group_buy_unit_size || 0) ) } ] },
|
||||
{ group_by: proc { |li| li.variant },
|
||||
sort_by: proc { |variant| variant.options_text } } ]
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
Spree::OrdersController.class_eval do
|
||||
before_filter :populate_order_distributor, :only => :populate
|
||||
before_filter :populate_order_count_on_hand, :only => :populate
|
||||
after_filter :populate_variant_attributes, :only => :populate
|
||||
|
||||
def populate_order_distributor
|
||||
@@ -15,6 +16,24 @@ Spree::OrdersController.class_eval do
|
||||
end
|
||||
end
|
||||
|
||||
def populate_order_count_on_hand
|
||||
params[:products].each do |product_id, variant_id|
|
||||
product = Spree::Product.find product_id
|
||||
if product.count_on_hand < params[:quantity].to_i
|
||||
flash[:error] = "Unfortunately " + (product.count_on_hand == 0 ? "no" : "only" + product.count_on_hand.to_s ) + " units of the selected item remain."
|
||||
redirect_populate_to_first_product
|
||||
end
|
||||
end if params[:products]
|
||||
|
||||
params[:variants].each do |variant_id, quantity|
|
||||
variant = Spree::Variant.find variant_id
|
||||
if variant.count_on_hand < params[:quantity].to_i
|
||||
flash[:error] = "Unfortunately " + (variant.count_on_hand == 0 ? "no" : "only" + variant.count_on_hand.to_s ) + " units of the selected item remain."
|
||||
redirect_populate_to_first_product
|
||||
end
|
||||
end if params[:variants]
|
||||
end
|
||||
|
||||
def populate_variant_attributes
|
||||
if params.key? :variant_attributes
|
||||
params[:variant_attributes].each do |variant_id, attributes|
|
||||
@@ -30,6 +49,24 @@ Spree::OrdersController.class_eval do
|
||||
end
|
||||
end
|
||||
|
||||
def select_distributor
|
||||
distributor = Enterprise.is_distributor.find params[:id]
|
||||
|
||||
order = current_order(true)
|
||||
order.distributor = distributor
|
||||
order.save!
|
||||
|
||||
redirect_to main_app.enterprise_path(distributor)
|
||||
end
|
||||
|
||||
def deselect_distributor
|
||||
order = current_order(true)
|
||||
|
||||
order.distributor = nil
|
||||
order.save!
|
||||
|
||||
redirect_to root_path
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -50,7 +87,7 @@ Spree::OrdersController.class_eval do
|
||||
|
||||
# -- If products in cart, distributor can't be changed
|
||||
order = current_order(false)
|
||||
if !order.nil? && !order.can_change_distributor? && order.distributor != distributor
|
||||
if !order.nil? && !DistributorChangeValidator.new(order).can_change_to_distributor?(distributor)
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
45
app/helpers/angular_form_builder.rb
Normal file
45
app/helpers/angular_form_builder.rb
Normal file
@@ -0,0 +1,45 @@
|
||||
class AngularFormBuilder < ActionView::Helpers::FormBuilder
|
||||
def ng_fields_for(record_name, *args, &block)
|
||||
raise "Nested ng_fields_for is not yet supported" if @fields_for_record_name.present?
|
||||
@fields_for_record_name = record_name
|
||||
block.call self
|
||||
@fields_for_record_name = nil
|
||||
end
|
||||
|
||||
def ng_text_field(method, options = {})
|
||||
# @object_name --> "enterprise_fee_set"
|
||||
# @fields_for_record_name --> :collection
|
||||
# @object.send(@fields_for_record_name).first.class.to_s.underscore --> enterprise_fee
|
||||
|
||||
value = "{{ #{@object.send(@fields_for_record_name).first.class.to_s.underscore}.#{method} }}"
|
||||
|
||||
@template.text_field_tag angular_name(method), value, :id => angular_id(method)
|
||||
end
|
||||
|
||||
def ng_hidden_field(method, options = {})
|
||||
value = "{{ #{@object.send(@fields_for_record_name).first.class.to_s.underscore}.#{method} }}"
|
||||
|
||||
@template.hidden_field_tag angular_name(method), value, :id => angular_id(method)
|
||||
end
|
||||
|
||||
def ng_select(method, choices, angular_field, options = {})
|
||||
options.reverse_merge!({'id' => angular_id(method)})
|
||||
|
||||
@template.select_tag angular_name(method), @template.ng_options_for_select(choices, angular_field), options
|
||||
end
|
||||
|
||||
def ng_collection_select(method, collection, value_method, text_method, angular_field, options = {})
|
||||
options.reverse_merge!({'id' => angular_id(method)})
|
||||
|
||||
@template.select_tag angular_name(method), @template.ng_options_from_collection_for_select(collection, value_method, text_method, angular_field), options
|
||||
end
|
||||
|
||||
private
|
||||
def angular_name(method)
|
||||
"#{@object_name}[#{@fields_for_record_name}_attributes][{{ $index }}][#{method}]"
|
||||
end
|
||||
|
||||
def angular_id(method)
|
||||
"#{@object_name}_#{@fields_for_record_name}_attributes_{{ $index }}_#{method}"
|
||||
end
|
||||
end
|
||||
25
app/helpers/angular_form_helper.rb
Normal file
25
app/helpers/angular_form_helper.rb
Normal file
@@ -0,0 +1,25 @@
|
||||
module AngularFormHelper
|
||||
def ng_options_for_select(container, angular_field=nil)
|
||||
return container if String === container
|
||||
|
||||
container.map do |element|
|
||||
html_attributes = option_html_attributes(element)
|
||||
text, value = option_text_and_value(element).map { |item| item.to_s }
|
||||
selected_attribute = %Q( ng-selected="#{angular_field} == '#{value}'") if angular_field
|
||||
%(<option value="#{ERB::Util.html_escape(value)}"#{selected_attribute}#{html_attributes}>#{ERB::Util.html_escape(text)}</option>)
|
||||
end.join("\n").html_safe
|
||||
end
|
||||
|
||||
def ng_options_from_collection_for_select(collection, value_method, text_method, angular_field)
|
||||
options = collection.map do |element|
|
||||
[element.send(text_method), element.send(value_method)]
|
||||
end
|
||||
|
||||
ng_options_for_select(options, angular_field)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class ActionView::Helpers::InstanceTag
|
||||
include AngularFormHelper
|
||||
end
|
||||
@@ -6,6 +6,13 @@ module ApplicationHelper
|
||||
end
|
||||
|
||||
|
||||
def ng_form_for(name, *args, &block)
|
||||
options = args.extract_options!
|
||||
|
||||
form_for(name, *(args << options.merge(:builder => AngularFormBuilder)), &block)
|
||||
end
|
||||
|
||||
|
||||
# Pass URL helper calls on to spree where applicable so that we don't need to use
|
||||
# spree.foo_path in any view rendered from non-spree-namespaced controllers.
|
||||
def method_missing(method, *args, &block)
|
||||
|
||||
5
app/helpers/enterprise_fees_helper.rb
Normal file
5
app/helpers/enterprise_fees_helper.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
module EnterpriseFeesHelper
|
||||
def enterprise_fee_type_options
|
||||
EnterpriseFee::FEE_TYPES.map { |f| [f.capitalize, f] }
|
||||
end
|
||||
end
|
||||
@@ -2,4 +2,8 @@ module EnterprisesHelper
|
||||
def current_distributor
|
||||
@current_distributor ||= current_order(false).andand.distributor
|
||||
end
|
||||
|
||||
def enterprises_options enterprises
|
||||
enterprises.map { |enterprise| [enterprise.name + ": " + enterprise.address.address1 + ", " + enterprise.address.city, enterprise.id.to_i] }
|
||||
end
|
||||
end
|
||||
|
||||
5
app/helpers/order_cycles_helper.rb
Normal file
5
app/helpers/order_cycles_helper.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
module OrderCyclesHelper
|
||||
def coordinating_enterprises
|
||||
Enterprise.is_distributor.order('name')
|
||||
end
|
||||
end
|
||||
@@ -5,5 +5,9 @@ module Spree
|
||||
amount = order.line_items.map { |li| li.itemwise_shipping_cost }.sum
|
||||
options.delete(:format_as_currency) ? number_to_currency(amount) : amount
|
||||
end
|
||||
|
||||
def alternative_available_distributors(order)
|
||||
DistributorChangeValidator.new(order).available_distributors(Enterprise.all) - [order.distributor]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -27,6 +27,10 @@ class Enterprise < ActiveRecord::Base
|
||||
def to_param
|
||||
"#{id}-#{name.parameterize}"
|
||||
end
|
||||
|
||||
def available_variants
|
||||
ProductDistribution.find_all_by_distributor_id( self.id ).map{ |pd| pd.product.variants + [pd.product.master] }.flatten
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
13
app/models/enterprise_fee.rb
Normal file
13
app/models/enterprise_fee.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
class EnterpriseFee < ActiveRecord::Base
|
||||
belongs_to :enterprise
|
||||
|
||||
calculated_adjustments
|
||||
has_one :calculator, :as => :calculable, :dependent => :destroy, :class_name => 'Spree::Calculator'
|
||||
|
||||
attr_accessible :enterprise_id, :fee_type, :name, :calculator_type
|
||||
|
||||
FEE_TYPES = %w(packing transport admin sales)
|
||||
|
||||
validates_inclusion_of :fee_type, :in => FEE_TYPES
|
||||
validates_presence_of :name
|
||||
end
|
||||
7
app/models/enterprise_fee_set.rb
Normal file
7
app/models/enterprise_fee_set.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
class EnterpriseFeeSet < ModelSet
|
||||
def initialize(attributes={})
|
||||
super(EnterpriseFee, EnterpriseFee.all,
|
||||
proc { |attrs| attrs[:enterprise_id].blank? },
|
||||
attributes)
|
||||
end
|
||||
end
|
||||
@@ -1,34 +1,5 @@
|
||||
# Tableless model to handle updating multiple enterprises at once from a
|
||||
# single form. Used to update next_collection_at field for all distributors in
|
||||
# admin backend.
|
||||
class EnterpriseSet
|
||||
include ActiveModel::Conversion
|
||||
extend ActiveModel::Naming
|
||||
|
||||
attr_accessor :enterprises
|
||||
|
||||
class EnterpriseSet < ModelSet
|
||||
def initialize(attributes={})
|
||||
@enterprises = Enterprise.all
|
||||
|
||||
attributes.each do |name, value|
|
||||
send("#{name}=", value)
|
||||
end
|
||||
super(Enterprise, Enterprise.all, nil, attributes)
|
||||
end
|
||||
|
||||
def enterprises_attributes=(attributes)
|
||||
attributes.each do |k, attributes|
|
||||
# attributes == {:id => 123, :next_collection_at => '...'}
|
||||
e = @enterprises.detect { |e| e.id.to_s == attributes[:id].to_s }
|
||||
e.assign_attributes(attributes.except(:id))
|
||||
end
|
||||
end
|
||||
|
||||
def save
|
||||
enterprises.all?(&:save)
|
||||
end
|
||||
|
||||
def persisted?
|
||||
false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
17
app/models/exchange.rb
Normal file
17
app/models/exchange.rb
Normal file
@@ -0,0 +1,17 @@
|
||||
class Exchange < ActiveRecord::Base
|
||||
belongs_to :order_cycle
|
||||
belongs_to :sender, :class_name => 'Enterprise'
|
||||
belongs_to :receiver, :class_name => 'Enterprise'
|
||||
belongs_to :payment_enterprise, :class_name => 'Enterprise'
|
||||
|
||||
has_many :exchange_variants, :dependent => :destroy
|
||||
has_many :variants, :through => :exchange_variants
|
||||
|
||||
has_many :exchange_fees, :dependent => :destroy
|
||||
has_many :enterprise_fees, :through => :exchange_fees
|
||||
|
||||
validates_presence_of :order_cycle, :sender, :receiver
|
||||
validates_uniqueness_of :sender_id, :scope => [:order_cycle_id, :receiver_id]
|
||||
|
||||
accepts_nested_attributes_for :variants
|
||||
end
|
||||
4
app/models/exchange_fee.rb
Normal file
4
app/models/exchange_fee.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
class ExchangeFee < ActiveRecord::Base
|
||||
belongs_to :exchange
|
||||
belongs_to :enterprise_fee
|
||||
end
|
||||
4
app/models/exchange_variant.rb
Normal file
4
app/models/exchange_variant.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
class ExchangeVariant < ActiveRecord::Base
|
||||
belongs_to :exchange
|
||||
belongs_to :variant, :class_name => 'Spree::Variant'
|
||||
end
|
||||
40
app/models/model_set.rb
Normal file
40
app/models/model_set.rb
Normal file
@@ -0,0 +1,40 @@
|
||||
# Tableless model to handle updating multiple models at once from a single form
|
||||
class ModelSet
|
||||
include ActiveModel::Conversion
|
||||
extend ActiveModel::Naming
|
||||
|
||||
attr_accessor :collection
|
||||
|
||||
def initialize(klass, collection, reject_if=nil, attributes={})
|
||||
@klass, @collection, @reject_if = klass, collection, reject_if
|
||||
|
||||
attributes.each do |name, value|
|
||||
send("#{name}=", value)
|
||||
end
|
||||
end
|
||||
|
||||
def collection_attributes=(attributes)
|
||||
attributes.each do |k, attributes|
|
||||
# attributes == {:id => 123, :next_collection_at => '...'}
|
||||
e = @collection.detect { |e| e.id.to_s == attributes[:id].to_s && !e.id.nil? }
|
||||
if e.nil?
|
||||
@collection << @klass.new(attributes) unless @reject_if.andand.call(attributes)
|
||||
else
|
||||
e.assign_attributes(attributes.except(:id))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def errors
|
||||
@collection.map { |ef| ef.errors.full_messages }.flatten
|
||||
end
|
||||
|
||||
def save
|
||||
collection.all?(&:save)
|
||||
end
|
||||
|
||||
def persisted?
|
||||
false
|
||||
end
|
||||
|
||||
end
|
||||
29
app/models/order_cycle.rb
Normal file
29
app/models/order_cycle.rb
Normal file
@@ -0,0 +1,29 @@
|
||||
class OrderCycle < ActiveRecord::Base
|
||||
belongs_to :coordinator, :class_name => 'Enterprise'
|
||||
belongs_to :coordinator_admin_fee, :class_name => 'EnterpriseFee'
|
||||
belongs_to :coordinator_sales_fee, :class_name => 'EnterpriseFee'
|
||||
|
||||
has_many :exchanges, :dependent => :destroy
|
||||
|
||||
attr_accessor :incoming_exchanges, :outgoing_exchanges
|
||||
|
||||
validates_presence_of :name, :coordinator_id
|
||||
|
||||
|
||||
def suppliers
|
||||
self.exchanges.where(:receiver_id => self.coordinator).map(&:sender).uniq
|
||||
end
|
||||
|
||||
def distributors
|
||||
self.exchanges.where(:sender_id => self.coordinator).map(&:receiver).uniq
|
||||
end
|
||||
|
||||
def variants
|
||||
self.exchanges.map(&:variants).flatten.uniq
|
||||
end
|
||||
|
||||
def products
|
||||
self.variants.map(&:product).uniq
|
||||
end
|
||||
|
||||
end
|
||||
5
app/models/order_cycle_set.rb
Normal file
5
app/models/order_cycle_set.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
class OrderCycleSet < ModelSet
|
||||
def initialize(attributes={})
|
||||
super(OrderCycle, OrderCycle.all, nil, attributes)
|
||||
end
|
||||
end
|
||||
@@ -1,17 +1,18 @@
|
||||
require 'open_food_web/distributor_change_validator'
|
||||
|
||||
Spree::Order.class_eval do
|
||||
belongs_to :distributor, :class_name => 'Enterprise'
|
||||
|
||||
before_validation :shipping_address_from_distributor
|
||||
validate :products_available_from_new_distributor, :if => :distributor_id_changed?
|
||||
attr_accessible :distributor_id
|
||||
|
||||
after_create :set_default_shipping_method
|
||||
|
||||
def can_change_distributor?
|
||||
# Distributor may not be changed once an item has been added to the cart/order
|
||||
line_items.empty?
|
||||
end
|
||||
|
||||
def distributor=(distributor)
|
||||
raise "You cannot change the distributor of an order with products" unless distributor == self.distributor || can_change_distributor?
|
||||
super(distributor)
|
||||
|
||||
def products_available_from_new_distributor
|
||||
# Check that the line_items in the current order are available from a newly selected distributor
|
||||
errors.add(:distributor_id, "cannot supply the products in your cart") unless DistributorChangeValidator.new(self).can_change_to_distributor?(distributor)
|
||||
end
|
||||
|
||||
def set_distributor!(distributor)
|
||||
@@ -19,11 +20,6 @@ Spree::Order.class_eval do
|
||||
save!
|
||||
end
|
||||
|
||||
|
||||
def can_add_product_to_cart?(product)
|
||||
can_change_distributor? || product.distributors.include?(distributor)
|
||||
end
|
||||
|
||||
def set_variant_attributes(variant, attributes)
|
||||
line_item = contains?(variant)
|
||||
|
||||
@@ -34,6 +30,10 @@ Spree::Order.class_eval do
|
||||
line_item.assign_attributes(attributes)
|
||||
line_item.save!
|
||||
end
|
||||
|
||||
def line_item_variants
|
||||
line_items.map{ |li| li.variant }
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
4
app/overrides/add_cms_checkout_distribution.rb
Normal file
4
app/overrides/add_cms_checkout_distribution.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
Deface::Override.new(:virtual_path => "spree/checkout/_delivery",
|
||||
:insert_before => "fieldset#shipping_method",
|
||||
:text => "<%= cms_snippet_content(Cms::Snippet.find_by_identifier('distribution')) %>",
|
||||
:name => "cms_checkout_distribution")
|
||||
4
app/overrides/add_cms_to_cart.rb
Normal file
4
app/overrides/add_cms_to_cart.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
Deface::Override.new(:virtual_path => "spree/orders/edit",
|
||||
:insert_after => "h1",
|
||||
:text => "<%= cms_snippet_content(Cms::Snippet.find_by_identifier('cart')) %>",
|
||||
:name => "cms_to_cart")
|
||||
@@ -0,0 +1,4 @@
|
||||
Deface::Override.new(:virtual_path => "spree/admin/configurations/index",
|
||||
:name => "add_enterprise_fees_to_admin_configurations_menu",
|
||||
:insert_bottom => "[data-hook='admin_configurations_menu']",
|
||||
:partial => 'enterprise_fees/admin_configurations_menu')
|
||||
4
app/overrides/add_order_cycles_admin_tab.rb
Normal file
4
app/overrides/add_order_cycles_admin_tab.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
Deface::Override.new(:virtual_path => "spree/layouts/admin",
|
||||
:name => "cms_order_cycles_tab",
|
||||
:insert_bottom => "[data-hook='admin_tabs'], #admin_tabs[data-hook]",
|
||||
:text => "<li><%= link_to('Order Cycles', main_app.admin_order_cycles_path) %></li>")
|
||||
4
app/overrides/order_item_description.rb
Normal file
4
app/overrides/order_item_description.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
Deface::Override.new(:virtual_path => "spree/shared/_order_details",
|
||||
:replace => "[data-hook='order_item_description']",
|
||||
:partial => "spree/orders/order_item_description",
|
||||
:name => "order_item_description")
|
||||
4
app/overrides/replace_checkout_payment_button.rb
Normal file
4
app/overrides/replace_checkout_payment_button.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
Deface::Override.new(:virtual_path => "spree/checkout/_payment",
|
||||
:replace => "code[erb-loud]:contains('submit_tag t(:save_and_continue)')",
|
||||
:partial => "spree/checkout/process_my_order_button",
|
||||
:name => "process_my_order_button")
|
||||
@@ -1,4 +1,9 @@
|
||||
Deface::Override.new(:virtual_path => "spree/checkout/_address",
|
||||
:replace => "[data-hook='shipping_fieldset_wrapper']",
|
||||
:partial => "spree/checkout/distributor",
|
||||
:name => "delivery_address")
|
||||
:replace => "[data-hook='shipping_fieldset_wrapper']",
|
||||
:partial => "spree/checkout/distributor",
|
||||
:name => "replace_shipping_form")
|
||||
|
||||
Deface::Override.new(:virtual_path => "spree/checkout/edit",
|
||||
:insert_after => "[data-hook='checkout_summary_box']",
|
||||
:partial => "spree/checkout/other_available_distributors",
|
||||
:name => "other_available_distributors")
|
||||
|
||||
4
app/overrides/replace_order_details_steps_data.rb
Normal file
4
app/overrides/replace_order_details_steps_data.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
Deface::Override.new(:virtual_path => "spree/shared/_order_details",
|
||||
:replace => "div.row.steps-data",
|
||||
:partial => "spree/shared/order_details_steps_data",
|
||||
:name => "order_details_steps_data")
|
||||
9
app/overrides/set_auth_token_in_test.rb
Normal file
9
app/overrides/set_auth_token_in_test.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
Deface::Override.new(:virtual_path => "spree/layouts/spree_application",
|
||||
:insert_bottom => "[data-hook='inside_head']",
|
||||
:partial => "layouts/auth_token_script",
|
||||
:name => "auth_token_script")
|
||||
|
||||
Deface::Override.new(:virtual_path => "spree/layouts/admin",
|
||||
:insert_bottom => "[data-hook='admin_inside_head']",
|
||||
:partial => "layouts/auth_token_script",
|
||||
:name => "auth_token_script")
|
||||
31
app/presenters/enterprise_fee_presenter.rb
Normal file
31
app/presenters/enterprise_fee_presenter.rb
Normal file
@@ -0,0 +1,31 @@
|
||||
class EnterpriseFeePresenter
|
||||
def initialize(controller, enterprise_fee, index)
|
||||
@controller, @enterprise_fee, @index = controller, enterprise_fee, index
|
||||
end
|
||||
|
||||
delegate :id, :enterprise_id, :fee_type, :name, :calculator_type, :to => :enterprise_fee
|
||||
|
||||
def enterprise_fee
|
||||
@enterprise_fee
|
||||
end
|
||||
|
||||
|
||||
def enterprise_name
|
||||
@enterprise_fee.enterprise.andand.name
|
||||
end
|
||||
|
||||
def calculator_description
|
||||
@enterprise_fee.calculator.andand.description
|
||||
end
|
||||
|
||||
def calculator_settings
|
||||
result = nil
|
||||
|
||||
@controller.send(:with_format, :html) do
|
||||
result = @controller.render_to_string :partial => 'admin/enterprise_fees/calculator_settings', :locals => {:enterprise_fee => @enterprise_fee, :index => @index}
|
||||
end
|
||||
|
||||
result.gsub('[0]', '[{{ $index }}]').gsub('_0_', '_{{ $index }}_')
|
||||
end
|
||||
|
||||
end
|
||||
13
app/presenters/variant_presenter.rb
Normal file
13
app/presenters/variant_presenter.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
class VariantPresenter
|
||||
attr_accessor :variant
|
||||
|
||||
def initialize(variant)
|
||||
@variant = variant
|
||||
end
|
||||
|
||||
delegate :id, :to => :variant
|
||||
|
||||
def image_url
|
||||
@variant.images.first.attachment.url :mini if @variant.images.present?
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,12 @@
|
||||
-# Render only the calculator settings and not the surrounding form
|
||||
- enterprise_fee_set = ModelSet.new(EnterpriseFee, EnterpriseFee.where(:id => enterprise_fee.id))
|
||||
- calculator_form_string = nil
|
||||
- form_for enterprise_fee_set, :as => :enterprise_fee_set, :url => '' do |form|
|
||||
- form.fields_for :collection do |f|
|
||||
- calculator_form_string = capture do
|
||||
- if !enterprise_fee.new_record?
|
||||
.calculator-settings
|
||||
= f.fields_for :calculator do |calculator_form|
|
||||
= preference_fields(enterprise_fee.calculator, calculator_form)
|
||||
|
||||
= calculator_form_string
|
||||
33
app/views/admin/enterprise_fees/index.html.haml
Normal file
33
app/views/admin/enterprise_fees/index.html.haml
Normal file
@@ -0,0 +1,33 @@
|
||||
%h1 Enterprise Fees
|
||||
|
||||
= ng_form_for @enterprise_fee_set, :url => main_app.bulk_update_admin_enterprise_fees_path, :html => {'ng-app' => 'enterprise_fees', 'ng-controller' => 'AdminEnterpriseFeesCtrl'} do |enterprise_fee_set_form|
|
||||
- if @enterprise_fee_set.errors.present?
|
||||
%h2 Errors
|
||||
%ul
|
||||
- @enterprise_fee_set.errors.each do |error|
|
||||
%li= error
|
||||
|
||||
%input.search{'ng-model' => 'query', 'placeholder' => 'Search'}
|
||||
|
||||
%table.index#listing_enterprise_fees
|
||||
%thead
|
||||
%tr
|
||||
%th Enterprise
|
||||
%th Fee Type
|
||||
%th Name
|
||||
%th Calculator
|
||||
%th Calculator values
|
||||
%th
|
||||
%tbody
|
||||
= enterprise_fee_set_form.ng_fields_for :collection do |f|
|
||||
%tr{'ng-repeat' => 'enterprise_fee in enterprise_fees | filter:query'}
|
||||
%td
|
||||
= f.ng_hidden_field :id
|
||||
= f.ng_collection_select :enterprise_id, Enterprise.all, :id, :name, 'enterprise_fee.enterprise_id', :include_blank => true
|
||||
%td= f.ng_select :fee_type, enterprise_fee_type_options, 'enterprise_fee.fee_type'
|
||||
%td= f.ng_text_field :name
|
||||
%td= f.ng_collection_select :calculator_type, @calculators, :name, :description, 'enterprise_fee.calculator_type', {'class' => 'calculator_type', 'ng-model' => 'calculatorType', 'spree-ensure-calculator-preferences-match-type' => "1"}
|
||||
%td{'ng-bind-html-unsafe-compiled' => 'enterprise_fee.calculator_settings'}
|
||||
%td{'spree-delete-resource' => "1"}
|
||||
|
||||
= enterprise_fee_set_form.submit 'Update'
|
||||
10
app/views/admin/enterprise_fees/index.rep
Normal file
10
app/views/admin/enterprise_fees/index.rep
Normal file
@@ -0,0 +1,10 @@
|
||||
r.list_of :enterprise_fees, @presented_collection do
|
||||
r.element :id
|
||||
r.element :enterprise_id
|
||||
r.element :enterprise_name
|
||||
r.element :fee_type
|
||||
r.element :name
|
||||
r.element :calculator_type
|
||||
r.element :calculator_description
|
||||
r.element :calculator_settings
|
||||
end
|
||||
@@ -7,6 +7,8 @@
|
||||
<br class="clear" />
|
||||
</div>
|
||||
|
||||
<h1>Enterprises</h1>
|
||||
|
||||
<%= form_for @enterprise_set, :url => main_app.bulk_update_admin_enterprises_path do |f| %>
|
||||
<table class="index" id="listing_enterprises">
|
||||
<thead>
|
||||
@@ -19,7 +21,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%= f.fields_for :enterprises do |enterprise_form| %>
|
||||
<%= f.fields_for :collection do |enterprise_form| %>
|
||||
<% enterprise = enterprise_form.object %>
|
||||
<tr>
|
||||
<td><%= link_to enterprise.name, main_app.admin_enterprise_path(enterprise) %></td>
|
||||
|
||||
15
app/views/admin/enterprises/index.rep
Normal file
15
app/views/admin/enterprises/index.rep
Normal file
@@ -0,0 +1,15 @@
|
||||
r.list_of :enterprises, @collection do
|
||||
r.element :id
|
||||
r.element :name
|
||||
|
||||
r.list_of :supplied_products do |product|
|
||||
r.element :name
|
||||
r.element :supplier_name, product.supplier.andand.name
|
||||
r.element :image_url, product.images.present? ? product.images.first.attachment.url(:mini) : nil
|
||||
r.element :master_id, product.master.id
|
||||
r.list_of :variants do |variant|
|
||||
r.element :id
|
||||
r.element :label, variant.options_text
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,10 @@
|
||||
%td{:colspan => 3}
|
||||
.exchange-product{'ng-repeat' => 'product in supplied_products | filter:productSuppliedToOrderCycle'}
|
||||
.exchange-product-details
|
||||
.supplier {{ product.supplier_name }}
|
||||
= check_box_tag 'order_cycle_outgoing_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}', 1, 1, 'ng-hide' => 'product.variants', 'ng-model' => 'exchange.variants[product.master_id]', 'id' => 'order_cycle_outgoing_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}'
|
||||
%img{'ng-src' => '{{ product.image_url }}'}
|
||||
{{ product.name }}
|
||||
.exchange-product-variant{'ng-repeat' => 'variant in product.variants | filter:variantSuppliedToOrderCycle'}
|
||||
= check_box_tag 'order_cycle_outgoing_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}', 1, 1, 'ng-model' => 'exchange.variants[variant.id]', 'id' => 'order_cycle_outgoing_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}'
|
||||
{{ variant.label }}
|
||||
15
app/views/admin/order_cycles/_exchange_form.html.haml
Normal file
15
app/views/admin/order_cycles/_exchange_form.html.haml
Normal file
@@ -0,0 +1,15 @@
|
||||
%td.active= check_box_tag 'order_cycle_exchange_{{ $index }}_active', 1, 1, 'ng-model' => 'exchange.active', 'id' => 'order_cycle_exchange_{{ $index }}_active'
|
||||
%td{:class => "#{type}_name"} {{ enterprises[exchange.enterprise_id].name }}
|
||||
%td.products
|
||||
= f.submit 'Products', 'ng-click' => 'toggleProducts($event, exchange)'
|
||||
{{ exchangeSelectedVariants(exchange) }} /
|
||||
- if type == 'supplier'
|
||||
{{ enterpriseTotalVariants(enterprises[exchange.enterprise_id]) }}
|
||||
- else
|
||||
{{ incomingExchangesVariants().length }}
|
||||
selected
|
||||
- if type == 'distributor'
|
||||
%td.collection-details
|
||||
= text_field_tag 'order_cycle_outgoing_exchange_{{ $index }}_pickup_time', '', 'id' => 'order_cycle_outgoing_exchange_{{ $index }}_pickup_time', 'placeholder' => 'Pickup time / date', 'ng-model' => 'exchange.pickup_time'
|
||||
%br/
|
||||
= text_field_tag 'order_cycle_outgoing_exchange_{{ $index }}_pickup_instructions', '', 'id' => 'order_cycle_outgoing_exchange_{{ $index }}_pickup_instructions', 'placeholder' => 'Delivery instructions', 'ng-model' => 'exchange.pickup_instructions'
|
||||
@@ -0,0 +1,10 @@
|
||||
/ TODO: Unify this with exchange_distributed_products_form
|
||||
%td{:colspan => 3}
|
||||
.exchange-product{'ng-repeat' => 'product in enterprises[exchange.enterprise_id].supplied_products'}
|
||||
.exchange-product-details
|
||||
= check_box_tag 'order_cycle_incoming_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}', 1, 1, 'ng-hide' => 'product.variants', 'ng-model' => 'exchange.variants[product.master_id]', 'id' => 'order_cycle_incoming_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}'
|
||||
%img{'ng-src' => '{{ product.image_url }}'}
|
||||
{{ product.name }}
|
||||
.exchange-product-variant{'ng-repeat' => 'variant in product.variants'}
|
||||
= check_box_tag 'order_cycle_incoming_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}', 1, 1, 'ng-model' => 'exchange.variants[variant.id]', 'id' => 'order_cycle_incoming_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}'
|
||||
{{ variant.label }}
|
||||
62
app/views/admin/order_cycles/_form.html.haml
Normal file
62
app/views/admin/order_cycles/_form.html.haml
Normal file
@@ -0,0 +1,62 @@
|
||||
= f.label :name
|
||||
= f.text_field :name, 'ng-model' => 'order_cycle.name', 'required' => true
|
||||
%br/
|
||||
|
||||
.date-field
|
||||
= f.label :orders_open_at, 'Orders open'
|
||||
= f.text_field :orders_open_at, 'datetimepicker' => 'order_cycle.orders_open_at', 'ng-model' => 'order_cycle.orders_open_at'
|
||||
.date-field
|
||||
= f.label :orders_close_at, 'Orders close'
|
||||
= f.text_field :orders_close_at, 'datetimepicker' => 'order_cycle.orders_close_at', 'ng-model' => 'order_cycle.orders_close_at'
|
||||
%br/
|
||||
|
||||
|
||||
%h2 Incoming
|
||||
%table.exchanges
|
||||
%thead
|
||||
%tr
|
||||
%th
|
||||
%th Supplier
|
||||
%th Products
|
||||
%tbody{'ng-repeat' => 'exchange in order_cycle.incoming_exchanges'}
|
||||
%tr.supplier
|
||||
= render 'exchange_form', :f => f, :type => 'supplier'
|
||||
%tr.products{'ng-show' => 'exchange.showProducts'}
|
||||
= render 'exchange_supplied_products_form'
|
||||
|
||||
= select_tag :new_supplier_id, options_from_collection_for_select(Enterprise.is_primary_producer, :id, :name), {'ng-model' => 'new_supplier_id'}
|
||||
= f.submit 'Add supplier', 'ng-click' => 'addSupplier($event)'
|
||||
|
||||
|
||||
%h2 Coordinator
|
||||
= f.label :coordinator_id, 'Coordinator'
|
||||
= f.collection_select :coordinator_id, coordinating_enterprises, :id, :name, {}, {'ng-model' => 'order_cycle.coordinator_id', 'required' => true}
|
||||
|
||||
%h2 Outgoing
|
||||
%table.exchanges
|
||||
%thead
|
||||
%tr
|
||||
%th
|
||||
%th Distributor
|
||||
%th Products
|
||||
%th Collection details
|
||||
%tbody{'ng-repeat' => 'exchange in order_cycle.outgoing_exchanges'}
|
||||
%tr.distributor
|
||||
= render 'exchange_form', :f => f, :type => 'distributor'
|
||||
%tr.products{'ng-show' => 'exchange.showProducts'}
|
||||
= render 'exchange_distributed_products_form'
|
||||
|
||||
= select_tag :new_distributor_id, options_from_collection_for_select(Enterprise.is_distributor, :id, :name), {'ng-model' => 'new_distributor_id'}
|
||||
= f.submit 'Add distributor', 'ng-click' => 'addDistributor($event)'
|
||||
|
||||
.actions
|
||||
= f.submit @order_cycle.new_record? ? 'Create' : 'Update'
|
||||
or
|
||||
= link_to 'Cancel', main_app.admin_order_cycles_path
|
||||
|
||||
|
||||
%h2 Debug information
|
||||
|
||||
%pre order_cycle = {{ order_cycle | json }}
|
||||
%pre enterprises = {{ enterprises | json }}
|
||||
%pre supplied_products = {{ supplied_products | json }}
|
||||
4
app/views/admin/order_cycles/edit.html.haml
Normal file
4
app/views/admin/order_cycles/edit.html.haml
Normal file
@@ -0,0 +1,4 @@
|
||||
%h1 Edit Order Cycle
|
||||
|
||||
= form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'order_cycle', 'ng-controller' => 'AdminEditOrderCycleCtrl', 'ng-submit' => 'submit()'} do |f|
|
||||
= render 'form', :f => f
|
||||
41
app/views/admin/order_cycles/index.html.haml
Normal file
41
app/views/admin/order_cycles/index.html.haml
Normal file
@@ -0,0 +1,41 @@
|
||||
.toolbar{'data-hook' => "toolbar"}
|
||||
%ul.actions
|
||||
%li
|
||||
= button_link_to "New Order Cycle", main_app.new_admin_order_cycle_path, :icon => 'add', :id => 'admin_new_order_cycle_link'
|
||||
%br.clear/
|
||||
|
||||
%h1 Order Cycles
|
||||
|
||||
= form_for @order_cycle_set, :url => main_app.bulk_update_admin_order_cycles_path do |f|
|
||||
%table.index#listing_order_cycles
|
||||
%thead
|
||||
%tr
|
||||
%th Name
|
||||
%th Open
|
||||
%th Close
|
||||
%th Coordinator
|
||||
%th Suppliers
|
||||
%th Distributors
|
||||
%th Products
|
||||
%th
|
||||
%tbody
|
||||
= f.fields_for :collection do |order_cycle_form|
|
||||
- order_cycle = order_cycle_form.object
|
||||
%tr
|
||||
%td= link_to order_cycle.name, main_app.edit_admin_order_cycle_path(order_cycle)
|
||||
%td= order_cycle_form.text_field :orders_open_at, :class => 'datetimepicker', :value => order_cycle.orders_open_at
|
||||
%td= order_cycle_form.text_field :orders_close_at, :class => 'datetimepicker', :value => order_cycle.orders_close_at
|
||||
%td= order_cycle.coordinator.name
|
||||
%td.suppliers
|
||||
- order_cycle.suppliers.each do |s|
|
||||
= s.name
|
||||
%br/
|
||||
%td.distributors
|
||||
- order_cycle.distributors.each do |d|
|
||||
= d.name
|
||||
%br/
|
||||
%td.products
|
||||
- order_cycle.variants.each do |v|
|
||||
= image_tag(v.images.first.attachment.url(:mini)) if v.images.present?
|
||||
%td
|
||||
= f.submit 'Update'
|
||||
4
app/views/admin/order_cycles/new.html.haml
Normal file
4
app/views/admin/order_cycles/new.html.haml
Normal file
@@ -0,0 +1,4 @@
|
||||
%h1 New Order Cycle
|
||||
|
||||
= form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'order_cycle', 'ng-controller' => 'AdminCreateOrderCycleCtrl', 'ng-submit' => 'submit()'} do |f|
|
||||
= render 'form', :f => f
|
||||
17
app/views/admin/order_cycles/show.rep
Normal file
17
app/views/admin/order_cycles/show.rep
Normal file
@@ -0,0 +1,17 @@
|
||||
r.element :order_cycle, @order_cycle do
|
||||
r.element :id
|
||||
r.element :name
|
||||
r.element :orders_open_at, @order_cycle.orders_open_at.to_s
|
||||
r.element :orders_close_at, @order_cycle.orders_close_at.to_s
|
||||
r.element :coordinator_id
|
||||
r.list_of :exchanges do |exchange|
|
||||
r.element :id
|
||||
r.element :sender_id
|
||||
r.element :receiver_id
|
||||
|
||||
r.element :variants, Hash[ exchange.variants.map { |v| [v.id, true] } ], {}
|
||||
|
||||
r.element :pickup_time
|
||||
r.element :pickup_instructions
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,3 @@
|
||||
%tr
|
||||
%td= link_to "Enterprise Fees", main_app.admin_enterprise_fees_path
|
||||
%td Create and manage fees charged by enterprises on order cycles
|
||||
4
app/views/layouts/_auth_token_script.html.haml
Normal file
4
app/views/layouts/_auth_token_script.html.haml
Normal file
@@ -0,0 +1,4 @@
|
||||
:javascript
|
||||
if(typeof AUTH_TOKEN === 'undefined') {
|
||||
var AUTH_TOKEN = '';
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
<script type="text/javascript">
|
||||
var uvOptions = {};
|
||||
(function() {
|
||||
var uv = document.createElement('script'); uv.type = 'text/javascript'; uv.async = true;
|
||||
uv.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'widget.uservoice.com/mCbT1cbjQZkPELXOix9Ag.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(uv, s);
|
||||
})();
|
||||
</script>
|
||||
10
app/views/layouts/_feedback_script.html.erb
Normal file
10
app/views/layouts/_feedback_script.html.erb
Normal file
@@ -0,0 +1,10 @@
|
||||
<% if Rails.env.production? %>
|
||||
<script type="text/javascript">
|
||||
var uvOptions = {};
|
||||
(function() {
|
||||
var uv = document.createElement('script'); uv.type = 'text/javascript'; uv.async = true;
|
||||
uv.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'widget.uservoice.com/mCbT1cbjQZkPELXOix9Ag.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(uv, s);
|
||||
})();
|
||||
</script>
|
||||
<% end %>
|
||||
39
app/views/spree/admin/overview/index.html.erb
Normal file
39
app/views/spree/admin/overview/index.html.erb
Normal file
@@ -0,0 +1,39 @@
|
||||
<% content_for :head do %>
|
||||
<% if Rails.env.production? %>
|
||||
<%= stylesheet_link_tag 'https://api.jirafe.com/dashboard/css/spree_ui.css', :media => 'all' %>
|
||||
<%= javascript_include_tag 'https://jirafe.com/dashboard/js/spree_namespaced_ui.js' %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% if Rails.env.production? %>
|
||||
<% if Spree::Dash::Config.configured? %>
|
||||
<h1><%= t(:overview) %></h1>
|
||||
<div id="jirafe"></div>
|
||||
<%= javascript_tag :defer => 'defer' do %>
|
||||
jirafe.jQuery('#jirafe').jirafe({
|
||||
api_url: 'https://api.jirafe.com/v1',
|
||||
api_token: '<%= Spree::Dash::Config.token %>',
|
||||
app_id: '<%= Spree::Dash::Config.app_id %>',
|
||||
version: 'spree-v0.1.0',
|
||||
locale: '<%= Spree::Dash::Config.locale %>' });
|
||||
setTimeout(function() {
|
||||
if ($('mod-jirafe') == undefined) {
|
||||
$('messages').insert ("<ul class=\"messages\"><li class=\"error-msg\">We're unable to connect with the Jirafe service for the moment. Please wait a few minutes and refresh this page later.</li></ul>");
|
||||
}
|
||||
}, 10000);
|
||||
<% end %>
|
||||
<div id="jirafe_locales">
|
||||
<%= raw jirafe_locale_links.join(' | ') %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="analytics_splash">
|
||||
<%= image_tag 'analytics_dashboard_preview.png', :alt => 'Spree Analytics' %>
|
||||
</div>
|
||||
<br/>
|
||||
<div class="preview-buttons">
|
||||
<%= link_to content_tag(:span, t(:activate)), admin_analytics_sign_up_path, :class => 'button green' %>
|
||||
<%= t(:or) %>
|
||||
<%= link_to content_tag(:span, t(:learn_more)), "http://spreecommerce.com/blog/2012/01/31/introducing-spree-analytics/", :class => 'button', :target => '_blank' %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
@@ -0,0 +1,13 @@
|
||||
<% unless @order.state != 'address' %>
|
||||
<div class="columns omega four" style="padding-top: 30px">
|
||||
<% unless alternative_available_distributors(@order).empty? %>
|
||||
<%= form_for(@order) do |f| %>
|
||||
<%= f.label :distributor_label, "Alternative distributors for this order:" %>
|
||||
<%= f.select :distributor_id, options_for_select( enterprises_options(alternative_available_distributors(@order)) ) %>
|
||||
<%= f.submit "Change Distributor" %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
No alternative distributors available.
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -0,0 +1 @@
|
||||
<%= submit_tag "Process My Order", :class => 'continue button primary' %>
|
||||
@@ -1,10 +1,11 @@
|
||||
Dear Customer,
|
||||
Dear <%= @order.bill_address.firstname %>,
|
||||
|
||||
Please review and retain the following order information for your records.
|
||||
|
||||
============================================================
|
||||
Order Summary
|
||||
============================================================
|
||||
Order for: <%= @order.bill_address.full_name %>
|
||||
<% @order.line_items.each do |item| %>
|
||||
<%= item.variant.sku %> <%= raw(item.variant.product.name) %> <%= raw(item.variant.options_text) -%> (<%=item.quantity%>) @ <%= number_to_currency item.price %> = <%= number_to_currency(item.price * item.quantity) %>
|
||||
<% end %>
|
||||
@@ -15,15 +16,22 @@ Subtotal: <%= number_to_currency @order.item_total %>
|
||||
<% end %>
|
||||
Order Total: <%= number_to_currency(@order.total) %>
|
||||
|
||||
<% if @order.payment_method.name.include? "EFT" %>
|
||||
============================================================
|
||||
Delivery Details
|
||||
Payment Details
|
||||
============================================================
|
||||
<%= @order.payment_method.description.html_safe %>
|
||||
|
||||
<% end %>
|
||||
============================================================
|
||||
Collection / Delivery Details
|
||||
============================================================
|
||||
Address:
|
||||
<%= @order.distributor.name %>
|
||||
<% address = @order.distributor.address %>
|
||||
<%= address.address1 %> <%= ",\n #{address.address2}" unless address.address2.blank? %>
|
||||
<%= [address.city, address.state_text, address.zipcode, address.country.name].compact.join ', ' %>
|
||||
Colection time:
|
||||
Collection time:
|
||||
<%= @order.distributor.next_collection_at %>
|
||||
Contact:
|
||||
<%= @order.distributor.contact %>
|
||||
|
||||
@@ -4,5 +4,4 @@
|
||||
- if @order.insufficient_stock_lines.include? line_item
|
||||
%span.out-of-stock
|
||||
= variant.in_stock? ? t(:insufficient_stock, :on_hand => variant.on_hand) : t(:out_of_stock)
|
||||
%br/
|
||||
= truncate_html(variant.product.description, :length => 100, :omission => "...")
|
||||
%br/
|
||||
@@ -1,5 +1,6 @@
|
||||
#delivery-fees
|
||||
%h2 Delivery Fees
|
||||
%h2 Distribution Costs
|
||||
= cms_snippet_content(Cms::Snippet.find_by_identifier('cart_distribution_costs'))
|
||||
|
||||
%table#delivery
|
||||
%thead
|
||||
|
||||
3
app/views/spree/orders/_order_item_description.html.haml
Normal file
3
app/views/spree/orders/_order_item_description.html.haml
Normal file
@@ -0,0 +1,3 @@
|
||||
%td(data-hook = "order_item_description")
|
||||
%h4= item.variant.product.name
|
||||
= "(" + variant_options(item.variant) + ")" unless item.variant.option_values.empty?
|
||||
@@ -1,26 +1,34 @@
|
||||
.add-to-cart
|
||||
- order = current_order(false)
|
||||
- if !@product.has_stock? && !Spree::Config[:allow_backorders]
|
||||
= content_tag('strong', t(:out_of_stock))
|
||||
|
||||
- elsif current_order(false) && !current_order(false).can_add_product_to_cart?(@product)
|
||||
- elsif !order.nil? && !DistributorChangeValidator.new(order).can_change_distributor? && !@product.distributors.include?(order.distributor)
|
||||
.error-distributor
|
||||
Please complete your order at
|
||||
= link_to current_distributor.name, root_path
|
||||
before shopping with another distributor.
|
||||
|
||||
- else
|
||||
%p Quantity
|
||||
= number_field_tag (@product.has_variants? ? :quantity : "variants[#{@product.master.id}]"), 1, :class => 'title', :in => 1..@product.on_hand
|
||||
%div(class = "columns alpha two")
|
||||
%div Quantity
|
||||
= number_field_tag (@product.has_variants? ? :quantity : "variants[#{@product.master.id}]"), 1, :class => 'title', :in => 1..@product.on_hand
|
||||
- if @product.group_buy
|
||||
%p Max quantity
|
||||
= number_field_tag (@product.has_variants? ? :max_quantity : "variant_attributes[#{@product.master.id}][max_quantity]"), 1, :class => 'title max_quantity', :in => 1..@product.on_hand
|
||||
- order = current_order(false)
|
||||
- if order.nil? || order.can_change_distributor?
|
||||
%p Distributor
|
||||
= select_tag "distributor_id", options_from_collection_for_select([Enterprise.new]+@product.distributors, "id", "name", current_distributor.andand.id)
|
||||
- else
|
||||
= hidden_field_tag "distributor_id", order.distributor.id
|
||||
.distributor-fixed= "Your distributor for this order is #{order.distributor.name}"
|
||||
%br/
|
||||
%div(class = "columns alpha three")
|
||||
%div Max quantity
|
||||
= number_field_tag (@product.has_variants? ? :max_quantity : "variant_attributes[#{@product.master.id}][max_quantity]"), 1, :class => 'title max_quantity', :in => 1..@product.on_hand
|
||||
%div.cleared
|
||||
%br
|
||||
- if order.nil? || order.distributor.nil?
|
||||
%div Distributor for your order:
|
||||
= select_tag "distributor_id", options_from_collection_for_select([Enterprise.new]+@product.distributors, "id", "name", :include_blank => '')
|
||||
- else
|
||||
- available_distributors = DistributorChangeValidator.new(order).available_distributors(@product.distributors)
|
||||
- if available_distributors.length > 1
|
||||
%div Distributor for your order:
|
||||
= select_tag "distributor_id", options_from_collection_for_select(available_distributors, "id", "name", current_distributor.andand.id)
|
||||
- else
|
||||
= hidden_field_tag "distributor_id", order.distributor.id
|
||||
.distributor-fixed= "Your distributor for this order is #{order.distributor.name}"
|
||||
%br
|
||||
= button_tag :class => 'large primary', :id => 'add-to-cart-button', :type => :submit do
|
||||
= t(:add_to_cart)
|
||||
= t(:add_to_cart)
|
||||
@@ -1,17 +1,30 @@
|
||||
%div{:data-hook => "product_source"}
|
||||
%h6.product-section-title Source
|
||||
%h6.product-section-title SUPPLIER
|
||||
%table#product-source.table-display{:width => "100%"}
|
||||
%tbody
|
||||
- if @product.supplier
|
||||
%tr.odd
|
||||
%td
|
||||
%strong Supplier
|
||||
%td= @product.supplier.name
|
||||
%td= link_to @product.supplier.name, [main_app, @product.supplier]
|
||||
%br/
|
||||
%h6.product-section-title DISTRIBUTORS
|
||||
%table#product-source.table-display{:width => "100%"}
|
||||
%tbody
|
||||
- order = current_order(false)
|
||||
- validator = DistributorChangeValidator.new(order)
|
||||
- @product.distributors.each do |distributor|
|
||||
%tr.even
|
||||
%td
|
||||
%strong Distributor
|
||||
%td= distributor.name
|
||||
- if !order.nil? && distributor == order.distributor
|
||||
%tr.odd
|
||||
%td
|
||||
%b= link_to(distributor.name, [main_app, distributor])
|
||||
%td
|
||||
%b Current
|
||||
- elsif order.nil? || validator.can_change_to_distributor?(distributor)
|
||||
%tr.even
|
||||
%td= link_to distributor.name, [main_app, distributor]
|
||||
%td Available
|
||||
-#%td= link_to "Change to distributor", select_distributor_order_path(distributor)
|
||||
- else
|
||||
%tr.even
|
||||
%td= link_to distributor.name, [main_app, distributor]
|
||||
%td
|
||||
|
||||
@@ -9,13 +9,14 @@
|
||||
%h6.filter_name Shop by Distributor
|
||||
%ul.filter_choices
|
||||
- order = current_order(false)
|
||||
- validator = DistributorChangeValidator.new(order)
|
||||
- @distributors.each do |distributor|
|
||||
%li.nowrap
|
||||
- if order.nil? || order.can_change_distributor?
|
||||
= link_to distributor.name, main_app.select_distributor_enterprise_path(distributor)
|
||||
- if order.nil? || validator.can_change_to_distributor?(distributor)
|
||||
= link_to distributor.name, [main_app, distributor]
|
||||
- elsif order.distributor == distributor
|
||||
= link_to distributor.name, [main_app, distributor]
|
||||
- else
|
||||
%span.inactive= distributor.name
|
||||
- if current_distributor && order.can_change_distributor?
|
||||
= button_to 'Browse All Distributors', main_app.deselect_distributor_enterprises_path, :method => :get
|
||||
%abbr(title="One or more of the products in your cart is not available from this distributor")= distributor.name
|
||||
- if current_distributor && validator.can_change_distributor?
|
||||
= button_to 'Browse All Distributors', deselect_distributor_orders_path, :method => :get
|
||||
|
||||
49
app/views/spree/shared/_order_details_steps_data.html.erb
Normal file
49
app/views/spree/shared/_order_details_steps_data.html.erb
Normal file
@@ -0,0 +1,49 @@
|
||||
<div class="row steps-data">
|
||||
|
||||
<div class="columns alpha six">
|
||||
<h6><%= "Customer Details" %> <%= link_to "(#{t(:edit)})", checkout_state_path(:address) unless @order.completed? %></h6>
|
||||
<div class="address">
|
||||
Name: <%= order.bill_address.full_name %><br />
|
||||
Address: <%= order.bill_address.address1 + ", " + order.bill_address.city %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="columns alpha six">
|
||||
<h6><%= "Distributor Details" %> <%# link_to "(#{t(:edit)})", checkout_state_path(:address) unless @order.completed? %></h6>
|
||||
<div class="address">
|
||||
Distributor: <%= order.distributor.name %><br />
|
||||
Address: <%= order.distributor.address.address1 + ", " + order.distributor.address.city %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="columns alpha four">
|
||||
<h6><%= t(:shipping_method) %> <%= link_to "(#{t(:edit)})", checkout_state_path(:delivery) unless @order.completed? %></h6>
|
||||
<div class="delivery">
|
||||
<%= order.shipping_method.name %>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="row steps-data">
|
||||
<div class="columns alpha six" <% if order.payment_method.name.include? "EFT" %>id="eft-payment-alert"<% end %>>
|
||||
<h6><%= t(:payment_information) %> <%= link_to "(#{t(:edit)})", checkout_state_path(:payment) unless @order.completed? %></h6>
|
||||
<div class="payment-info">
|
||||
<% if order.payment_method.name.include? "PayPal" %>
|
||||
<div class="flash notice">Your payment via PayPal has been processed successfully.</div>
|
||||
<% elsif order.payment_method.name.include? "EFT" %>
|
||||
<span><%= order.payment_method.description.html_safe %></span>
|
||||
<% elsif order.creditcards.empty? == false %>
|
||||
<span class="cc-type">
|
||||
<%= image_tag "creditcards/icons/#{order.creditcards.first.cc_type}.png" %>
|
||||
<%= t(:ending_in)%> <%= order.creditcards.first.last_digits %>
|
||||
</span>
|
||||
<br />
|
||||
<span class="full-name">
|
||||
<%= order.creditcards.first.first_name %>
|
||||
<%= order.creditcards.first.last_name %>
|
||||
</span>
|
||||
<% elsif order.payment_method.type == "Spree::PaymentMethod::Check" %>
|
||||
<span><%= order.payment_method.description %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
22
config-angular/testacular-e2e.conf.js
Normal file
22
config-angular/testacular-e2e.conf.js
Normal file
@@ -0,0 +1,22 @@
|
||||
basePath = '../';
|
||||
|
||||
files = [
|
||||
ANGULAR_SCENARIO,
|
||||
ANGULAR_SCENARIO_ADAPTER,
|
||||
'test/e2e/**/*.js'
|
||||
];
|
||||
|
||||
autoWatch = false;
|
||||
|
||||
browsers = ['Chrome'];
|
||||
|
||||
singleRun = true;
|
||||
|
||||
proxies = {
|
||||
'/': 'http://localhost:8000/'
|
||||
};
|
||||
|
||||
junitReporter = {
|
||||
outputFile: 'test_out/e2e.xml',
|
||||
suite: 'e2e'
|
||||
};
|
||||
24
config-angular/testacular.conf.js
Normal file
24
config-angular/testacular.conf.js
Normal file
@@ -0,0 +1,24 @@
|
||||
basePath = '../';
|
||||
|
||||
files = [
|
||||
JASMINE,
|
||||
JASMINE_ADAPTER,
|
||||
'app/assets/javascripts/shared/jquery-1.8.0.js', // TODO: Can we link to Rails' jquery?
|
||||
'app/assets/javascripts/shared/angular.js',
|
||||
'app/assets/javascripts/shared/angular-*.js',
|
||||
|
||||
'app/assets/javascripts/admin/order_cycle.js.erb.coffee',
|
||||
|
||||
'spec/javascripts/unit/**/*.js*'
|
||||
];
|
||||
|
||||
exclude = ['**/.#*']
|
||||
|
||||
autoWatch = true;
|
||||
|
||||
browsers = ['Chrome'];
|
||||
|
||||
junitReporter = {
|
||||
outputFile: 'log/testacular-unit.xml',
|
||||
suite: 'unit'
|
||||
};
|
||||
@@ -28,6 +28,13 @@ module Openfoodweb
|
||||
initializer "spree.register.calculators" do |app|
|
||||
app.config.spree.calculators.shipping_methods << OpenFoodWeb::Calculator::Itemwise
|
||||
app.config.spree.calculators.shipping_methods << OpenFoodWeb::Calculator::Weight
|
||||
|
||||
app.config.spree.calculators.enterprise_fees = [Spree::Calculator::FlatPercentItemTotal,
|
||||
Spree::Calculator::FlatRate,
|
||||
Spree::Calculator::FlexiRate,
|
||||
Spree::Calculator::PerItem,
|
||||
Spree::Calculator::PriceSack,
|
||||
OpenFoodWeb::Calculator::Weight]
|
||||
end
|
||||
|
||||
|
||||
@@ -36,7 +43,7 @@ module Openfoodweb
|
||||
# -- all .rb files in that directory are automatically loaded.
|
||||
|
||||
# Custom directories with classes and modules you want to be autoloadable.
|
||||
# config.autoload_paths += %W(#{config.root}/extras)
|
||||
config.autoload_paths += %W(#{config.root}/app/presenters)
|
||||
|
||||
# Only load the plugins named here, in the order given (default is alphabetical).
|
||||
# :all can be used as a placeholder for all plugins not explicitly named.
|
||||
|
||||
@@ -27,6 +27,9 @@ Openfoodweb::Application.configure do
|
||||
|
||||
# Expands the lines which load the assets
|
||||
config.assets.debug = true
|
||||
|
||||
# Show emails using Letter Opener
|
||||
config.action_mailer.delivery_method = :letter_opener
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -3,43 +3,43 @@
|
||||
ComfortableMexicanSofa.configure do |config|
|
||||
# Title of the admin area
|
||||
# config.cms_title = 'ComfortableMexicanSofa CMS Engine'
|
||||
|
||||
|
||||
# Module responsible for authentication. You can replace it with your own.
|
||||
# It simply needs to have #authenticate method. See http_auth.rb for reference.
|
||||
config.admin_auth = 'CmsSpreeAuth'
|
||||
|
||||
|
||||
# Module responsible for public authentication. Similar to the above. You also
|
||||
# will have access to @cms_site, @cms_layout, @cms_page so you can use them in
|
||||
# your logic. Default module doesn't do anything.
|
||||
# config.public_auth = 'ComfortableMexicanSofa::DummyAuth'
|
||||
|
||||
# Default url to access admin area is http://yourhost/cms-admin/
|
||||
|
||||
# Default url to access admin area is http://yourhost/cms-admin/
|
||||
# You can change 'cms-admin' to 'admin', for example. To disable admin area
|
||||
# entirely set this to '' or nil
|
||||
# config.admin_route_prefix = 'cms-admin'
|
||||
|
||||
|
||||
# When arriving at /cms-admin you may chose to redirect to arbirtary path,
|
||||
# for example '/cms-admin/users'
|
||||
# config.admin_route_redirect = ''
|
||||
|
||||
|
||||
# Normally we include default routes from https://github.com/comfy/comfortable-mexican-sofa/blob/master/config/routes.rb
|
||||
# If you want to include the routes manually set this to false
|
||||
# config.use_default_routes = true
|
||||
|
||||
|
||||
# /sitemap.xml that is used by search engines for indexing. It's enabled by
|
||||
# default, but you may turn it off.
|
||||
# config.enable_sitemap = true
|
||||
|
||||
|
||||
# File uploads use Paperclip and can support filesystem or s3 uploads. Override
|
||||
# the upload method and appropriate settings based on Paperclip. For S3 see:
|
||||
# http://rdoc.info/gems/paperclip/2.3.8/Paperclip/Storage/S3, and for
|
||||
# http://rdoc.info/gems/paperclip/2.3.8/Paperclip/Storage/S3, and for
|
||||
# filesystem see: http://rdoc.info/gems/paperclip/2.3.8/Paperclip/Storage/Filesystem
|
||||
config.upload_file_options = {
|
||||
:storage => 's3',
|
||||
:s3_credentials => {
|
||||
:bucket => ENV['S3_BUCKET'],
|
||||
:access_key_id => ENV['S3_KEY'],
|
||||
:secret_access_key => ENV['S3_SECRET']
|
||||
:bucket => Spree::Config[:s3_bucket],
|
||||
:access_key_id => Spree::Config[:s3_access_key],
|
||||
:secret_access_key => Spree::Config[:s3_secret]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,11 +47,11 @@ ComfortableMexicanSofa.configure do |config|
|
||||
# request (if necessary). Please note that database entries are destroyed if there's
|
||||
# no corresponding file. Fixtures are disabled by default.
|
||||
# config.enable_fixtures = false
|
||||
|
||||
|
||||
# Path where fixtures can be located.
|
||||
# config.fixtures_path = File.expand_path('db/cms_fixtures', Rails.root)
|
||||
|
||||
# Importing fixtures into Database
|
||||
|
||||
# Importing fixtures into Database
|
||||
# To load fixtures into the database just run this rake task:
|
||||
# local: $ rake comfortable_mexican_sofa:fixtures:import FROM=example.local TO=localhost
|
||||
# Heroku: $ heroku run rake comfortable_mexican_sofa:fixtures:import FROM=example.local TO=yourapp.herokuapp.com
|
||||
@@ -62,48 +62,48 @@ ComfortableMexicanSofa.configure do |config|
|
||||
# local: $ rake comfortable_mexican_sofa:fixtures:export FROM=localhost TO=example.local
|
||||
# Heroku: $ heroku run rake comfortable_mexican_sofa:fixtures:export FROM=yourapp.herokuapp.com TO=example.local
|
||||
# This will create example.local folder and dump all content from example.com Site.
|
||||
|
||||
|
||||
# Content for Layouts, Pages and Snippets has a revision history. You can revert
|
||||
# a previous version using this system. You can control how many revisions per
|
||||
# object you want to keep. Set it to 0 if you wish to turn this feature off.
|
||||
# config.revisions_limit = 25
|
||||
|
||||
|
||||
# Locale definitions. If you want to define your own locale merge
|
||||
# {:locale => 'Locale Title'} with this.
|
||||
# config.locales = {:en => 'English', :es => 'Español'}
|
||||
|
||||
|
||||
# Admin interface will respect the locale of the site being managed. However you can
|
||||
# force it to English by setting this to `:en`
|
||||
# config.admin_locale = nil
|
||||
|
||||
|
||||
# If you want to keep your CMS tables in a location other than the default database
|
||||
# add a database_config. For example, setting it to 'cms' will look for a cms_#{Rails.env}
|
||||
# definition in your database.yml file
|
||||
# config.database_config = nil
|
||||
|
||||
|
||||
# A class that is included as a sweeper to admin base controller if it's set
|
||||
# config.admin_cache_sweeper = nil
|
||||
|
||||
|
||||
# By default you cannot have irb code inside your layouts/pages/snippets.
|
||||
# Generally this is to prevent putting something like this:
|
||||
# <% User.delete_all %> but if you really want to allow it...
|
||||
# config.allow_irb = false
|
||||
|
||||
|
||||
# Whitelist of all helper methods that can be used via {{cms:helper}} tag. By default
|
||||
# all helpers are allowed except `eval`, `send`, `call` and few others. Empty array
|
||||
# will prevent rendering of all helpers.
|
||||
# config.allowed_helpers = nil
|
||||
|
||||
|
||||
# Whitelist of partials paths that can be used via {{cms:partial}} tag. All partials
|
||||
# are accessible by default. Empty array will prevent rendering of all partials.
|
||||
# config.allowed_partials = nil
|
||||
|
||||
# Site aliases, if you want to have aliases for your site. Good for harmonizing
|
||||
|
||||
# Site aliases, if you want to have aliases for your site. Good for harmonizing
|
||||
# production env with dev/testing envs.
|
||||
# e.g. config.site_aliases = {'host.com' => 'host.inv', 'host_a.com' => ['host.lvh.me', 'host.dev']}
|
||||
# Default is nil (not used)
|
||||
# config.hostname_aliases = nil
|
||||
|
||||
|
||||
end
|
||||
|
||||
module CmsSpreeAuth
|
||||
|
||||
6
config/initializers/db2fog.rb
Normal file
6
config/initializers/db2fog.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
DB2Fog.config = {
|
||||
:aws_access_key_id => Spree::Config[:s3_access_key],
|
||||
:aws_secret_access_key => Spree::Config[:s3_secret],
|
||||
:directory => Spree::Config[:s3_bucket],
|
||||
:provider => 'AWS'
|
||||
}
|
||||
@@ -26,3 +26,17 @@ Spree.config do |config|
|
||||
# Auto-capture payments. Without this option, payments must be manually captured in the paypal interface.
|
||||
config.auto_capture = true
|
||||
end
|
||||
|
||||
|
||||
# Add calculators category for enterprise fees
|
||||
module Spree
|
||||
module Core
|
||||
class Environment
|
||||
class Calculators
|
||||
include EnvironmentExtension
|
||||
|
||||
attr_accessor :enterprise_fees
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
255
config/newrelic.yml
Normal file
255
config/newrelic.yml
Normal file
@@ -0,0 +1,255 @@
|
||||
# Here are the settings that are common to all environments
|
||||
common: &default_settings
|
||||
# ============================== LICENSE KEY ===============================
|
||||
|
||||
# You must specify the license key associated with your New Relic
|
||||
# account. This key binds your Agent's data to your account in the
|
||||
# New Relic service.
|
||||
license_key: '<%= ENV["NEW_RELIC_LICENSE_KEY"] %>'
|
||||
|
||||
# Agent Enabled (Rails Only)
|
||||
# Use this setting to force the agent to run or not run.
|
||||
# Default is 'auto' which means the agent will install and run only
|
||||
# if a valid dispatcher such as Mongrel is running. This prevents
|
||||
# it from running with Rake or the console. Set to false to
|
||||
# completely turn the agent off regardless of the other settings.
|
||||
# Valid values are true, false and auto.
|
||||
#
|
||||
# agent_enabled: auto
|
||||
|
||||
# Application Name Set this to be the name of your application as
|
||||
# you'd like it show up in New Relic. The service will then auto-map
|
||||
# instances of your application into an "application" on your
|
||||
# dashboard page. If you want to map this instance into multiple
|
||||
# apps, like "AJAX Requests" and "All UI" then specify a semicolon
|
||||
# separated list of up to three distinct names, or a yaml list.
|
||||
# Defaults to the capitalized RAILS_ENV or RACK_ENV (i.e.,
|
||||
# Production, Staging, etc)
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# app_name:
|
||||
# - Ajax Service
|
||||
# - All Services
|
||||
#
|
||||
app_name: <%= ENV["NEW_RELIC_APP_NAME"] %>
|
||||
|
||||
# When "true", the agent collects performance data about your
|
||||
# application and reports this data to the New Relic service at
|
||||
# newrelic.com. This global switch is normally overridden for each
|
||||
# environment below. (formerly called 'enabled')
|
||||
monitor_mode: true
|
||||
|
||||
# Developer mode should be off in every environment but
|
||||
# development as it has very high overhead in memory.
|
||||
developer_mode: false
|
||||
|
||||
# The newrelic agent generates its own log file to keep its logging
|
||||
# information separate from that of your application. Specify its
|
||||
# log level here.
|
||||
log_level: info
|
||||
|
||||
# Optionally set the path to the log file This is expanded from the
|
||||
# root directory (may be relative or absolute, e.g. 'log/' or
|
||||
# '/var/log/') The agent will attempt to create this directory if it
|
||||
# does not exist.
|
||||
# log_file_path: 'log'
|
||||
|
||||
# Optionally set the name of the log file, defaults to 'newrelic_agent.log'
|
||||
# log_file_name: 'newrelic_agent.log'
|
||||
|
||||
# The newrelic agent communicates with the service via http by
|
||||
# default. If you want to communicate via https to increase
|
||||
# security, then turn on SSL by setting this value to true. Note,
|
||||
# this will result in increased CPU overhead to perform the
|
||||
# encryption involved in SSL communication, but this work is done
|
||||
# asynchronously to the threads that process your application code,
|
||||
# so it should not impact response times.
|
||||
ssl: false
|
||||
|
||||
# EXPERIMENTAL: enable verification of the SSL certificate sent by
|
||||
# the server. This setting has no effect unless SSL is enabled
|
||||
# above. This may block your application. Only enable it if the data
|
||||
# you send us needs end-to-end verified certificates.
|
||||
#
|
||||
# This means we cannot cache the DNS lookup, so each request to the
|
||||
# service will perform a lookup. It also means that we cannot
|
||||
# use a non-blocking lookup, so in a worst case, if you have DNS
|
||||
# problems, your app may block indefinitely.
|
||||
# verify_certificate: true
|
||||
|
||||
# Set your application's Apdex threshold value with the 'apdex_t'
|
||||
# setting, in seconds. The apdex_t value determines the buckets used
|
||||
# to compute your overall Apdex score.
|
||||
# Requests that take less than apdex_t seconds to process will be
|
||||
# classified as Satisfying transactions; more than apdex_t seconds
|
||||
# as Tolerating transactions; and more than four times the apdex_t
|
||||
# value as Frustrating transactions.
|
||||
# For more about the Apdex standard, see
|
||||
# http://newrelic.com/docs/general/apdex
|
||||
|
||||
apdex_t: 0.5
|
||||
|
||||
#============================== Browser Monitoring ===============================
|
||||
# New Relic Real User Monitoring gives you insight into the performance real users are
|
||||
# experiencing with your website. This is accomplished by measuring the time it takes for
|
||||
# your users' browsers to download and render your web pages by injecting a small amount
|
||||
# of JavaScript code into the header and footer of each page.
|
||||
browser_monitoring:
|
||||
# By default the agent automatically injects the monitoring JavaScript
|
||||
# into web pages. Set this attribute to false to turn off this behavior.
|
||||
auto_instrument: true
|
||||
|
||||
# Proxy settings for connecting to the service.
|
||||
#
|
||||
# If a proxy is used, the host setting is required. Other settings
|
||||
# are optional. Default port is 8080.
|
||||
#
|
||||
# proxy_host: hostname
|
||||
# proxy_port: 8080
|
||||
# proxy_user:
|
||||
# proxy_pass:
|
||||
|
||||
|
||||
# Tells transaction tracer and error collector (when enabled)
|
||||
# whether or not to capture HTTP params. When true, frameworks can
|
||||
# exclude HTTP parameters from being captured.
|
||||
# Rails: the RoR filter_parameter_logging excludes parameters
|
||||
# Java: create a config setting called "ignored_params" and set it to
|
||||
# a comma separated list of HTTP parameter names.
|
||||
# ex: ignored_params: credit_card, ssn, password
|
||||
capture_params: false
|
||||
|
||||
|
||||
# Transaction tracer captures deep information about slow
|
||||
# transactions and sends this to the service once a
|
||||
# minute. Included in the transaction is the exact call sequence of
|
||||
# the transactions including any SQL statements issued.
|
||||
transaction_tracer:
|
||||
|
||||
# Transaction tracer is enabled by default. Set this to false to
|
||||
# turn it off. This feature is only available at the Professional
|
||||
# and above product levels.
|
||||
enabled: true
|
||||
|
||||
# Threshold in seconds for when to collect a transaction
|
||||
# trace. When the response time of a controller action exceeds
|
||||
# this threshold, a transaction trace will be recorded and sent to
|
||||
# the service. Valid values are any float value, or (default)
|
||||
# "apdex_f", which will use the threshold for an dissatisfying
|
||||
# Apdex controller action - four times the Apdex T value.
|
||||
transaction_threshold: apdex_f
|
||||
|
||||
# When transaction tracer is on, SQL statements can optionally be
|
||||
# recorded. The recorder has three modes, "off" which sends no
|
||||
# SQL, "raw" which sends the SQL statement in its original form,
|
||||
# and "obfuscated", which strips out numeric and string literals
|
||||
record_sql: obfuscated
|
||||
|
||||
# Threshold in seconds for when to collect stack trace for a SQL
|
||||
# call. In other words, when SQL statements exceed this threshold,
|
||||
# then capture and send the current stack trace. This is
|
||||
# helpful for pinpointing where long SQL calls originate from
|
||||
stack_trace_threshold: 0.500
|
||||
|
||||
# Determines whether the agent will capture query plans for slow
|
||||
# SQL queries. Only supported in mysql and postgres. Should be
|
||||
# set to false when using other adapters.
|
||||
# explain_enabled: true
|
||||
|
||||
# Threshold for query execution time below which query plans will not
|
||||
# not be captured. Relevant only when `explain_enabled` is true.
|
||||
# explain_threshold: 0.5
|
||||
|
||||
# Error collector captures information about uncaught exceptions and
|
||||
# sends them to the service for viewing
|
||||
error_collector:
|
||||
|
||||
# Error collector is enabled by default. Set this to false to turn
|
||||
# it off. This feature is only available at the Professional and above
|
||||
# product levels
|
||||
enabled: true
|
||||
|
||||
# Rails Only - tells error collector whether or not to capture a
|
||||
# source snippet around the place of the error when errors are View
|
||||
# related.
|
||||
capture_source: true
|
||||
|
||||
# To stop specific errors from reporting to New Relic, set this property
|
||||
# to comma separated values. Default is to ignore routing errors
|
||||
# which are how 404's get triggered.
|
||||
#
|
||||
ignore_errors: ActionController::RoutingError
|
||||
|
||||
# (Advanced) Uncomment this to ensure the cpu and memory samplers
|
||||
# won't run. Useful when you are using the agent to monitor an
|
||||
# external resource
|
||||
# disable_samplers: true
|
||||
|
||||
# If you aren't interested in visibility in these areas, you can
|
||||
# disable the instrumentation to reduce overhead.
|
||||
#
|
||||
# disable_view_instrumentation: true
|
||||
# disable_activerecord_instrumentation: true
|
||||
# disable_memcache_instrumentation: true
|
||||
# disable_dj: true
|
||||
|
||||
# If you're interested in capturing memcache keys as though they
|
||||
# were SQL uncomment this flag. Note that this does increase
|
||||
# overhead slightly on every memcached call, and can have security
|
||||
# implications if your memcached keys are sensitive
|
||||
# capture_memcache_keys: true
|
||||
|
||||
# Certain types of instrumentation such as GC stats will not work if
|
||||
# you are running multi-threaded. Please let us know.
|
||||
# multi_threaded = false
|
||||
|
||||
# Application Environments
|
||||
# ------------------------------------------
|
||||
# Environment specific settings are in this section.
|
||||
# For Rails applications, RAILS_ENV is used to determine the environment
|
||||
# For Java applications, pass -Dnewrelic.environment <environment> to set
|
||||
# the environment
|
||||
|
||||
# NOTE if your application has other named environments, you should
|
||||
# provide newrelic configuration settings for these environments here.
|
||||
|
||||
development:
|
||||
<<: *default_settings
|
||||
# Turn off communication to New Relic service in development mode (also
|
||||
# 'enabled').
|
||||
# NOTE: for initial evaluation purposes, you may want to temporarily
|
||||
# turn the agent on in development mode.
|
||||
monitor_mode: false
|
||||
|
||||
# Rails Only - when running in Developer Mode, the New Relic Agent will
|
||||
# present performance information on the last 100 transactions you have
|
||||
# executed since starting the mongrel.
|
||||
# NOTE: There is substantial overhead when running in developer mode.
|
||||
# Do not use for production or load testing.
|
||||
developer_mode: true
|
||||
|
||||
# Enable textmate links
|
||||
# textmate: true
|
||||
|
||||
test:
|
||||
<<: *default_settings
|
||||
# It almost never makes sense to turn on the agent when running
|
||||
# unit, functional or integration tests or the like.
|
||||
monitor_mode: false
|
||||
|
||||
# Turn on the agent in production for 24x7 monitoring. NewRelic
|
||||
# testing shows an average performance impact of < 5 ms per
|
||||
# transaction, you you can leave this on all the time without
|
||||
# incurring any user-visible performance degradation.
|
||||
production:
|
||||
<<: *default_settings
|
||||
monitor_mode: true
|
||||
|
||||
# Many applications have a staging environment which behaves
|
||||
# identically to production. Support for that environment is provided
|
||||
# here. By default, the staging environment has the agent turned on.
|
||||
staging:
|
||||
<<: *default_settings
|
||||
monitor_mode: true
|
||||
app_name: <%= ENV["NEW_RELIC_APP_NAME"] %> (Staging)
|
||||
@@ -4,14 +4,20 @@ Openfoodweb::Application.routes.draw do
|
||||
resources :enterprises do
|
||||
get :suppliers, :on => :collection
|
||||
get :distributors, :on => :collection
|
||||
get :select_distributor, :on => :member
|
||||
get :deselect_distributor, :on => :collection
|
||||
end
|
||||
|
||||
namespace :admin do
|
||||
resources :order_cycles do
|
||||
post :bulk_update, :on => :collection, :as => :bulk_update
|
||||
end
|
||||
|
||||
resources :enterprises do
|
||||
post :bulk_update, :on => :collection, :as => :bulk_update
|
||||
end
|
||||
|
||||
resources :enterprise_fees do
|
||||
post :bulk_update, :on => :collection, :as => :bulk_update
|
||||
end
|
||||
end
|
||||
|
||||
# Mount Spree's routes
|
||||
@@ -25,4 +31,9 @@ Spree::Core::Engine.routes.prepend do
|
||||
match '/admin/reports/bulk_coop' => 'admin/reports#bulk_coop', :as => "bulk_coop_admin_reports", :via => [:get, :post]
|
||||
match '/admin/reports/payments' => 'admin/reports#payments', :as => "payments_admin_reports", :via => [:get, :post]
|
||||
match '/admin/reports/order_cycles' => 'admin/reports#order_cycles', :as => "order_cycles_admin_reports", :via => [:get, :post]
|
||||
|
||||
resources :orders do
|
||||
get :select_distributor, :on => :member
|
||||
get :deselect_distributor, :on => :collection
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,2 +1,27 @@
|
||||
preload_app true # https://newrelic.com/docs/ruby/no-data-with-unicorn
|
||||
worker_processes 4 # amount of unicorn workers to spin up
|
||||
timeout 30 # restarts workers that hang for 30 seconds
|
||||
timeout 30 # restarts workers that hang for 30 seconds
|
||||
|
||||
|
||||
# https://devcenter.heroku.com/articles/forked-pg-connections
|
||||
before_fork do |server, worker|
|
||||
|
||||
Signal.trap 'TERM' do
|
||||
puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
|
||||
Process.kill 'QUIT', Process.pid
|
||||
end
|
||||
|
||||
defined?(ActiveRecord::Base) and
|
||||
ActiveRecord::Base.connection.disconnect!
|
||||
end
|
||||
|
||||
after_fork do |server, worker|
|
||||
|
||||
Signal.trap 'TERM' do
|
||||
puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to sent QUIT'
|
||||
end
|
||||
|
||||
defined?(ActiveRecord::Base) and
|
||||
ActiveRecord::Base.establish_connection
|
||||
|
||||
end
|
||||
|
||||
11
db/migrate/20121115010717_create_enterprise_fees.rb
Normal file
11
db/migrate/20121115010717_create_enterprise_fees.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
class CreateEnterpriseFees < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :enterprise_fees do |t|
|
||||
t.references :enterprise
|
||||
t.string :fee_type
|
||||
t.string :name
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
||||
35
db/migrate/20121125232613_create_order_cycles.rb
Normal file
35
db/migrate/20121125232613_create_order_cycles.rb
Normal file
@@ -0,0 +1,35 @@
|
||||
class CreateOrderCycles < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :order_cycles do |t|
|
||||
t.string :name
|
||||
t.datetime :orders_open_at
|
||||
t.datetime :orders_close_at
|
||||
t.references :coordinator
|
||||
t.references :coordinator_admin_fee
|
||||
t.references :coordinator_sales_fee
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
create_table :exchanges do |t|
|
||||
t.references :order_cycle
|
||||
t.references :sender
|
||||
t.references :receiver
|
||||
t.references :payment_enterprise
|
||||
t.datetime :pickup_time
|
||||
t.string :pickup_instructions
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
create_table :exchange_variants do |t|
|
||||
t.references :exchange
|
||||
t.references :variant
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
create_table :exchange_fees do |t|
|
||||
t.references :exchange
|
||||
t.references :enterprise_fee
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
class ChangeExchangePickupTimeToString < ActiveRecord::Migration
|
||||
def up
|
||||
change_column :exchanges, :pickup_time, :string
|
||||
end
|
||||
|
||||
def down
|
||||
change_column :exchanges, :pickup_time, :datetime
|
||||
end
|
||||
end
|
||||
43
db/sanitize_data.rb
Normal file
43
db/sanitize_data.rb
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
def update_address(address, user)
|
||||
unless address.nil?
|
||||
address.firstname = user[:first_name]
|
||||
address.lastname = user[:last_name]
|
||||
address.phone = user[:phone]
|
||||
address.save!
|
||||
end
|
||||
end
|
||||
|
||||
def sanitize_data
|
||||
canned_users = [ { :first_name => "Bob", :last_name => "jones", :email => "bob@jones.com", :phone => "0123456789" },
|
||||
{ :first_name => "cindy", :last_name => "rest", :email => "cindy@gmail.com", :phone => "0123456789" },
|
||||
{ :first_name => "Pete", :last_name => "smith", :email => "pete@gmail.com", :phone => "0123456789" },
|
||||
{ :first_name => "Tony", :last_name => "ballantyne", :email => "tony@gmail.com", :phone => "0123456789" },
|
||||
{ :first_name => "Ben", :last_name => "raven", :email => "ben@gmail.com", :phone => "0123456789" },
|
||||
{ :first_name => "Robyn", :last_name => "monster", :email => "robyn@gmail.com", :phone => "0123456789" },
|
||||
{ :first_name => "Nako", :last_name => "tolkein", :email => "nako@gmail.com", :phone => "0123456789" },
|
||||
{ :first_name => "Helen", :last_name => "mitcham", :email => "helen@gmail.com", :phone => "0123456789" },
|
||||
{ :first_name => "Emma", :last_name => "low", :email => "emma@gmail.com", :phone => "0123456789" },
|
||||
{ :first_name => "Mandy", :last_name => "Trust", :email => "Mandy@trust.com", :phone => "0123456789" } ]
|
||||
|
||||
Spree::Order.all.each_with_index do |order, index|
|
||||
canned_user = canned_users[index%canned_users.size]
|
||||
puts "updating order #{order.id} with #{canned_user[:first_name]}"
|
||||
|
||||
order.email = canned_user[:email]
|
||||
|
||||
update_address(order.bill_address, canned_user)
|
||||
update_address(order.ship_address, canned_user)
|
||||
order.save!
|
||||
end
|
||||
|
||||
Spree::User.all.each_with_index do |user, index|
|
||||
unless user.email == "admin@openfoodweb.org"
|
||||
canned_user = canned_users[index%canned_users.size]
|
||||
puts "updating user #{user.id} with #{canned_user[:first_name]}"
|
||||
|
||||
user.email = "#{canned_user[:email]}#{index}"
|
||||
user.save!
|
||||
end
|
||||
end
|
||||
end
|
||||
194
db/schema.rb
194
db/schema.rb
@@ -11,7 +11,7 @@
|
||||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
ActiveRecord::Schema.define(:version => 20130118031610) do
|
||||
|
||||
create_table "cms_blocks", :force => true do |t|
|
||||
t.integer "page_id", :null => false
|
||||
@@ -130,6 +130,14 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
add_index "cms_snippets", ["site_id", "identifier"], :name => "index_cms_snippets_on_site_id_and_identifier", :unique => true
|
||||
add_index "cms_snippets", ["site_id", "position"], :name => "index_cms_snippets_on_site_id_and_position"
|
||||
|
||||
create_table "enterprise_fees", :force => true do |t|
|
||||
t.integer "enterprise_id"
|
||||
t.string "fee_type"
|
||||
t.string "name"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
create_table "enterprises", :force => true do |t|
|
||||
t.string "name"
|
||||
t.string "description"
|
||||
@@ -150,6 +158,42 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
create_table "exchange_fees", :force => true do |t|
|
||||
t.integer "exchange_id"
|
||||
t.integer "enterprise_fee_id"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
create_table "exchange_variants", :force => true do |t|
|
||||
t.integer "exchange_id"
|
||||
t.integer "variant_id"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
create_table "exchanges", :force => true do |t|
|
||||
t.integer "order_cycle_id"
|
||||
t.integer "sender_id"
|
||||
t.integer "receiver_id"
|
||||
t.integer "payment_enterprise_id"
|
||||
t.string "pickup_time"
|
||||
t.string "pickup_instructions"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
create_table "order_cycles", :force => true do |t|
|
||||
t.string "name"
|
||||
t.datetime "orders_open_at"
|
||||
t.datetime "orders_close_at"
|
||||
t.integer "coordinator_id"
|
||||
t.integer "coordinator_admin_fee_id"
|
||||
t.integer "coordinator_sales_fee_id"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
create_table "product_distributions", :force => true do |t|
|
||||
t.integer "product_id"
|
||||
t.integer "distributor_id"
|
||||
@@ -186,8 +230,8 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.string "alternative_phone"
|
||||
t.integer "state_id"
|
||||
t.integer "country_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.string "company"
|
||||
end
|
||||
|
||||
@@ -196,12 +240,12 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
|
||||
create_table "spree_adjustments", :force => true do |t|
|
||||
t.integer "source_id"
|
||||
t.decimal "amount", :precision => 8, :scale => 2, :default => 0.0
|
||||
t.decimal "amount", :precision => 8, :scale => 2
|
||||
t.string "label"
|
||||
t.string "source_type"
|
||||
t.integer "adjustable_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.boolean "mandatory"
|
||||
t.boolean "locked"
|
||||
t.integer "originator_id"
|
||||
@@ -233,15 +277,15 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.string "type"
|
||||
t.integer "calculable_id", :null => false
|
||||
t.string "calculable_type", :null => false
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
create_table "spree_configurations", :force => true do |t|
|
||||
t.string "name"
|
||||
t.string "type", :limit => 50
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
add_index "spree_configurations", ["name", "type"], :name => "index_configurations_on_name_and_type"
|
||||
@@ -279,8 +323,8 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.string "environment", :default => "development"
|
||||
t.string "server", :default => "test"
|
||||
t.boolean "test_mode", :default => true
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
create_table "spree_inventory_units", :force => true do |t|
|
||||
@@ -288,8 +332,8 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.string "state"
|
||||
t.integer "variant_id"
|
||||
t.integer "order_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.integer "shipment_id"
|
||||
t.integer "return_authorization_id"
|
||||
end
|
||||
@@ -303,8 +347,8 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.integer "variant_id"
|
||||
t.integer "quantity", :null => false
|
||||
t.decimal "price", :precision => 8, :scale => 2, :null => false
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.integer "max_quantity"
|
||||
t.integer "shipping_method_id"
|
||||
end
|
||||
@@ -316,22 +360,22 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.integer "source_id"
|
||||
t.string "source_type"
|
||||
t.text "details"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
create_table "spree_mail_methods", :force => true do |t|
|
||||
t.string "environment"
|
||||
t.boolean "active", :default => true
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
create_table "spree_option_types", :force => true do |t|
|
||||
t.string "name", :limit => 100
|
||||
t.string "presentation", :limit => 100
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.integer "position", :default => 0, :null => false
|
||||
end
|
||||
|
||||
@@ -345,8 +389,8 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.string "name"
|
||||
t.string "presentation"
|
||||
t.integer "option_type_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
create_table "spree_option_values_variants", :id => false, :force => true do |t|
|
||||
@@ -365,8 +409,8 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.decimal "adjustment_total", :precision => 8, :scale => 2, :default => 0.0, :null => false
|
||||
t.decimal "credit_total", :precision => 8, :scale => 2, :default => 0.0, :null => false
|
||||
t.integer "user_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.datetime "completed_at"
|
||||
t.integer "bill_address_id"
|
||||
t.integer "ship_address_id"
|
||||
@@ -387,8 +431,8 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.text "description"
|
||||
t.boolean "active", :default => true
|
||||
t.string "environment", :default => "development"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.datetime "deleted_at"
|
||||
t.string "display_on"
|
||||
end
|
||||
@@ -396,8 +440,8 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
create_table "spree_payments", :force => true do |t|
|
||||
t.decimal "amount", :precision => 8, :scale => 2, :default => 0.0, :null => false
|
||||
t.integer "order_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.integer "source_id"
|
||||
t.string "source_type"
|
||||
t.integer "payment_method_id"
|
||||
@@ -426,8 +470,8 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.integer "owner_id"
|
||||
t.string "owner_type"
|
||||
t.text "value"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.string "key"
|
||||
t.string "value_type"
|
||||
end
|
||||
@@ -452,16 +496,16 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.integer "position"
|
||||
t.integer "product_id"
|
||||
t.integer "option_type_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
create_table "spree_product_properties", :force => true do |t|
|
||||
t.string "value"
|
||||
t.integer "product_id"
|
||||
t.integer "property_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
add_index "spree_product_properties", ["product_id"], :name => "index_product_properties_on_product_id"
|
||||
@@ -485,8 +529,8 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.string "meta_keywords"
|
||||
t.integer "tax_category_id"
|
||||
t.integer "shipping_category_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.integer "count_on_hand", :default => 0, :null => false
|
||||
t.integer "supplier_id"
|
||||
t.boolean "group_buy"
|
||||
@@ -531,8 +575,8 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.integer "user_id"
|
||||
t.integer "product_group_id"
|
||||
t.string "type"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
add_index "spree_promotion_rules", ["product_group_id"], :name => "index_promotion_rules_on_product_group_id"
|
||||
@@ -549,8 +593,8 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
create_table "spree_properties", :force => true do |t|
|
||||
t.string "name"
|
||||
t.string "presentation", :null => false
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
create_table "spree_properties_prototypes", :id => false, :force => true do |t|
|
||||
@@ -560,8 +604,8 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
|
||||
create_table "spree_prototypes", :force => true do |t|
|
||||
t.string "name"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
create_table "spree_return_authorizations", :force => true do |t|
|
||||
@@ -570,8 +614,8 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.decimal "amount", :precision => 8, :scale => 2, :default => 0.0, :null => false
|
||||
t.integer "order_id"
|
||||
t.text "reason"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
create_table "spree_roles", :force => true do |t|
|
||||
@@ -594,8 +638,8 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.integer "order_id"
|
||||
t.integer "shipping_method_id"
|
||||
t.integer "address_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.string "state"
|
||||
end
|
||||
|
||||
@@ -603,15 +647,15 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
|
||||
create_table "spree_shipping_categories", :force => true do |t|
|
||||
t.string "name"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
create_table "spree_shipping_methods", :force => true do |t|
|
||||
t.string "name"
|
||||
t.integer "zone_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.string "display_on"
|
||||
t.integer "shipping_category_id"
|
||||
t.boolean "match_none"
|
||||
@@ -627,8 +671,8 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.integer "transaction_id"
|
||||
t.integer "customer_id"
|
||||
t.string "payment_type"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
create_table "spree_state_changes", :force => true do |t|
|
||||
@@ -636,8 +680,8 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.string "previous_state"
|
||||
t.integer "stateful_id"
|
||||
t.integer "user_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.string "stateful_type"
|
||||
t.string "next_state"
|
||||
end
|
||||
@@ -651,8 +695,8 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
create_table "spree_tax_categories", :force => true do |t|
|
||||
t.string "name"
|
||||
t.string "description"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.boolean "is_default", :default => false
|
||||
t.datetime "deleted_at"
|
||||
end
|
||||
@@ -661,15 +705,15 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.decimal "amount", :precision => 8, :scale => 5
|
||||
t.integer "zone_id"
|
||||
t.integer "tax_category_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.boolean "included_in_price", :default => false
|
||||
end
|
||||
|
||||
create_table "spree_taxonomies", :force => true do |t|
|
||||
t.string "name", :null => false
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
create_table "spree_taxons", :force => true do |t|
|
||||
@@ -678,8 +722,8 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.string "name", :null => false
|
||||
t.string "permalink"
|
||||
t.integer "taxonomy_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.integer "lft"
|
||||
t.integer "rgt"
|
||||
t.string "icon_file_name"
|
||||
@@ -697,8 +741,8 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.integer "permissable_id"
|
||||
t.string "permissable_type"
|
||||
t.string "token"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
add_index "spree_tokenized_permissions", ["permissable_id", "permissable_type"], :name => "index_tokenized_name_and_type"
|
||||
@@ -707,8 +751,8 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.string "environment"
|
||||
t.string "analytics_id"
|
||||
t.boolean "active", :default => true
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
create_table "spree_users", :force => true do |t|
|
||||
@@ -729,8 +773,8 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.string "login"
|
||||
t.integer "ship_address_id"
|
||||
t.integer "bill_address_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.string "authentication_token"
|
||||
t.string "unlock_token"
|
||||
t.datetime "locked_at"
|
||||
@@ -753,7 +797,7 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.boolean "is_master", :default => false
|
||||
t.integer "product_id"
|
||||
t.integer "count_on_hand", :default => 0, :null => false
|
||||
t.decimal "cost_price", :precision => 8, :scale => 2, :default => 0.0
|
||||
t.decimal "cost_price", :precision => 8, :scale => 2
|
||||
t.integer "position"
|
||||
end
|
||||
|
||||
@@ -763,15 +807,15 @@ ActiveRecord::Schema.define(:version => 20121031222403) do
|
||||
t.integer "zoneable_id"
|
||||
t.string "zoneable_type"
|
||||
t.integer "zone_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
create_table "spree_zones", :force => true do |t|
|
||||
t.string "name"
|
||||
t.string "description"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.boolean "default_tax", :default => false
|
||||
t.integer "zone_members_count", :default => 0
|
||||
end
|
||||
|
||||
22
lib/open_food_web/distributor_change_validator.rb
Normal file
22
lib/open_food_web/distributor_change_validator.rb
Normal file
@@ -0,0 +1,22 @@
|
||||
class DistributorChangeValidator
|
||||
|
||||
def initialize order
|
||||
@order = order
|
||||
end
|
||||
|
||||
def can_change_distributor?
|
||||
# Distributor may not be changed once an item has been added to the cart/order
|
||||
@order.line_items.empty?
|
||||
end
|
||||
|
||||
def can_change_to_distributor? distributor
|
||||
# Distributor may not be changed once an item has been added to the cart/order, unless all items are available from the specified distributor
|
||||
@order.line_items.empty? || (available_distributors(Enterprise.all) || []).include?(distributor)
|
||||
end
|
||||
|
||||
def available_distributors enterprises
|
||||
enterprises.select do |e|
|
||||
(@order.line_item_variants - e.available_variants).empty?
|
||||
end
|
||||
end
|
||||
end
|
||||
68
lib/open_food_web/order_cycle_form_applicator.rb
Normal file
68
lib/open_food_web/order_cycle_form_applicator.rb
Normal file
@@ -0,0 +1,68 @@
|
||||
module OpenFoodWeb
|
||||
class OrderCycleFormApplicator
|
||||
def initialize(order_cycle)
|
||||
@order_cycle = order_cycle
|
||||
end
|
||||
|
||||
def go!
|
||||
@touched_exchanges = []
|
||||
|
||||
@order_cycle.incoming_exchanges.each do |exchange|
|
||||
variant_ids = exchange_variant_ids(exchange)
|
||||
|
||||
if exchange_exists?(exchange[:enterprise_id], @order_cycle.coordinator_id)
|
||||
update_exchange(exchange[:enterprise_id], @order_cycle.coordinator_id, {variant_ids: variant_ids})
|
||||
else
|
||||
add_exchange(exchange[:enterprise_id], @order_cycle.coordinator_id, {variant_ids: variant_ids})
|
||||
end
|
||||
end
|
||||
|
||||
@order_cycle.outgoing_exchanges.each do |exchange|
|
||||
variant_ids = exchange_variant_ids(exchange)
|
||||
|
||||
if exchange_exists?(@order_cycle.coordinator_id, exchange[:enterprise_id])
|
||||
update_exchange(@order_cycle.coordinator_id, exchange[:enterprise_id], {variant_ids: variant_ids, pickup_time: exchange[:pickup_time], pickup_instructions: exchange[:pickup_instructions]})
|
||||
else
|
||||
add_exchange(@order_cycle.coordinator_id, exchange[:enterprise_id], {variant_ids: variant_ids, pickup_time: exchange[:pickup_time], pickup_instructions: exchange[:pickup_instructions]})
|
||||
end
|
||||
end
|
||||
|
||||
destroy_untouched_exchanges
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
attr_accessor :touched_exchanges
|
||||
|
||||
def exchange_exists?(sender_id, receiver_id)
|
||||
@order_cycle.exchanges.where(:sender_id => sender_id, :receiver_id => receiver_id).present?
|
||||
end
|
||||
|
||||
def add_exchange(sender_id, receiver_id, attrs={})
|
||||
attrs = attrs.reverse_merge(:sender_id => sender_id, :receiver_id => receiver_id)
|
||||
exchange = @order_cycle.exchanges.create! attrs
|
||||
@touched_exchanges << exchange
|
||||
end
|
||||
|
||||
def update_exchange(sender_id, receiver_id, attrs={})
|
||||
exchange = @order_cycle.exchanges.where(:sender_id => sender_id, :receiver_id => receiver_id).first
|
||||
exchange.update_attributes!(attrs)
|
||||
|
||||
@touched_exchanges << exchange
|
||||
end
|
||||
|
||||
def destroy_untouched_exchanges
|
||||
untouched_exchanges.each { |exchange| exchange.destroy }
|
||||
end
|
||||
|
||||
def untouched_exchanges
|
||||
@order_cycle.exchanges - @touched_exchanges
|
||||
end
|
||||
|
||||
|
||||
def exchange_variant_ids(exchange)
|
||||
exchange[:variants].select { |k, v| v }.keys.map { |k| k.to_i }
|
||||
end
|
||||
end
|
||||
end
|
||||
11
script-angular/e2e-test.bat
Normal file
11
script-angular/e2e-test.bat
Normal file
@@ -0,0 +1,11 @@
|
||||
@echo off
|
||||
|
||||
REM Windows script for running e2e tests
|
||||
REM You have to run server and capture some browser first
|
||||
REM
|
||||
REM Requirements:
|
||||
REM - NodeJS (http://nodejs.org/)
|
||||
REM - Testacular (npm install -g testacular)
|
||||
|
||||
set BASE_DIR=%~dp0
|
||||
testacular start "%BASE_DIR%\..\config\testacular-e2e.conf.js" %*
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user