mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-19 19:46:51 +00:00
Compare commits
105 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2535e3965b | ||
|
|
568d948cbe | ||
|
|
6d9257d941 | ||
|
|
7430fc9bdd | ||
|
|
473b4e9adc | ||
|
|
2aa450b072 | ||
|
|
3886ec39f7 | ||
|
|
afb8faa96f | ||
|
|
27b7d59f46 | ||
|
|
bc408d8b6e | ||
|
|
a8758f1271 | ||
|
|
2bce9df25a | ||
|
|
479c49752c | ||
|
|
62d6067c1a | ||
|
|
a1b5102476 | ||
|
|
593f3887c8 | ||
|
|
757456dd57 | ||
|
|
3894ce946d | ||
|
|
f1f9b5b2e8 | ||
|
|
5402590d5f | ||
|
|
eaca160367 | ||
|
|
85f18cfb12 | ||
|
|
7492522066 | ||
|
|
334f84637d | ||
|
|
3f15fc0b52 | ||
|
|
a013854d2d | ||
|
|
c883ab87b6 | ||
|
|
0e313e5826 | ||
|
|
3794c00856 | ||
|
|
b87c59c051 | ||
|
|
356ae40c7b | ||
|
|
8394c47064 | ||
|
|
a84f6f08eb | ||
|
|
3a391d1e76 | ||
|
|
9dd94eaf57 | ||
|
|
9f013f0e37 | ||
|
|
f0ec3080e4 | ||
|
|
245de4fe1a | ||
|
|
9d33ef460c | ||
|
|
e0b8b8b4d4 | ||
|
|
529de72f75 | ||
|
|
b4f867924b | ||
|
|
9d3afe80c6 | ||
|
|
28e75d6467 | ||
|
|
b0fa05df0c | ||
|
|
f3ffba378a | ||
|
|
2d89640271 | ||
|
|
e6ee6b5164 | ||
|
|
768a170bb8 | ||
|
|
8834268970 | ||
|
|
fe61b4aab1 | ||
|
|
a6c2490597 | ||
|
|
9110dc6414 | ||
|
|
77be0dd6eb | ||
|
|
40544eb27b | ||
|
|
306cb5b089 | ||
|
|
c46613877c | ||
|
|
2db2fbcade | ||
|
|
ea05f05576 | ||
|
|
361a87f580 | ||
|
|
330c62716c | ||
|
|
63bf25293d | ||
|
|
93867682bb | ||
|
|
7d5c158021 | ||
|
|
06c6422591 | ||
|
|
5e04032797 | ||
|
|
f716176361 | ||
|
|
2826f62497 | ||
|
|
7172fe0c87 | ||
|
|
7e9a84087e | ||
|
|
58e9cd3eeb | ||
|
|
54559c4a5f | ||
|
|
8f5b5e7ae4 | ||
|
|
759ceae23f | ||
|
|
32b37a1390 | ||
|
|
0e43fcfaa1 | ||
|
|
6a27f8da32 | ||
|
|
c24543c237 | ||
|
|
44314ccb99 | ||
|
|
9ad42a3966 | ||
|
|
d34e6570fc | ||
|
|
b5b35491cc | ||
|
|
1e471e5e22 | ||
|
|
aa027f6e29 | ||
|
|
6f581fce43 | ||
|
|
8156da509e | ||
|
|
718e54f933 | ||
|
|
cb56e9f658 | ||
|
|
9afa566be5 | ||
|
|
86847d99da | ||
|
|
258559f9d0 | ||
|
|
af05448dd8 | ||
|
|
e74f9054ae | ||
|
|
82dd485e01 | ||
|
|
1d5e4d22e7 | ||
|
|
28d2292de0 | ||
|
|
73e601315b | ||
|
|
a0c1d1d255 | ||
|
|
411ba107ce | ||
|
|
4f1e4fc223 | ||
|
|
eae05ea59c | ||
|
|
c09d4c98c8 | ||
|
|
474c049f0d | ||
|
|
1d3b7de5c6 | ||
|
|
3f08c2a9b0 |
31
.gitignore
vendored
31
.gitignore
vendored
@@ -10,48 +10,21 @@ log/*.log.lck
|
||||
log/*.log.*
|
||||
tmp/
|
||||
.idea/*
|
||||
solr/data/
|
||||
solr/pids/
|
||||
\#*
|
||||
.#*
|
||||
*~
|
||||
*.~lock.*
|
||||
.emacs.desktop
|
||||
.DS_Store
|
||||
.emacs.desktop.lock*
|
||||
coverage
|
||||
merged_coverage
|
||||
upstream_coverage
|
||||
true/
|
||||
reports
|
||||
*.tmproj
|
||||
*tags
|
||||
dump.rdb
|
||||
bin/
|
||||
spec/javascripts/generated/*
|
||||
db/development_structure.sql
|
||||
db/test_structure.sql
|
||||
db/staging_structure.sql
|
||||
db/production_structure.sql
|
||||
db/bootstrap/*.sql
|
||||
db/bootstrap/*.dump
|
||||
db/bootstrap/*.bak
|
||||
db/bootstrap/*.pgz
|
||||
db/bootstrap/image_fixtures/*
|
||||
db/bootstrap/image_fixtures/properties/*
|
||||
db/backup
|
||||
public/system
|
||||
public/stylesheets
|
||||
public/images
|
||||
vendor/bundle
|
||||
config/database.Tom-Meiers-MacBook-Pro.local.yml
|
||||
public/spree
|
||||
config/abr.yml
|
||||
vendor/ruby
|
||||
ey-cloud-recipes/db/bootstrap/*.dump
|
||||
ey-cloud-recipes/db/bootstrap/*.pgz
|
||||
ey-cloud-recipes/db/bootstrap/image_fixtures/*
|
||||
ey-cloud-recipes/.idea/*
|
||||
chromedriver.log
|
||||
financial_reports/*.csv
|
||||
NERD_tree*
|
||||
spec/reference_images/*
|
||||
public/search
|
||||
|
||||
25
Gemfile
25
Gemfile
@@ -1,23 +1,26 @@
|
||||
source 'http://rubygems.org'
|
||||
ruby "1.9.3"
|
||||
|
||||
gem 'rails', '3.2.3'
|
||||
gem 'rails', '3.2.8'
|
||||
|
||||
gem 'pg'
|
||||
gem 'spree'
|
||||
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/spree/spree_paypal_express.git', :branch => '1-1-stable'
|
||||
gem 'spree_last_address', :git => 'git://github.com/dancinglightning/spree-last-address.git'
|
||||
|
||||
gem 'spree_usa_epay'
|
||||
gem 'spree_skrill'
|
||||
|
||||
# Fix bug in simple_form preventing collection_check_boxes usage within form_for block
|
||||
# When merged, revert to upstream gem
|
||||
gem 'simple_form', :git => 'git://github.com/RohanM/simple_form.git'
|
||||
|
||||
gem 'unicorn'
|
||||
gem 'bugsnag'
|
||||
gem 'spree_heroku', :git => 'git://github.com/joneslee85/spree-heroku.git'
|
||||
gem 'haml'
|
||||
gem 'aws-s3'
|
||||
gem 'andand'
|
||||
gem 'truncate_html'
|
||||
|
||||
# Gems used only for assets and not required
|
||||
# in production environments by default.
|
||||
@@ -33,17 +36,6 @@ end
|
||||
|
||||
gem 'jquery-rails'
|
||||
|
||||
# To use ActiveModel has_secure_password
|
||||
# gem 'bcrypt-ruby', '~> 3.0.0'
|
||||
|
||||
# Use unicorn as the web server
|
||||
# gem 'unicorn'
|
||||
|
||||
# Deploy with Capistrano
|
||||
# gem 'capistrano'
|
||||
|
||||
# To use debugger
|
||||
# gem 'ruby-debug19', :require => 'ruby-debug'
|
||||
|
||||
group :test, :development do
|
||||
# Pretty printed test output
|
||||
@@ -55,6 +47,7 @@ group :test, :development do
|
||||
gem 'capybara'
|
||||
gem 'database_cleaner', '0.7.1', :require => false
|
||||
gem 'spork', '~> 1.0rc'
|
||||
gem 'pry'
|
||||
gem 'pry-debugger'
|
||||
gem 'awesome_print'
|
||||
end
|
||||
|
||||
|
||||
257
Gemfile.lock
257
Gemfile.lock
@@ -6,6 +6,13 @@ 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/joneslee85/spree-heroku.git
|
||||
revision: 63f0cfa47089cae50365e226ec7dd1eccde0ac05
|
||||
@@ -14,6 +21,54 @@ GIT
|
||||
aws-sdk (~> 1.3.4)
|
||||
spree_core (>= 0.70.0)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/spree/spree.git
|
||||
revision: d66ffac9088d0d5d0b0d146f305044ce619f0464
|
||||
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)
|
||||
rabl (= 0.6.5)
|
||||
spree_auth (= 1.1.3)
|
||||
spree_core (= 1.1.3)
|
||||
spree_auth (1.1.3)
|
||||
cancan (= 1.6.7)
|
||||
devise (~> 2.0.0)
|
||||
spree_core (= 1.1.3)
|
||||
spree_cmd (1.1.3)
|
||||
thor (>= 0.14.6)
|
||||
spree_core (1.1.3)
|
||||
activemerchant (= 1.28.0)
|
||||
acts_as_list (= 0.1.4)
|
||||
aws-sdk (~> 1.3.4)
|
||||
deface (>= 0.9.0)
|
||||
ffaker (~> 1.12.0)
|
||||
highline (= 1.6.11)
|
||||
jquery-rails (~> 2.0)
|
||||
kaminari (= 0.13.0)
|
||||
nested_set (= 1.7.0)
|
||||
paperclip (~> 2.7)
|
||||
rails (~> 3.2.8)
|
||||
ransack (~> 0.6.0)
|
||||
state_machine (= 1.1.2)
|
||||
stringex (~> 1.3.2)
|
||||
spree_dash (1.1.3)
|
||||
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)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/spree/spree_i18n.git
|
||||
revision: a96bee02340e008e60549295a4f09e047fd2e628
|
||||
@@ -22,55 +77,62 @@ GIT
|
||||
i18n (~> 0.5)
|
||||
spree (~> 1.1)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/spree/spree_paypal_express.git
|
||||
revision: 2c61f1700ef853e3d4f39739793dc3308422e94b
|
||||
branch: 1-1-stable
|
||||
specs:
|
||||
spree_paypal_express (1.1.0)
|
||||
spree_auth (>= 1.0.0)
|
||||
spree_core (>= 1.0.0)
|
||||
|
||||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
actionmailer (3.2.3)
|
||||
actionpack (= 3.2.3)
|
||||
actionmailer (3.2.8)
|
||||
actionpack (= 3.2.8)
|
||||
mail (~> 2.4.4)
|
||||
actionpack (3.2.3)
|
||||
activemodel (= 3.2.3)
|
||||
activesupport (= 3.2.3)
|
||||
actionpack (3.2.8)
|
||||
activemodel (= 3.2.8)
|
||||
activesupport (= 3.2.8)
|
||||
builder (~> 3.0.0)
|
||||
erubis (~> 2.7.0)
|
||||
journey (~> 1.0.1)
|
||||
journey (~> 1.0.4)
|
||||
rack (~> 1.4.0)
|
||||
rack-cache (~> 1.2)
|
||||
rack-test (~> 0.6.1)
|
||||
sprockets (~> 2.1.2)
|
||||
active_utils (1.0.3)
|
||||
sprockets (~> 2.1.3)
|
||||
active_utils (1.0.5)
|
||||
activesupport (>= 2.3.11)
|
||||
i18n
|
||||
activemerchant (1.20.4)
|
||||
activemerchant (1.28.0)
|
||||
active_utils (>= 1.0.2)
|
||||
activesupport (>= 2.3.11)
|
||||
braintree (>= 2.0.0)
|
||||
builder (>= 2.0.0)
|
||||
i18n
|
||||
json (>= 1.5.1)
|
||||
money (<= 3.7.1)
|
||||
activemodel (3.2.3)
|
||||
activesupport (= 3.2.3)
|
||||
money
|
||||
nokogiri
|
||||
activemodel (3.2.8)
|
||||
activesupport (= 3.2.8)
|
||||
builder (~> 3.0.0)
|
||||
activerecord (3.2.3)
|
||||
activemodel (= 3.2.3)
|
||||
activesupport (= 3.2.3)
|
||||
activerecord (3.2.8)
|
||||
activemodel (= 3.2.8)
|
||||
activesupport (= 3.2.8)
|
||||
arel (~> 3.0.2)
|
||||
tzinfo (~> 0.3.29)
|
||||
activeresource (3.2.3)
|
||||
activemodel (= 3.2.3)
|
||||
activesupport (= 3.2.3)
|
||||
activesupport (3.2.3)
|
||||
activeresource (3.2.8)
|
||||
activemodel (= 3.2.8)
|
||||
activesupport (= 3.2.8)
|
||||
activesupport (3.2.8)
|
||||
i18n (~> 0.6)
|
||||
multi_json (~> 1.0)
|
||||
acts_as_list (0.1.4)
|
||||
addressable (2.2.8)
|
||||
akami (1.1.0)
|
||||
gyoku (>= 0.4.0)
|
||||
nokogiri (>= 1.5.2)
|
||||
andand (1.3.3)
|
||||
ansi (1.4.2)
|
||||
arel (3.0.2)
|
||||
awesome_print (1.0.2)
|
||||
aws-s3 (0.6.3)
|
||||
builder
|
||||
mime-types
|
||||
@@ -81,9 +143,10 @@ GEM
|
||||
nokogiri (>= 1.4.4)
|
||||
uuidtools (~> 2.1)
|
||||
bcrypt-ruby (3.0.1)
|
||||
braintree (2.16.0)
|
||||
builder (>= 2.0.0)
|
||||
builder (3.0.0)
|
||||
bugsnag (1.1.2)
|
||||
httparty (~> 0.8.3)
|
||||
multi_json (~> 1.3.4)
|
||||
builder (3.0.3)
|
||||
cancan (1.6.7)
|
||||
capybara (1.1.2)
|
||||
mime-types (>= 1.16)
|
||||
@@ -94,8 +157,8 @@ GEM
|
||||
xpath (~> 0.1.4)
|
||||
childprocess (0.3.2)
|
||||
ffi (~> 1.0.6)
|
||||
cocaine (0.2.1)
|
||||
coderay (1.0.6)
|
||||
cocaine (0.3.0)
|
||||
coderay (1.0.7)
|
||||
coffee-rails (3.2.2)
|
||||
coffee-script (>= 2.2.0)
|
||||
railties (~> 3.2.0)
|
||||
@@ -103,7 +166,15 @@ GEM
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.3.3)
|
||||
columnize (0.3.6)
|
||||
database_cleaner (0.7.1)
|
||||
debugger (1.1.4)
|
||||
columnize (>= 0.3.1)
|
||||
debugger-linecache (~> 1.1.1)
|
||||
debugger-ruby_core_source (~> 1.1.3)
|
||||
debugger-linecache (1.1.2)
|
||||
debugger-ruby_core_source (>= 1.1.1)
|
||||
debugger-ruby_core_source (1.1.3)
|
||||
deface (0.9.1)
|
||||
nokogiri (~> 1.5.0)
|
||||
rails (~> 3.1)
|
||||
@@ -125,22 +196,18 @@ GEM
|
||||
i18n (~> 0.4)
|
||||
ffaker (1.12.1)
|
||||
ffi (1.0.11)
|
||||
gyoku (0.4.5)
|
||||
builder (>= 2.1.2)
|
||||
haml (3.1.6)
|
||||
highline (1.6.11)
|
||||
hike (1.2.1)
|
||||
httparty (0.8.3)
|
||||
multi_json (~> 1.0)
|
||||
multi_xml
|
||||
httpi (1.0.0)
|
||||
rack
|
||||
i18n (0.6.0)
|
||||
i18n (0.6.1)
|
||||
journey (1.0.4)
|
||||
jquery-rails (2.0.2)
|
||||
railties (>= 3.2.0, < 5.0)
|
||||
jquery-rails (2.1.2)
|
||||
railties (>= 3.1.0, < 5.0)
|
||||
thor (~> 0.14)
|
||||
json (1.7.3)
|
||||
json (1.7.5)
|
||||
kaminari (0.13.0)
|
||||
actionpack (>= 3.0.0)
|
||||
activesupport (>= 3.0.0)
|
||||
@@ -153,17 +220,17 @@ GEM
|
||||
i18n (>= 0.4.0)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
method_source (0.7.1)
|
||||
mime-types (1.18)
|
||||
money (3.7.1)
|
||||
method_source (0.8)
|
||||
mime-types (1.19)
|
||||
money (5.0.0)
|
||||
i18n (~> 0.4)
|
||||
json
|
||||
multi_json (1.3.6)
|
||||
multi_xml (0.5.1)
|
||||
nested_set (1.7.0)
|
||||
activerecord (>= 3.0.0)
|
||||
railties (>= 3.0.0)
|
||||
nokogiri (1.5.3)
|
||||
nori (1.1.0)
|
||||
nokogiri (1.5.5)
|
||||
orm_adapter (0.0.7)
|
||||
paperclip (2.7.0)
|
||||
activerecord (>= 2.3.0)
|
||||
@@ -174,10 +241,13 @@ GEM
|
||||
polyamorous (0.5.0)
|
||||
activerecord (~> 3.0)
|
||||
polyglot (0.3.3)
|
||||
pry (0.9.9.6)
|
||||
pry (0.9.10)
|
||||
coderay (~> 1.0.5)
|
||||
method_source (~> 0.7.1)
|
||||
slop (>= 2.4.4, < 3)
|
||||
method_source (~> 0.8)
|
||||
slop (~> 3.3.1)
|
||||
pry-debugger (0.2.0)
|
||||
debugger (~> 1.1.3)
|
||||
pry (~> 0.9.9)
|
||||
rabl (0.6.5)
|
||||
activesupport (>= 2.3.14)
|
||||
multi_json (~> 1.0)
|
||||
@@ -188,21 +258,21 @@ GEM
|
||||
rack
|
||||
rack-test (0.6.1)
|
||||
rack (>= 1.0)
|
||||
rails (3.2.3)
|
||||
actionmailer (= 3.2.3)
|
||||
actionpack (= 3.2.3)
|
||||
activerecord (= 3.2.3)
|
||||
activeresource (= 3.2.3)
|
||||
activesupport (= 3.2.3)
|
||||
rails (3.2.8)
|
||||
actionmailer (= 3.2.8)
|
||||
actionpack (= 3.2.8)
|
||||
activerecord (= 3.2.8)
|
||||
activeresource (= 3.2.8)
|
||||
activesupport (= 3.2.8)
|
||||
bundler (~> 1.0)
|
||||
railties (= 3.2.3)
|
||||
railties (3.2.3)
|
||||
actionpack (= 3.2.3)
|
||||
activesupport (= 3.2.3)
|
||||
railties (= 3.2.8)
|
||||
railties (3.2.8)
|
||||
actionpack (= 3.2.8)
|
||||
activesupport (= 3.2.8)
|
||||
rack-ssl (~> 1.3.2)
|
||||
rake (>= 0.8.7)
|
||||
rdoc (~> 3.4)
|
||||
thor (~> 0.14.6)
|
||||
thor (>= 0.14.6, < 2.0)
|
||||
raindrops (0.9.0)
|
||||
rake (0.9.2.2)
|
||||
ransack (0.6.0)
|
||||
@@ -230,14 +300,6 @@ GEM
|
||||
railties (~> 3.2.0)
|
||||
sass (>= 3.1.10)
|
||||
tilt (~> 1.3)
|
||||
savon (0.9.14)
|
||||
akami (~> 1.1)
|
||||
builder (>= 2.1.2)
|
||||
gyoku (>= 0.4.0)
|
||||
httpi (~> 1.0)
|
||||
nokogiri (>= 1.4.0)
|
||||
nori (~> 1.1)
|
||||
wasabi (~> 2.2)
|
||||
selenium-webdriver (2.22.2)
|
||||
childprocess (>= 0.2.5)
|
||||
ffi (~> 1.0)
|
||||
@@ -246,54 +308,8 @@ GEM
|
||||
rubyzip
|
||||
shoulda-matchers (1.1.0)
|
||||
activesupport (>= 3.0.0)
|
||||
slop (2.4.4)
|
||||
slop (3.3.3)
|
||||
spork (1.0.0rc3)
|
||||
spree (1.1.1)
|
||||
spree_api (= 1.1.1)
|
||||
spree_auth (= 1.1.1)
|
||||
spree_cmd (= 1.1.1)
|
||||
spree_core (= 1.1.1)
|
||||
spree_dash (= 1.1.1)
|
||||
spree_promo (= 1.1.1)
|
||||
spree_sample (= 1.1.1)
|
||||
spree_api (1.1.1)
|
||||
rabl (= 0.6.5)
|
||||
spree_auth (= 1.1.1)
|
||||
spree_core (= 1.1.1)
|
||||
spree_auth (1.1.1)
|
||||
cancan (= 1.6.7)
|
||||
devise (~> 2.0.0)
|
||||
spree_core (= 1.1.1)
|
||||
spree_cmd (1.1.1)
|
||||
spree_core (1.1.1)
|
||||
activemerchant (= 1.20.4)
|
||||
acts_as_list (= 0.1.4)
|
||||
aws-sdk (~> 1.3.4)
|
||||
deface (>= 0.8.0)
|
||||
ffaker (~> 1.12.0)
|
||||
highline (= 1.6.11)
|
||||
jquery-rails (~> 2.0.0)
|
||||
kaminari (>= 0.13.0)
|
||||
nested_set (= 1.7.0)
|
||||
paperclip (~> 2.7)
|
||||
rails (>= 3.2.2, <= 3.2.3)
|
||||
ransack (~> 0.6.0)
|
||||
state_machine (= 1.1.2)
|
||||
stringex (~> 1.3.2)
|
||||
spree_dash (1.1.1)
|
||||
httparty (~> 0.8.1)
|
||||
spree_auth (= 1.1.1)
|
||||
spree_core (= 1.1.1)
|
||||
spree_promo (1.1.1)
|
||||
spree_auth (= 1.1.1)
|
||||
spree_core (= 1.1.1)
|
||||
spree_sample (1.1.1)
|
||||
spree_core (= 1.1.1)
|
||||
spree_skrill (1.0.2)
|
||||
spree_core (>= 1.0.0)
|
||||
spree_usa_epay (1.0.2)
|
||||
savon
|
||||
spree_core (>= 1.0.0)
|
||||
sprockets (2.1.3)
|
||||
hike (~> 1.2)
|
||||
rack (~> 1.0)
|
||||
@@ -302,11 +318,12 @@ GEM
|
||||
stringex (1.3.3)
|
||||
therubyracer (0.10.1)
|
||||
libv8 (~> 3.3.10)
|
||||
thor (0.14.6)
|
||||
thor (0.16.0)
|
||||
tilt (1.3.3)
|
||||
treetop (1.4.10)
|
||||
polyglot
|
||||
polyglot (>= 0.3.1)
|
||||
truncate_html (0.5.5)
|
||||
turn (0.8.3)
|
||||
ansi
|
||||
tzinfo (0.3.33)
|
||||
@@ -317,12 +334,9 @@ GEM
|
||||
kgio (~> 2.6)
|
||||
rack
|
||||
raindrops (~> 0.7)
|
||||
uuidtools (2.1.2)
|
||||
uuidtools (2.1.3)
|
||||
warden (1.1.1)
|
||||
rack (>= 1.0)
|
||||
wasabi (2.4.0)
|
||||
httpi (~> 1.0)
|
||||
nokogiri (>= 1.4.0)
|
||||
xml-simple (1.1.1)
|
||||
xpath (0.1.4)
|
||||
nokogiri (~> 1.3)
|
||||
@@ -332,7 +346,9 @@ PLATFORMS
|
||||
|
||||
DEPENDENCIES
|
||||
andand
|
||||
awesome_print
|
||||
aws-s3
|
||||
bugsnag
|
||||
capybara
|
||||
coffee-rails (~> 3.2.1)
|
||||
database_cleaner (= 0.7.1)
|
||||
@@ -341,19 +357,20 @@ DEPENDENCIES
|
||||
haml
|
||||
jquery-rails
|
||||
pg
|
||||
pry
|
||||
rails (= 3.2.3)
|
||||
pry-debugger
|
||||
rails (= 3.2.8)
|
||||
rspec-rails
|
||||
sass-rails (~> 3.2.3)
|
||||
shoulda-matchers
|
||||
simple_form!
|
||||
spork (~> 1.0rc)
|
||||
spree
|
||||
spree!
|
||||
spree_heroku!
|
||||
spree_i18n!
|
||||
spree_skrill
|
||||
spree_usa_epay
|
||||
spree_last_address!
|
||||
spree_paypal_express!
|
||||
therubyracer
|
||||
truncate_html
|
||||
turn (~> 0.8.3)
|
||||
uglifier (>= 1.0.3)
|
||||
unicorn
|
||||
|
||||
BIN
app/assets/images/eaterprises_logo.jpg
Normal file
BIN
app/assets/images/eaterprises_logo.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
BIN
app/assets/images/logo.jpg
Normal file
BIN
app/assets/images/logo.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.0 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 6.5 KiB |
BIN
app/assets/images/store/cart.png
Executable file
BIN
app/assets/images/store/cart.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 479 B |
@@ -5,6 +5,8 @@
|
||||
// the compiled file.
|
||||
//
|
||||
|
||||
//= require jquery
|
||||
//= require jquery_ujs
|
||||
//= require admin/spree_core
|
||||
//= require admin/spree_auth
|
||||
//= require admin/spree_promo
|
||||
|
||||
38
app/assets/javascripts/store/products.js
Normal file
38
app/assets/javascripts/store/products.js
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Update the price on the product details page in real time when the variant or the quantity are changed.
|
||||
**/
|
||||
|
||||
$(document).ready(function() {
|
||||
// Product page with variant choice
|
||||
$("#product-variants input[type='radio']").change(products_update_price_with_variant);
|
||||
$("#quantity").change(products_update_price_with_variant);
|
||||
$("#quantity").change();
|
||||
|
||||
// Product page with master price only
|
||||
$(".add-to-cart input.title:not(#quantity):not(.max_quantity)").change(products_update_price_without_variant).change();
|
||||
});
|
||||
|
||||
|
||||
function products_update_price_with_variant() {
|
||||
var variant_price = $("#product-variants input[type='radio']:checked").parent().find("span.price").html();
|
||||
variant_price = variant_price.substr(2, variant_price.length-3);
|
||||
|
||||
var quantity = $("#quantity").val();
|
||||
|
||||
$("#product-price span.price").html("$"+(parseFloat(variant_price) * parseInt(quantity)).toFixed(2));
|
||||
}
|
||||
|
||||
|
||||
function products_update_price_without_variant() {
|
||||
var master_price = $("#product-price span.price").data('master-price');
|
||||
if(master_price == null) {
|
||||
// Store off the master price
|
||||
master_price = $("#product-price span.price").html();
|
||||
master_price = master_price.substring(1);
|
||||
$("#product-price span.price").data('master-price', master_price);
|
||||
}
|
||||
|
||||
var quantity = $(this).val();
|
||||
|
||||
$("#product-price span.price").html("$"+(parseFloat(master_price)*parseInt(quantity)).toFixed(2));
|
||||
}
|
||||
7
app/assets/stylesheets/admin/openfoodweb.css.scss
Normal file
7
app/assets/stylesheets/admin/openfoodweb.css.scss
Normal file
@@ -0,0 +1,7 @@
|
||||
#header #logo {
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
#header h1 {
|
||||
left: 275px;
|
||||
}
|
||||
@@ -1,5 +1,23 @@
|
||||
@import "screen";
|
||||
|
||||
a:hover {
|
||||
color: lighten($link_text_color, 20) !important;
|
||||
}
|
||||
|
||||
table {
|
||||
tbody, tfoot {
|
||||
tr {
|
||||
&.alt, &.odd {
|
||||
background-color: lighten($link_text_color, 75) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#header #logo {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
/* Style current distributor in main nav bar */
|
||||
nav #main-nav-bar {
|
||||
li {
|
||||
@@ -147,8 +165,43 @@ ul.product-listing {
|
||||
}
|
||||
#empty-cart {
|
||||
float: left;
|
||||
margin-top: 15px !important;
|
||||
|
||||
p {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Delivery fees table on checkout page */
|
||||
#delivery-fees {
|
||||
clear: both;
|
||||
padding-top: 6em;
|
||||
|
||||
table#delivery {
|
||||
width: 100%;
|
||||
|
||||
tbody {
|
||||
tr {
|
||||
td.item-shipping-cost, td.item-shipping-method {
|
||||
text-align: center;
|
||||
}
|
||||
td.item-shipping-cost {
|
||||
@extend span.price;
|
||||
@extend span.price.selling;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.subtotal {
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
text-transform: uppercase;
|
||||
margin-top: 15px;
|
||||
|
||||
span.order-total {
|
||||
@extend span.price;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
58
app/assets/stylesheets/store/variables.css.scss
Normal file
58
app/assets/stylesheets/store/variables.css.scss
Normal file
@@ -0,0 +1,58 @@
|
||||
/*--------------------------------------*/
|
||||
/* Colors
|
||||
/*--------------------------------------*/
|
||||
$c_green: #8dba53; /* Spree green */
|
||||
$c_red: #e45353; /* Error red */
|
||||
|
||||
$layout_background_color: #FFFFFF;
|
||||
$title_text_color: #404042;
|
||||
$body_text_color: #404042;
|
||||
$link_text_color: #006066;
|
||||
|
||||
$product_background_color: #FFFFFF;
|
||||
$product_title_text_color: #404042;
|
||||
$product_body_text_color: #404042;
|
||||
$product_link_text_color: #BBBBBB;
|
||||
|
||||
/*--------------------------------------*/
|
||||
/* Fonts import from remote
|
||||
/*--------------------------------------*/
|
||||
@import url(//fonts.googleapis.com/css?family=Ubuntu:400,700,400italic,700italic|&subset=latin,cyrillic,greek,greek-ext,latin-ext,cyrillic-ext);
|
||||
|
||||
/*--------------------------------------*/
|
||||
/* Font families
|
||||
/*--------------------------------------*/
|
||||
$ff_base: 'Ubuntu', sans-serif;
|
||||
|
||||
/*--------------------------------------
|
||||
| Font sizes
|
||||
|--------------------------------------
|
||||
|- Navigation
|
||||
| */
|
||||
$header_navigation_font_size: 14px;
|
||||
$horizontal_navigation_font_size: 16px;
|
||||
$main_navigation_header_font_size: 14px;
|
||||
$main_navigation_font_size: 12px;
|
||||
/*|------------------------------------
|
||||
|- Product Listing
|
||||
| */
|
||||
$product_list_name_font_size: 12px;
|
||||
$product_list_price_font_size: 16px;
|
||||
$product_list_header_font_size: 20px;
|
||||
$product_list_search_font_size: 14px;
|
||||
/*|------------------------------------
|
||||
|- Product Details
|
||||
| */
|
||||
$product_detail_name_font_size: 24px;
|
||||
$product_detail_description_font_size: 12px;
|
||||
$product_detail_price_font_size: 20px;
|
||||
$product_detail_title_font_size: 14px;
|
||||
/*|------------------------------------
|
||||
|- Basic
|
||||
| */
|
||||
$heading_font_size: 24px;
|
||||
$sub_heading_font_size: 14px;
|
||||
$button_font_size: 12px;
|
||||
$input_box_font_size: 13px;
|
||||
$base_font_size: 12px;
|
||||
$button_border_color: rgba(0, 138, 189, .75);
|
||||
@@ -6,7 +6,7 @@ class ApplicationController < ActionController::Base
|
||||
private
|
||||
def load_data_for_sidebar
|
||||
@suppliers = Spree::Supplier.all
|
||||
@distributors = Spree::Distributor.all
|
||||
@distributors = Spree::Distributor.with_active_products_on_hand.by_name
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,16 +1,30 @@
|
||||
module Spree
|
||||
module Admin
|
||||
class DistributorsController < ResourceController
|
||||
before_filter :load_data, :except => [:index]
|
||||
before_filter :load_distributor_set, :only => :index
|
||||
before_filter :load_countries, :except => :index
|
||||
|
||||
def bulk_update
|
||||
@distributor_set = DistributorSet.new(params[:distributor_set])
|
||||
if @distributor_set.save
|
||||
redirect_to admin_distributors_path, :notice => 'Distributor collection times updated.'
|
||||
else
|
||||
render :index
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def load_data
|
||||
@countries = Country.order(:name)
|
||||
def load_distributor_set
|
||||
@distributor_set = Spree::DistributorSet.new :distributors => collection
|
||||
end
|
||||
|
||||
def load_countries
|
||||
@countries = Country.order(:name)
|
||||
end
|
||||
|
||||
def collection
|
||||
super.order(:name)
|
||||
super.order(:name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
37
app/controllers/spree/admin/reports_controller_decorator.rb
Normal file
37
app/controllers/spree/admin/reports_controller_decorator.rb
Normal file
@@ -0,0 +1,37 @@
|
||||
require 'csv'
|
||||
require 'open_food_web/order_and_distributor_report'
|
||||
|
||||
Spree::Admin::ReportsController.class_eval do
|
||||
|
||||
Spree::Admin::ReportsController::AVAILABLE_REPORTS.merge!({:orders_and_distributors => {:name => "Orders And Distributors", :description => "Orders with distributor details"}})
|
||||
|
||||
def orders_and_distributors
|
||||
params[:q] = {} unless params[:q]
|
||||
|
||||
if params[:q][:created_at_gt].blank?
|
||||
params[:q][:created_at_gt] = Time.zone.now.beginning_of_month
|
||||
else
|
||||
params[:q][:created_at_gt] = Time.zone.parse(params[:q][:created_at_gt]).beginning_of_day rescue Time.zone.now.beginning_of_month
|
||||
end
|
||||
|
||||
if params[:q] && !params[:q][:created_at_lt].blank?
|
||||
params[:q][:created_at_lt] = Time.zone.parse(params[:q][:created_at_lt]).end_of_day rescue ""
|
||||
end
|
||||
params[:q][:meta_sort] ||= "created_at.desc"
|
||||
|
||||
@search = Spree::Order.complete.search(params[:q])
|
||||
orders = @search.result
|
||||
|
||||
@report = OpenFoodWeb::OrderAndDistributorReport.new orders
|
||||
if(!params[:csv])
|
||||
render :html => @report
|
||||
else
|
||||
csv_string = CSV.generate do |csv|
|
||||
csv << @report.header
|
||||
@report.table.each { |row| csv << row }
|
||||
end
|
||||
send_data csv_string, :filename => "orders_and_distributors.csv"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,28 @@
|
||||
module Spree
|
||||
module Admin
|
||||
ShippingMethodsController.class_eval do
|
||||
before_filter :do_not_destroy_referenced_shipping_methods, :only => :destroy
|
||||
|
||||
def do_not_destroy_referenced_shipping_methods
|
||||
order = Order.where(:shipping_method_id => @object).first
|
||||
if order
|
||||
flash[:error] = "That shipping method cannot be deleted as it is referenced by an order: #{order.number}."
|
||||
redirect_to collection_url and return
|
||||
end
|
||||
|
||||
product_distribution = ProductDistribution.where(:shipping_method_id => @object).first
|
||||
if product_distribution
|
||||
p = product_distribution.product
|
||||
flash[:error] = "That shipping method cannot be deleted as it is referenced by a product distribution: #{p.id} - #{p.name}."
|
||||
redirect_to collection_url and return
|
||||
end
|
||||
|
||||
line_item = LineItem.where(:shipping_method_id => @object).first
|
||||
if line_item
|
||||
flash[:error] = "That shipping method cannot be deleted as it is referenced by a line item in order: #{line_item.order.number}."
|
||||
redirect_to collection_url and return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
25
app/controllers/spree/base_controller_decorator.rb
Normal file
25
app/controllers/spree/base_controller_decorator.rb
Normal file
@@ -0,0 +1,25 @@
|
||||
module Spree
|
||||
BaseController.class_eval do
|
||||
|
||||
# Override definition in spree/auth/app/controllers/spree/base_controller_decorator.rb
|
||||
# Do not attempt to merge incomplete and current orders when they have differing distributors
|
||||
# Instead, destroy the incomplete orders, otherwise they are restored after checkout, causing much confusion
|
||||
def set_current_order
|
||||
if current_user
|
||||
if current_user.respond_to?(:last_incomplete_order)
|
||||
last_incomplete_order = current_user.last_incomplete_order
|
||||
if session[:order_id].nil? && last_incomplete_order
|
||||
session[:order_id] = last_incomplete_order.id
|
||||
elsif current_order && last_incomplete_order && current_order != last_incomplete_order
|
||||
if current_order.distributor.nil? || current_order.distributor == last_incomplete_order.distributor
|
||||
current_order.set_distributor! last_incomplete_order.distributor if current_order.distributor.nil?
|
||||
current_order.merge!(last_incomplete_order)
|
||||
else
|
||||
last_incomplete_order.destroy
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,20 +1,38 @@
|
||||
Spree::OrdersController.class_eval do
|
||||
before_filter :populate_order_distributor, :only => :populate
|
||||
before_filter :populate_order_distributor, :only => :populate
|
||||
after_filter :populate_variant_attributes, :only => :populate
|
||||
|
||||
def populate_order_distributor
|
||||
@distributor = params.key?(:distributor_id) ? Spree::Distributor.find(params[:distributor_id]) : nil
|
||||
@distributor = params[:distributor_id].present? ? Spree::Distributor.find(params[:distributor_id]) : nil
|
||||
|
||||
if populate_valid? @distributor
|
||||
order = current_order(true)
|
||||
order.distributor = @distributor
|
||||
order.save!
|
||||
order.set_distributor! @distributor
|
||||
|
||||
else
|
||||
redirect_to cart_path
|
||||
flash[:error] = "Please choose a distributor for this order." if @distributor.nil?
|
||||
redirect_populate_to_first_product
|
||||
end
|
||||
end
|
||||
|
||||
def populate_variant_attributes
|
||||
if params.key? :variant_attributes
|
||||
params[:variant_attributes].each do |variant_id, attributes|
|
||||
@order.set_variant_attributes(Spree::Variant.find(variant_id), attributes)
|
||||
end
|
||||
end
|
||||
|
||||
if params.key? :quantity
|
||||
params[:products].each do |product_id, variant_id|
|
||||
max_quantity = params[:max_quantity].to_i
|
||||
@order.set_variant_attributes(Spree::Variant.find(variant_id), {:max_quantity => max_quantity})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def populate_valid? distributor
|
||||
# -- Distributor must be specified
|
||||
return false if distributor.nil?
|
||||
@@ -38,4 +56,14 @@ Spree::OrdersController.class_eval do
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def redirect_populate_to_first_product
|
||||
product = if params[:products].present?
|
||||
Spree::Product.find(params[:products].keys.first)
|
||||
else
|
||||
Spree::Variant.find(params[:variants].keys.first).product
|
||||
end
|
||||
|
||||
redirect_to product
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
module Spree
|
||||
class SuppliersController < BaseController
|
||||
helper 'spree/products'
|
||||
|
||||
def show
|
||||
options = {:supplier_id => params[:id]}
|
||||
options.merge(params.reject { |k,v| k == :id })
|
||||
|
||||
9
app/helpers/spree/orders_helper.rb
Normal file
9
app/helpers/spree/orders_helper.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
module Spree
|
||||
module OrdersHelper
|
||||
def order_delivery_fee_subtotal(order, options={})
|
||||
options.reverse_merge! :format_as_currency => true
|
||||
amount = order.line_items.map { |li| li.itemwise_shipping_cost }.sum
|
||||
options.delete(:format_as_currency) ? number_to_currency(amount) : amount
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,8 +1,7 @@
|
||||
module Spree
|
||||
ProductsHelper.class_eval do
|
||||
# Return the price of the variant, or nil if it is identical to the master price
|
||||
# Return the price of the variant
|
||||
def variant_price_diff(variant)
|
||||
return nil if variant.price == variant.product.price
|
||||
"(#{number_to_currency variant.price})"
|
||||
end
|
||||
end
|
||||
|
||||
13
app/models/open_food_web/calculator/itemwise.rb
Normal file
13
app/models/open_food_web/calculator/itemwise.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
module OpenFoodWeb
|
||||
class Calculator::Itemwise < Spree::Calculator
|
||||
|
||||
def self.description
|
||||
"Itemwise Shipping"
|
||||
end
|
||||
|
||||
def compute(object)
|
||||
# Given an order, sum the shipping on each individual item
|
||||
object.line_items.map { |li| li.itemwise_shipping_cost }.inject(:+) || 0
|
||||
end
|
||||
end
|
||||
end
|
||||
15
app/models/open_food_web/calculator/weight.rb
Normal file
15
app/models/open_food_web/calculator/weight.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
module OpenFoodWeb
|
||||
class Calculator::Weight < Spree::Calculator
|
||||
preference :per_kg, :decimal, :default => 0.0
|
||||
attr_accessible :preferred_per_kg
|
||||
|
||||
def self.description
|
||||
"Weight (per kg)"
|
||||
end
|
||||
|
||||
def compute(object)
|
||||
total_weight = object.line_items.inject(0) { |sum, li| sum + ((li.variant.andand.weight || 0) * li.quantity) }
|
||||
total_weight * self.preferred_per_kg
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,15 +2,18 @@ module Spree
|
||||
class Distributor < ActiveRecord::Base
|
||||
self.table_name = 'distributors'
|
||||
belongs_to :pickup_address, :foreign_key => 'pickup_address_id', :class_name => 'Spree::Address'
|
||||
has_and_belongs_to_many :products
|
||||
has_many :orders
|
||||
|
||||
has_many :product_distributions, :dependent => :destroy
|
||||
has_many :products, :through => :product_distributions
|
||||
|
||||
accepts_nested_attributes_for :pickup_address
|
||||
|
||||
validates_presence_of :name, :pickup_address
|
||||
validates_associated :pickup_address
|
||||
|
||||
scope :by_name, order('name')
|
||||
scope :with_active_products_on_hand, lambda { joins(:products).where('spree_products.deleted_at IS NULL AND spree_products.available_on <= ? AND spree_products.count_on_hand > 0', Time.now).select('distinct(distributors.*)') }
|
||||
|
||||
after_initialize :initialize_country
|
||||
before_validation :set_unused_address_fields
|
||||
|
||||
36
app/models/spree/distributor_set.rb
Normal file
36
app/models/spree/distributor_set.rb
Normal file
@@ -0,0 +1,36 @@
|
||||
# Tableless model to handle updating multiple distributors at once from a
|
||||
# single form. Used to update next_collection_at field for all distributors in
|
||||
# admin backend.
|
||||
module Spree
|
||||
class DistributorSet
|
||||
include ActiveModel::Conversion
|
||||
extend ActiveModel::Naming
|
||||
|
||||
attr_accessor :distributors
|
||||
|
||||
def initialize(attributes={})
|
||||
@distributors = Spree::Distributor.all
|
||||
|
||||
attributes.each do |name, value|
|
||||
send("#{name}=", value)
|
||||
end
|
||||
end
|
||||
|
||||
def distributors_attributes=(attributes)
|
||||
attributes.each do |k, attributes|
|
||||
# attributes == {:id => 123, :next_collection_at => '...'}
|
||||
d = @distributors.detect { |d| d.id.to_s == attributes[:id].to_s }
|
||||
d.assign_attributes(attributes.except(:id))
|
||||
end
|
||||
end
|
||||
|
||||
def save
|
||||
distributors.all?(&:save)
|
||||
end
|
||||
|
||||
def persisted?
|
||||
false
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
20
app/models/spree/line_item_decorator.rb
Normal file
20
app/models/spree/line_item_decorator.rb
Normal file
@@ -0,0 +1,20 @@
|
||||
Spree::LineItem.class_eval do
|
||||
belongs_to :shipping_method
|
||||
|
||||
attr_accessible :max_quantity
|
||||
|
||||
before_create :set_itemwise_shipping_method
|
||||
|
||||
|
||||
def itemwise_shipping_cost
|
||||
order = OpenStruct.new :line_items => [self]
|
||||
shipping_method.compute_amount(order)
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def set_itemwise_shipping_method
|
||||
self.shipping_method = self.product.shipping_method_for_distributor(self.order.distributor)
|
||||
end
|
||||
end
|
||||
@@ -1,6 +1,9 @@
|
||||
Spree::Order.class_eval do
|
||||
belongs_to :distributor
|
||||
|
||||
before_validation :shipping_address_from_distributor
|
||||
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?
|
||||
@@ -11,15 +14,47 @@ Spree::Order.class_eval do
|
||||
super(distributor)
|
||||
end
|
||||
|
||||
def set_distributor!(distributor)
|
||||
self.distributor = distributor
|
||||
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)
|
||||
|
||||
if attributes.key?(:max_quantity) && attributes[:max_quantity].to_i < line_item.quantity
|
||||
attributes[:max_quantity] = line_item.quantity
|
||||
end
|
||||
|
||||
line_item.assign_attributes(attributes)
|
||||
line_item.save!
|
||||
end
|
||||
|
||||
before_validation :shipping_address_from_distributor
|
||||
|
||||
private
|
||||
|
||||
# On creation of the order (when the first item is added to the user's cart), set the
|
||||
# shipping method to the first one available and create a shipment.
|
||||
# order.create_shipment! creates an adjustment for the shipping cost on the order,
|
||||
# which means that the customer can see their shipping cost at every step of the
|
||||
# checkout process, not just after the delivery step.
|
||||
# This is based on the assumption that there's only one shipping method visible to the user,
|
||||
# which is a method using the itemwise shipping calculator.
|
||||
def set_default_shipping_method
|
||||
self.shipping_method = Spree::ShippingMethod.where("display_on != 'back_end'").first
|
||||
if self.shipping_method
|
||||
self.save!
|
||||
self.create_shipment!
|
||||
else
|
||||
raise 'No default shipping method found'
|
||||
end
|
||||
end
|
||||
|
||||
def shipping_address_from_distributor
|
||||
if distributor
|
||||
self.ship_address = distributor.pickup_address.clone
|
||||
|
||||
@@ -1,11 +1,32 @@
|
||||
Spree::Product.class_eval do
|
||||
belongs_to :supplier
|
||||
has_and_belongs_to_many :distributors
|
||||
|
||||
attr_accessible :supplier_id, :distributor_ids
|
||||
has_many :product_distributions, :dependent => :destroy
|
||||
has_many :distributors, :through => :product_distributions
|
||||
|
||||
validates_presence_of :supplier, :distributors
|
||||
accepts_nested_attributes_for :product_distributions, :allow_destroy => true
|
||||
|
||||
attr_accessible :supplier_id, :distributor_ids, :product_distributions_attributes, :group_buy
|
||||
|
||||
validates_presence_of :supplier
|
||||
|
||||
scope :in_supplier, lambda { |supplier| where(:supplier_id => supplier) }
|
||||
scope :in_distributor, lambda { |distributor| joins(:distributors).where('distributors.id = ?', (distributor.respond_to?(:id) ? distributor.id : distributor.to_i)) }
|
||||
scope :in_distributor, lambda { |distributor| joins(:product_distributions).where('product_distributions.distributor_id = ?', (distributor.respond_to?(:id) ? distributor.id : distributor.to_i)) }
|
||||
|
||||
|
||||
def shipping_method_for_distributor(distributor)
|
||||
distribution = self.product_distributions.find_by_distributor_id(distributor)
|
||||
raise ArgumentError, "This product is not available through that distributor" unless distribution
|
||||
distribution.shipping_method
|
||||
end
|
||||
|
||||
|
||||
# Build a product distribution for each distributor
|
||||
def build_product_distributions
|
||||
Spree::Distributor.all.each do |distributor|
|
||||
unless self.product_distributions.find_by_distributor_id distributor.id
|
||||
self.product_distributions.build(:distributor => distributor)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
13
app/models/spree/product_distribution.rb
Normal file
13
app/models/spree/product_distribution.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
module Spree
|
||||
class ProductDistribution < ActiveRecord::Base
|
||||
self.table_name = 'product_distributions'
|
||||
|
||||
belongs_to :product
|
||||
belongs_to :distributor
|
||||
belongs_to :shipping_method
|
||||
|
||||
validates_presence_of :product_id, :on => :update
|
||||
validates_presence_of :distributor_id, :shipping_method_id
|
||||
validates_uniqueness_of :product_id, :scope => :distributor_id
|
||||
end
|
||||
end
|
||||
4
app/overrides/add_distributor_fees_to_cart_form.rb
Normal file
4
app/overrides/add_distributor_fees_to_cart_form.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
Deface::Override.new(:virtual_path => "spree/orders/edit",
|
||||
:insert_after => "#empty-cart",
|
||||
:partial => "spree/orders/distributor_fees",
|
||||
:name => "cart_distributor_fees")
|
||||
@@ -1,9 +1,9 @@
|
||||
Deface::Override.new(:virtual_path => "spree/admin/products/_form",
|
||||
:insert_top => "[data-hook='admin_product_form_right']",
|
||||
:partial => "spree/admin/products/distributors",
|
||||
:name => "distributors")
|
||||
:insert_bottom => "[data-hook='admin_product_form_additional_fields']",
|
||||
:partial => "spree/admin/products/distributors_form",
|
||||
:name => "distributors")
|
||||
|
||||
Deface::Override.new(:virtual_path => "spree/admin/products/new",
|
||||
:insert_bottom => ".left",
|
||||
:partial => "spree/admin/products/distributors",
|
||||
:name => "distributors")
|
||||
:insert_after => "[data-hook='new_product_attrs']",
|
||||
:partial => "spree/admin/products/distributors_form",
|
||||
:name => "distributors")
|
||||
|
||||
9
app/overrides/add_group_buy_to_admin_product.rb
Normal file
9
app/overrides/add_group_buy_to_admin_product.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
Deface::Override.new(:virtual_path => "spree/admin/products/_form",
|
||||
:insert_top => "[data-hook='admin_product_form_right']",
|
||||
:partial => "spree/admin/products/group_buy_form",
|
||||
:name => "group buy")
|
||||
|
||||
Deface::Override.new(:virtual_path => "spree/admin/products/new",
|
||||
:insert_bottom => ".right",
|
||||
:partial => "spree/admin/products/group_buy_form",
|
||||
:name => "group buy")
|
||||
@@ -1,9 +1,9 @@
|
||||
Deface::Override.new(:virtual_path => "spree/admin/products/_form",
|
||||
:insert_top => "[data-hook='admin_product_form_right']",
|
||||
:partial => "spree/admin/products/supplier",
|
||||
:name => "supplier")
|
||||
Deface::Override.new(:virtual_path => "spree/admin/products/_form",
|
||||
:insert_top => "[data-hook='admin_product_form_right']",
|
||||
:partial => "spree/admin/products/supplier_form",
|
||||
:name => "supplier")
|
||||
|
||||
Deface::Override.new(:virtual_path => "spree/admin/products/new",
|
||||
:insert_bottom => ".left",
|
||||
:partial => "spree/admin/products/supplier",
|
||||
:name => "supplier")
|
||||
:insert_bottom => ".right",
|
||||
:partial => "spree/admin/products/supplier_form",
|
||||
:name => "supplier")
|
||||
|
||||
4
app/overrides/cart_item_description.rb
Normal file
4
app/overrides/cart_item_description.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
Deface::Override.new(:virtual_path => "spree/orders/_line_item",
|
||||
:replace => "[data-hook='cart_item_description']",
|
||||
:partial => "spree/orders/cart_item_description",
|
||||
:name => "cart_item_description")
|
||||
@@ -0,0 +1,4 @@
|
||||
Deface::Override.new(:virtual_path => "spree/shared/_order_details",
|
||||
:replace => "div.payment-info",
|
||||
:partial => "spree/shared/order_details_payment_info",
|
||||
:name => "order_details_payment_info")
|
||||
@@ -26,8 +26,11 @@
|
||||
%fieldset
|
||||
%legend Pickup details
|
||||
%table{"data-hook" => "distributors_pickup_details"}
|
||||
%tr{"data-hook" => "next_collection_at"}
|
||||
%td Next collection date/time:
|
||||
%td= f.text_field :next_collection_at
|
||||
%tr{"data-hook" => "pickup_times"}
|
||||
%td Pickup times:
|
||||
%td Regular pickup times:
|
||||
%td= f.text_field :pickup_times
|
||||
= f.fields_for :pickup_address do |pickup_address_form|
|
||||
= render 'spree/admin/shared/address_form', :form => pickup_address_form
|
||||
= render 'spree/admin/shared/address_form', :f => pickup_address_form
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
<div class="toolbar" data-hook="toolbar">
|
||||
<ul class="actions">
|
||||
<li>
|
||||
@@ -8,30 +7,34 @@
|
||||
<br class="clear" />
|
||||
</div>
|
||||
|
||||
<table class="index" id='listing_distributors'>
|
||||
<thead>
|
||||
<tr data-hook="distributors_header">
|
||||
<th>Name</th>
|
||||
<th>
|
||||
Description
|
||||
</th>
|
||||
<th>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @distributors.each do |distributor| %>
|
||||
<tr >
|
||||
<td><%= link_to distributor.name, spree.admin_distributor_path(distributor) %></td>
|
||||
<td><%=distributor.description %></td>
|
||||
<td data-hook="admin_users_index_row_actions">
|
||||
<%= link_to_edit distributor, :class => 'edit' %>
|
||||
<%= link_to_delete distributor %>
|
||||
</td>
|
||||
<%= form_for @distributor_set, :url => bulk_update_admin_distributors_path do |f| %>
|
||||
<table class="index" id="listing_distributors">
|
||||
<thead>
|
||||
<tr data-hook="distributors_header">
|
||||
<th>Name</th>
|
||||
<th>Next Collection Date/Time</th>
|
||||
<th>Description</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% if @distributors.empty? %>
|
||||
<tr><td colspan="2"><%= t(:none) %></td></tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%= f.fields_for :distributors do |distributor_form| %>
|
||||
<% distributor = distributor_form.object %>
|
||||
<tr>
|
||||
<td><%= link_to distributor.name, spree.admin_distributor_path(distributor) %></td>
|
||||
<td><%= distributor_form.text_field :next_collection_at %></td>
|
||||
<td><%= distributor.description %></td>
|
||||
<td data-hook="admin_users_index_row_actions">
|
||||
<%= link_to_edit distributor, :class => 'edit' %>
|
||||
<%= link_to_delete distributor %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% if @distributors.empty? %>
|
||||
<tr><td colspan="4"><%= t(:none) %></td></tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<%= f.submit 'Update' %>
|
||||
<% end %>
|
||||
|
||||
@@ -19,7 +19,10 @@
|
||||
%th Pickup address:
|
||||
%td= render 'spree/shared/address', :address => @distributor.pickup_address
|
||||
%tr
|
||||
%th Pickup times:
|
||||
%th Next collection date/time:
|
||||
%td= @distributor.next_collection_at
|
||||
%tr
|
||||
%th Regular pickup times:
|
||||
%td= @distributor.pickup_times
|
||||
%tr
|
||||
%th ABN:
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
= f.field_container :distributors do
|
||||
= f.label :distributors
|
||||
%br
|
||||
= f.collection_check_boxes(:distributor_ids, Spree::Distributor.all, :id, :name)
|
||||
= f.error_message_on :distributors
|
||||
14
app/views/spree/admin/products/_distributors_form.html.haml
Normal file
14
app/views/spree/admin/products/_distributors_form.html.haml
Normal file
@@ -0,0 +1,14 @@
|
||||
%h2 Distributors
|
||||
= f.field_container :product_distributions do
|
||||
- f.object.build_product_distributions
|
||||
%table
|
||||
= f.fields_for :product_distributions do |pd_form|
|
||||
%tr
|
||||
%td
|
||||
= hidden_field_tag "#{pd_form.object_name}[_destroy]", 1, :id => nil
|
||||
= check_box_tag "#{pd_form.object_name}[_destroy]", 0, !pd_form.object.new_record?
|
||||
%td
|
||||
= label_tag "#{pd_form.object_name}[_destroy]", pd_form.object.distributor.name
|
||||
= pd_form.hidden_field :distributor_id
|
||||
%td
|
||||
= pd_form.collection_select :shipping_method_id, Spree::ShippingMethod.all, :id, :name
|
||||
7
app/views/spree/admin/products/_group_buy_form.html.haml
Normal file
7
app/views/spree/admin/products/_group_buy_form.html.haml
Normal file
@@ -0,0 +1,7 @@
|
||||
= f.field_container :group_buy do
|
||||
= f.label :group_buy, 'Group buy?'
|
||||
%br
|
||||
= f.radio_button :group_buy, '1', :checked => f.object.group_buy
|
||||
= f.label :group_buy_1, 'Yes'
|
||||
= f.radio_button :group_buy, '0', :checked => !f.object.group_buy
|
||||
= f.label :group_buy_0, 'No'
|
||||
@@ -0,0 +1,32 @@
|
||||
= form_for @search, :url => spree.orders_and_distributors_admin_reports_path do |s|
|
||||
= label_tag nil, t(:date_range)
|
||||
%br
|
||||
.date-range-filter
|
||||
%div{"class" => "left sub-field"}
|
||||
= s.text_field :created_at_gt, :class => 'datepicker'
|
||||
%br
|
||||
= label_tag nil, t(:start), :class => 'sub'
|
||||
%div{"class" => "right sub-field"}
|
||||
= s.text_field :created_at_lt, :class => 'datepicker'
|
||||
%br
|
||||
= label_tag nil, t(:stop)
|
||||
= check_box_tag :csv
|
||||
= label_tag :csv, "Download as csv"
|
||||
%br
|
||||
= button t(:search)
|
||||
%br
|
||||
%br
|
||||
%table#listing_orders.index
|
||||
%thead
|
||||
%tr{'data-hook' => "orders_header"}
|
||||
- @report.header.each do |heading|
|
||||
%th=heading
|
||||
%tbody
|
||||
- @report.table.each do |row|
|
||||
%tr
|
||||
- row.each do |column|
|
||||
%td= column
|
||||
- if @report.table.empty?
|
||||
%tr
|
||||
%td{:colspan => "2"}= t(:none)
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
%tr{"data-hook" => "address1"}
|
||||
%td Address:
|
||||
%td= form.text_field :address1
|
||||
%td= f.text_field :address1
|
||||
%tr{"data-hook" => "address2"}
|
||||
%td Address (cont.):
|
||||
%td= form.text_field :address2
|
||||
%td= f.text_field :address2
|
||||
%tr{"data-hook" => "city"}
|
||||
%td City:
|
||||
%td= form.text_field :city
|
||||
%td= f.text_field :city
|
||||
%tr{"data-hook" => "zipcode"}
|
||||
%td Postcode:
|
||||
%td= form.text_field :zipcode
|
||||
%td= f.text_field :zipcode
|
||||
%tr{"data-hook" => "country"}
|
||||
%td Country:
|
||||
%td= form.collection_select(:country_id, available_countries, :id, :name)
|
||||
%td= f.collection_select(:country_id, available_countries, :id, :name)
|
||||
%tr{"data-hook" => "state"}
|
||||
%td State:
|
||||
%td= form.collection_select(:state_id, form.object.country.states, :id, :name)
|
||||
%td= f.collection_select(:state_id, f.object.country.states, :id, :name)
|
||||
|
||||
6
app/views/spree/admin/shared/_tabs.html.erb
Normal file
6
app/views/spree/admin/shared/_tabs.html.erb
Normal file
@@ -0,0 +1,6 @@
|
||||
<%= tab :overview, :route => :admin %>
|
||||
<%= tab :orders, :payments, :creditcard_payments, :shipments, :creditcards, :return_authorizations, {:url => admin_orders_path('q[s]' => 'completed_at desc')} %>
|
||||
<%= tab :products , :option_types, :properties, :prototypes, :variants, :product_properties, :taxons %>
|
||||
<%= tab :reports %>
|
||||
<%= tab :configurations, :general_settings, :mail_methods, :tax_categories, :zones, :states, :payment_methods, :inventory_settings, :taxonomies, :shipping_methods, :trackers, :label => 'configuration' %>
|
||||
<%= tab :users %>
|
||||
@@ -6,7 +6,7 @@
|
||||
%td Description:
|
||||
%td= f.text_field :description
|
||||
= f.fields_for :address do |address_form|
|
||||
= render 'spree/admin/shared/address_form', :form => address_form
|
||||
= render 'spree/admin/shared/address_form', :f => address_form
|
||||
%tr{'data-hook' => "email"}
|
||||
%td Email:
|
||||
%td= f.text_field :email
|
||||
|
||||
@@ -7,7 +7,11 @@
|
||||
%br/
|
||||
= render 'spree/shared/address', :address => @order.distributor.pickup_address
|
||||
%p
|
||||
%strong Pickup times:
|
||||
%strong Next collection time:
|
||||
%br/
|
||||
= @order.distributor.next_collection_at
|
||||
%p
|
||||
%strong Regular collection times:
|
||||
%br/
|
||||
= @order.distributor.pickup_times
|
||||
%p
|
||||
|
||||
33
app/views/spree/order_mailer/confirm_email.text.erb
Normal file
33
app/views/spree/order_mailer/confirm_email.text.erb
Normal file
@@ -0,0 +1,33 @@
|
||||
Dear Customer,
|
||||
|
||||
Please review and retain the following order information for your records.
|
||||
|
||||
============================================================
|
||||
Order Summary
|
||||
============================================================
|
||||
<% @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 %>
|
||||
============================================================
|
||||
Subtotal: <%= number_to_currency @order.item_total %>
|
||||
<% @order.adjustments.each do |adjustment| %>
|
||||
<%= raw(adjustment.label) %> <%= number_to_currency(adjustment.amount) %>
|
||||
<% end %>
|
||||
Order Total: <%= number_to_currency(@order.total) %>
|
||||
|
||||
============================================================
|
||||
Delivery Details
|
||||
============================================================
|
||||
Address:
|
||||
<%= @order.distributor.name %>
|
||||
<% address = @order.distributor.pickup_address %>
|
||||
<%= address.address1 %> <%= ",\n #{address.address2}" unless address.address2.blank? %>
|
||||
<%= [address.city, address.state_text, address.zipcode, address.country.name].compact.join ', ' %>
|
||||
Colection time:
|
||||
<%= @order.distributor.next_collection_at %>
|
||||
Contact:
|
||||
<%= @order.distributor.contact %>
|
||||
<%= "Phone: #{@order.distributor.phone}" %>
|
||||
<%= "Email: #{@order.distributor.email}" %>
|
||||
|
||||
Thank you for your business.
|
||||
8
app/views/spree/orders/_cart_item_description.html.haml
Normal file
8
app/views/spree/orders/_cart_item_description.html.haml
Normal file
@@ -0,0 +1,8 @@
|
||||
%td{'data-hook' => "cart_item_description"}
|
||||
%h4= link_to variant.product.name, product_path(variant.product)
|
||||
= variant.options_text
|
||||
- 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 => "...")
|
||||
23
app/views/spree/orders/_distributor_fees.html.haml
Normal file
23
app/views/spree/orders/_distributor_fees.html.haml
Normal file
@@ -0,0 +1,23 @@
|
||||
#delivery-fees
|
||||
%h2 Delivery Fees
|
||||
|
||||
%table#delivery
|
||||
%thead
|
||||
%tr
|
||||
%th Item
|
||||
%th Shipping Method
|
||||
%th Delivery Fee
|
||||
%tbody
|
||||
- @order.line_items.each do |line_item|
|
||||
- tr_class = cycle('', 'alt')
|
||||
%tr{:class => tr_class}
|
||||
%td
|
||||
%h4= link_to line_item.product.name, product_path(line_item.product)
|
||||
%td.item-shipping-method= line_item.shipping_method.name
|
||||
%td.item-shipping-cost= number_to_currency line_item.itemwise_shipping_cost
|
||||
|
||||
.subtotal{'data-hook' => 'delivery_fees_subtotal'}
|
||||
%h5
|
||||
Shipping total
|
||||
\:
|
||||
%span.order-total= order_delivery_fee_subtotal(@order)
|
||||
@@ -4,9 +4,17 @@
|
||||
|
||||
#subtotal{'data-hook' => ""}
|
||||
%h5
|
||||
= t(:subtotal)
|
||||
Item total
|
||||
\:
|
||||
%span.order-total= order_subtotal(@order)
|
||||
%span.order-total.item-total= number_to_currency @order.item_total
|
||||
%h5
|
||||
Shipping total
|
||||
\:
|
||||
%span.order-total.shipping-total= order_delivery_fee_subtotal(@order)
|
||||
%h4
|
||||
Total
|
||||
\:
|
||||
%span.order-total.grand-total= order_subtotal(@order)
|
||||
|
||||
.links{'data-hook' => "cart_buttons"}
|
||||
= button_tag :class => 'primary', :id => 'update-button' do
|
||||
|
||||
@@ -11,10 +11,13 @@
|
||||
- else
|
||||
%p 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(@product.distributors, "id", "name", current_distributor.andand.id)
|
||||
= select_tag "distributor_id", options_from_collection_for_select([Spree::Distributor.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}"
|
||||
|
||||
@@ -15,5 +15,5 @@
|
||||
= link_to distributor.name, root_path
|
||||
- else
|
||||
%span.inactive= distributor.name
|
||||
- if current_distributor && order.can_change_distributor?
|
||||
%li.nowrap= link_to 'Leave distributor', deselect_distributors_path
|
||||
- if current_distributor && order.can_change_distributor?
|
||||
= button_to 'Browse All Distributors', deselect_distributors_path, :method => :get
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
- if order.payment_method.type == "Spree::PaymentMethod::Check"
|
||||
= simple_format order.payment_method.description
|
||||
@@ -24,6 +24,13 @@ module Openfoodweb
|
||||
end
|
||||
end
|
||||
|
||||
# Register Spree calculators
|
||||
initializer "spree.register.calculators" do |app|
|
||||
app.config.spree.calculators.shipping_methods << OpenFoodWeb::Calculator::Itemwise
|
||||
app.config.spree.calculators.shipping_methods << OpenFoodWeb::Calculator::Weight
|
||||
end
|
||||
|
||||
|
||||
# Settings in config/environments/* take precedence over those specified here.
|
||||
# Application configuration should go into files in config/initializers
|
||||
# -- all .rb files in that directory are automatically loaded.
|
||||
@@ -57,5 +64,8 @@ module Openfoodweb
|
||||
|
||||
# Version of your assets, change this if you want to expire all your assets
|
||||
config.assets.version = '1.0'
|
||||
|
||||
config.assets.initialize_on_precompile = false
|
||||
config.assets.precompile += ['store/all.css', 'store/all.js', 'admin/all.css', 'admin/*.js', 'admin/**/*.js']
|
||||
end
|
||||
end
|
||||
|
||||
3
config/initializers/bugsnag.rb
Normal file
3
config/initializers/bugsnag.rb
Normal file
@@ -0,0 +1,3 @@
|
||||
Bugsnag.configure do |config|
|
||||
config.api_key = "937a200f492fad600b4cc29dddda5f71"
|
||||
end
|
||||
@@ -12,11 +12,17 @@ require 'open_food_web/searcher'
|
||||
|
||||
Spree.config do |config|
|
||||
config.site_name = "Open Food Web"
|
||||
config.logo = 'logo.jpg'
|
||||
config.admin_interface_logo = 'logo.jpg'
|
||||
|
||||
# config.shipping_instructions = true
|
||||
config.shipping_instructions = true
|
||||
config.checkout_zone = 'Australia'
|
||||
config.address_requires_state = true
|
||||
config.default_country_id = 12 # This should be Australia, see: spree/core/db/default/spree/countries.yml
|
||||
|
||||
config.searcher_class = OpenFoodWeb::Searcher
|
||||
|
||||
# -- spree_paypal_express
|
||||
# Auto-capture payments. Without this option, payments must be manually captured in the paypal interface.
|
||||
config.auto_capture = true
|
||||
end
|
||||
|
||||
@@ -12,7 +12,11 @@ Spree::Core::Engine.routes.prepend do
|
||||
end
|
||||
|
||||
namespace :admin do
|
||||
resources :distributors
|
||||
resources :distributors do
|
||||
post :bulk_update, :on => :collection, :as => :bulk_update
|
||||
end
|
||||
resources :suppliers
|
||||
end
|
||||
|
||||
match '/admin/reports/orders_and_distributors' => 'admin/reports#orders_and_distributors', :as => "orders_and_distributors_admin_reports", :via => [:get, :post]
|
||||
end
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
class RenameDistributorsProductsToProductDistributions < ActiveRecord::Migration
|
||||
def up
|
||||
# Convert m2m join table into explicit join model, and add a shipping method relation and timestamps
|
||||
rename_table :distributors_products, :product_distributions
|
||||
add_column :product_distributions, :id, :primary_key
|
||||
change_table :product_distributions do |t|
|
||||
t.references :shipping_method
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
# Set default shipping method on all product distributions
|
||||
sm = Spree::ShippingMethod.first
|
||||
Spree::ProductDistribution.update_all(:shipping_method_id => sm.id) if sm
|
||||
end
|
||||
|
||||
def down
|
||||
change_table :product_distributions do |t|
|
||||
t.remove :id
|
||||
t.remove :shipping_method_id
|
||||
t.remove :created_at, :updated_at
|
||||
end
|
||||
rename_table :product_distributions, :distributors_products
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,10 @@
|
||||
# This migration comes from spree (originally 20120507232704)
|
||||
class IncreaseScaleOfTaxRateAmount < ActiveRecord::Migration
|
||||
def up
|
||||
change_column :spree_tax_rates, :amount, :decimal, { :scale => 5, :precision => 8 }
|
||||
end
|
||||
|
||||
def down
|
||||
change_column :spree_tax_rates, :amount, :decimal, { :scale => 4, :precision => 8 }
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
# This migration comes from spree_auth (originally 20120203010234)
|
||||
class AddResetPasswordSentAtToSpreeUsers < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :spree_users, :reset_password_sent_at, :datetime
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
# This migration comes from spree_api (originally 20120411123334)
|
||||
class ResizeApiKeyField < ActiveRecord::Migration
|
||||
def change
|
||||
change_column :spree_users, :api_key, :string, :limit => 48
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,15 @@
|
||||
# This migration comes from spree_paypal_express (originally 20100224133156)
|
||||
class CreatePaypalAccounts < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :paypal_accounts do |t|
|
||||
t.string :email
|
||||
t.string :payer_id
|
||||
t.string :payer_country
|
||||
t.string :payer_status
|
||||
end
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :paypal_accounts
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
# This migration comes from spree_paypal_express (originally 20120117182027)
|
||||
class NamespacePaypalAccounts < ActiveRecord::Migration
|
||||
def change
|
||||
rename_table :paypal_accounts, :spree_paypal_accounts
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddNextCollectionAtToDistributors < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :distributors, :next_collection_at, :string
|
||||
end
|
||||
end
|
||||
6
db/migrate/20120802031147_add_group_buy_fields.rb
Normal file
6
db/migrate/20120802031147_add_group_buy_fields.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
class AddGroupBuyFields < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :spree_products, :group_buy, :boolean
|
||||
add_column :spree_line_items, :max_quantity, :integer
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,10 @@
|
||||
# This migration comes from spree (originally 20120523061241)
|
||||
class ConvertSalesTaxToDefaultTax < ActiveRecord::Migration
|
||||
def up
|
||||
execute "UPDATE spree_calculators SET type='Spree::Calculator::DefaultTax' WHERE type='Spree::Calculator::SalesTax'"
|
||||
end
|
||||
|
||||
def down
|
||||
execute "UPDATE spree_calculators SET type='Spree::Calculator::SalesTax' WHERE type='Spree::Calculator::DefaultTax'"
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
# This migration comes from spree (originally 20120604030249)
|
||||
class AddDeletedAtToSpreeShippingMethods < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :spree_shipping_methods, :deleted_at, :datetime
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,11 @@
|
||||
# This migration comes from spree (originally 20120605211305)
|
||||
class MakeUsersEmailIndexUnique < ActiveRecord::Migration
|
||||
def up
|
||||
add_index "spree_users", ["email"], :name => "email_idx_unique", :unique => true
|
||||
end
|
||||
|
||||
def down
|
||||
remove_index "spree_users", :name => "email_idx_unique"
|
||||
add_index "spree_users", ["email"], :name => "email_idx_unique"
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,15 @@
|
||||
# This migration comes from spree (originally 20120712172620)
|
||||
class AddCounterCacheToZoneMembers < ActiveRecord::Migration
|
||||
def up
|
||||
add_column :spree_zones, :zone_members_count, :integer, :default => 0
|
||||
|
||||
Spree::Zone.reset_column_information
|
||||
Spree::Zone.find(:all).each do |zone|
|
||||
Spree::Zone.update_counters zone.id, :zone_members_count => zone.zone_members.length
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
remove_column :spree_zones, :zone_members_count
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,20 @@
|
||||
class AddShippingMethodToLineItems < ActiveRecord::Migration
|
||||
def up
|
||||
add_column :spree_line_items, :shipping_method_id, :integer
|
||||
|
||||
Spree::LineItem.all.each do |li|
|
||||
begin
|
||||
shipping_method = li.product.shipping_method_for_distributor(li.order.distributor)
|
||||
rescue ArgumentError
|
||||
shipping_method = Spree::ShippingMethod.find_by_name 'Producer Delivery'
|
||||
say "Line item #{li.id} does not have a valid shipping method, setting to '#{shipping_method.name}'"
|
||||
end
|
||||
|
||||
Spree::LineItem.update_all("shipping_method_id = #{shipping_method.id}", "id = #{li.id}")
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
remove_column :spree_line_items, :shipping_method_id
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,10 @@
|
||||
class PopulateOrderDefaultShippingMethod < ActiveRecord::Migration
|
||||
def up
|
||||
Spree::Order.where(shipping_method_id: nil).each do |order|
|
||||
order.send(:set_default_shipping_method)
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
end
|
||||
end
|
||||
46
db/schema.rb
46
db/schema.rb
@@ -11,7 +11,7 @@
|
||||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 20120626013846) do
|
||||
ActiveRecord::Schema.define(:version => 20121005015852) do
|
||||
|
||||
create_table "distributors", :force => true do |t|
|
||||
t.string "name"
|
||||
@@ -26,11 +26,15 @@ ActiveRecord::Schema.define(:version => 20120626013846) do
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.integer "pickup_address_id"
|
||||
t.string "next_collection_at"
|
||||
end
|
||||
|
||||
create_table "distributors_products", :id => false, :force => true do |t|
|
||||
t.integer "product_id"
|
||||
t.integer "distributor_id"
|
||||
create_table "product_distributions", :force => true do |t|
|
||||
t.integer "product_id"
|
||||
t.integer "distributor_id"
|
||||
t.integer "shipping_method_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
create_table "spree_activators", :force => true do |t|
|
||||
@@ -129,7 +133,7 @@ ActiveRecord::Schema.define(:version => 20120626013846) do
|
||||
t.integer "numcode"
|
||||
end
|
||||
|
||||
create_table "spree_creditcards", :force => true do |t|
|
||||
create_table "spree_credit_cards", :force => true do |t|
|
||||
t.string "month"
|
||||
t.string "year"
|
||||
t.string "cc_type"
|
||||
@@ -140,8 +144,8 @@ ActiveRecord::Schema.define(:version => 20120626013846) do
|
||||
t.string "start_year"
|
||||
t.string "issue_number"
|
||||
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 "gateway_customer_profile_id"
|
||||
t.string "gateway_payment_profile_id"
|
||||
end
|
||||
@@ -176,10 +180,12 @@ ActiveRecord::Schema.define(:version => 20120626013846) do
|
||||
create_table "spree_line_items", :force => true do |t|
|
||||
t.integer "order_id"
|
||||
t.integer "variant_id"
|
||||
t.integer "quantity", :null => false
|
||||
t.decimal "price", :precision => 8, :scale => 2, :null => false
|
||||
t.integer "quantity", :null => false
|
||||
t.decimal "price", :precision => 8, :scale => 2, :null => false
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.integer "max_quantity"
|
||||
t.integer "shipping_method_id"
|
||||
end
|
||||
|
||||
add_index "spree_line_items", ["order_id"], :name => "index_line_items_on_order_id"
|
||||
@@ -279,6 +285,13 @@ ActiveRecord::Schema.define(:version => 20120626013846) do
|
||||
t.string "avs_response"
|
||||
end
|
||||
|
||||
create_table "spree_paypal_accounts", :force => true do |t|
|
||||
t.string "email"
|
||||
t.string "payer_id"
|
||||
t.string "payer_country"
|
||||
t.string "payer_status"
|
||||
end
|
||||
|
||||
create_table "spree_pending_promotions", :force => true do |t|
|
||||
t.integer "user_id"
|
||||
t.integer "promotion_id"
|
||||
@@ -355,6 +368,7 @@ ActiveRecord::Schema.define(:version => 20120626013846) do
|
||||
t.datetime "updated_at"
|
||||
t.integer "count_on_hand", :default => 0, :null => false
|
||||
t.integer "supplier_id"
|
||||
t.boolean "group_buy"
|
||||
end
|
||||
|
||||
add_index "spree_products", ["available_on"], :name => "index_products_on_available_on"
|
||||
@@ -481,6 +495,7 @@ ActiveRecord::Schema.define(:version => 20120626013846) do
|
||||
t.boolean "match_none"
|
||||
t.boolean "match_all"
|
||||
t.boolean "match_one"
|
||||
t.datetime "deleted_at"
|
||||
end
|
||||
|
||||
create_table "spree_skrill_transactions", :force => true do |t|
|
||||
@@ -521,7 +536,7 @@ ActiveRecord::Schema.define(:version => 20120626013846) do
|
||||
end
|
||||
|
||||
create_table "spree_tax_rates", :force => true do |t|
|
||||
t.decimal "amount", :precision => 8, :scale => 4
|
||||
t.decimal "amount", :precision => 8, :scale => 5
|
||||
t.integer "zone_id"
|
||||
t.integer "tax_category_id"
|
||||
t.datetime "created_at"
|
||||
@@ -582,8 +597,8 @@ ActiveRecord::Schema.define(:version => 20120626013846) do
|
||||
t.string "persistence_token"
|
||||
t.string "reset_password_token"
|
||||
t.string "perishable_token"
|
||||
t.integer "sign_in_count", :default => 0, :null => false
|
||||
t.integer "failed_attempts", :default => 0, :null => false
|
||||
t.integer "sign_in_count", :default => 0, :null => false
|
||||
t.integer "failed_attempts", :default => 0, :null => false
|
||||
t.datetime "last_request_at"
|
||||
t.datetime "current_sign_in_at"
|
||||
t.datetime "last_sign_in_at"
|
||||
@@ -598,9 +613,11 @@ ActiveRecord::Schema.define(:version => 20120626013846) do
|
||||
t.string "unlock_token"
|
||||
t.datetime "locked_at"
|
||||
t.datetime "remember_created_at"
|
||||
t.string "api_key", :limit => 40
|
||||
t.string "api_key", :limit => 48
|
||||
t.datetime "reset_password_sent_at"
|
||||
end
|
||||
|
||||
add_index "spree_users", ["email"], :name => "email_idx_unique", :unique => true
|
||||
add_index "spree_users", ["persistence_token"], :name => "index_users_on_persistence_token"
|
||||
|
||||
create_table "spree_variants", :force => true do |t|
|
||||
@@ -633,7 +650,8 @@ ActiveRecord::Schema.define(:version => 20120626013846) do
|
||||
t.string "description"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.boolean "default_tax", :default => false
|
||||
t.boolean "default_tax", :default => false
|
||||
t.integer "zone_members_count", :default => 0
|
||||
end
|
||||
|
||||
create_table "suppliers", :force => true do |t|
|
||||
|
||||
@@ -37,13 +37,13 @@ end
|
||||
|
||||
|
||||
# -- Shipping / payment information
|
||||
unless Spree::Zone.count > 0
|
||||
unless Spree::Zone.find_by_name 'Australia'
|
||||
puts "[db:seed] Seeding shipping / payment information"
|
||||
zone = FactoryGirl.create(:zone)
|
||||
zone = FactoryGirl.create(:zone, :name => 'Australia', :zone_members => [])
|
||||
country = Spree::Country.find_by_name('Australia')
|
||||
Spree::ZoneMember.create(:zoneable => country, :zone => zone)
|
||||
Spree::ZoneMember.create(:zone => zone, :zoneable => country)
|
||||
FactoryGirl.create(:shipping_method, :zone => zone)
|
||||
FactoryGirl.create(:payment_method)
|
||||
FactoryGirl.create(:payment_method, :environment => 'development')
|
||||
end
|
||||
|
||||
|
||||
|
||||
31
lib/open_food_web/order_and_distributor_report.rb
Normal file
31
lib/open_food_web/order_and_distributor_report.rb
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
module OpenFoodWeb
|
||||
class OrderAndDistributorReport
|
||||
|
||||
def initialize orders
|
||||
@orders = orders
|
||||
end
|
||||
|
||||
def header
|
||||
["Order date", "Order Id",
|
||||
"Customer Name","Customer Email", "Customer Phone", "Customer City",
|
||||
"SKU", "Item name", "Variant", "Quantity", "Max Quantity", "Cost", "Shipping cost",
|
||||
"Payment method",
|
||||
"Distributor", "Distributor address", "Distributor city", "Distributor postcode", "Shipping instructions"]
|
||||
end
|
||||
|
||||
def table
|
||||
order_and_distributor_details = []
|
||||
@orders.each do |order|
|
||||
order.line_items.each do |line_item|
|
||||
order_and_distributor_details << [order.created_at, order.id,
|
||||
order.bill_address.full_name, order.email, order.bill_address.phone, order.bill_address.city,
|
||||
line_item.product.sku, line_item.product.name, line_item.variant.options_text, line_item.quantity, line_item.max_quantity, line_item.price * line_item.quantity, line_item.itemwise_shipping_cost,
|
||||
order.payments.first.payment_method.andand.name,
|
||||
order.distributor.andand.name, order.distributor.pickup_address.address1, order.distributor.pickup_address.city, order.distributor.pickup_address.zipcode, order.special_instructions ]
|
||||
end
|
||||
end
|
||||
order_and_distributor_details
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -3,6 +3,14 @@ require 'spree/core/search/base'
|
||||
module OpenFoodWeb
|
||||
class Searcher < Spree::Core::Search::Base
|
||||
|
||||
# Do not perform pagination
|
||||
def retrieve_products
|
||||
@products_scope = get_base_scope
|
||||
curr_page = page || 1
|
||||
|
||||
@products = @products_scope.includes([:master])
|
||||
end
|
||||
|
||||
def get_base_scope
|
||||
base_scope = super
|
||||
|
||||
|
||||
@@ -4,9 +4,11 @@ require 'spree/core/current_order'
|
||||
describe Spree::DistributorsController do
|
||||
include Spree::Core::CurrentOrder
|
||||
|
||||
before do
|
||||
before :each do
|
||||
stub!(:before_save_new_order)
|
||||
stub!(:after_save_new_order)
|
||||
|
||||
create(:itemwise_shipping_method)
|
||||
end
|
||||
|
||||
|
||||
@@ -40,9 +42,10 @@ describe Spree::DistributorsController do
|
||||
d2 = create(:distributor)
|
||||
p = create(:product, :distributors => [d1])
|
||||
o = current_order(true)
|
||||
|
||||
o.distributor = d1
|
||||
o.add_variant(p.master, 1)
|
||||
o.save!
|
||||
o.add_variant(p.master, 1)
|
||||
|
||||
# When I attempt to select a distributor
|
||||
spree_get :select, :id => d2.id
|
||||
@@ -58,8 +61,8 @@ describe Spree::DistributorsController do
|
||||
p = create(:product, :distributors => [d])
|
||||
o = current_order(true)
|
||||
o.distributor = d
|
||||
o.add_variant(p.master, 1)
|
||||
o.save!
|
||||
o.add_variant(p.master, 1)
|
||||
|
||||
# When I attempt to deselect the distributor
|
||||
spree_get :deselect
|
||||
|
||||
@@ -25,4 +25,39 @@ describe Spree::HomeController do
|
||||
assigns(:products_local).should == [p1]
|
||||
assigns(:products_remote).should == [p2]
|
||||
end
|
||||
|
||||
context "BaseController: merging incomplete orders" do
|
||||
it "does not attempt to merge incomplete and current orders when they have differing distributors" do
|
||||
incomplete_order = double(:order, distributor: 1)
|
||||
current_order = double(:order, distributor: 2)
|
||||
|
||||
user = double(:user, last_incomplete_order: incomplete_order)
|
||||
controller.stub(:current_user).and_return(user)
|
||||
controller.stub(:current_order).and_return(current_order)
|
||||
|
||||
incomplete_order.should_receive(:destroy)
|
||||
incomplete_order.should_receive(:merge!).never
|
||||
current_order.should_receive(:merge!).never
|
||||
|
||||
session[:order_id] = 123
|
||||
|
||||
spree_get :index
|
||||
end
|
||||
|
||||
it "sets the distributor when the target order has no distributor" do
|
||||
incomplete_order = double(:order, distributor: 1)
|
||||
current_order = double(:order, distributor: nil)
|
||||
|
||||
user = double(:user, last_incomplete_order: incomplete_order)
|
||||
controller.stub(:current_user).and_return(user)
|
||||
controller.stub(:current_order).and_return(current_order)
|
||||
|
||||
current_order.should_receive(:set_distributor!).with(1)
|
||||
current_order.should_receive(:merge!)
|
||||
|
||||
session[:order_id] = 123
|
||||
|
||||
spree_get :index
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -15,7 +15,7 @@ describe Spree::OrdersController do
|
||||
p = create(:product)
|
||||
|
||||
expect do
|
||||
spree_put :populate, :variants => {p.id => 1}
|
||||
spree_post :populate, :variants => {p.master.id => 1}
|
||||
end.to change(Spree::LineItem, :count).by(0)
|
||||
end
|
||||
|
||||
@@ -25,7 +25,7 @@ describe Spree::OrdersController do
|
||||
p = create(:product, :distributors => [distributor_product])
|
||||
|
||||
expect do
|
||||
spree_put :populate, :variants => {p.id => 1}, :distributor_id => distributor_no_product.id
|
||||
spree_post :populate, :variants => {p.master.id => 1}, :distributor_id => distributor_no_product.id
|
||||
end.to change(Spree::LineItem, :count).by(0)
|
||||
end
|
||||
|
||||
@@ -39,7 +39,7 @@ describe Spree::OrdersController do
|
||||
order.save!
|
||||
|
||||
expect do
|
||||
spree_put :populate, :variants => {p.id => 1}, :distributor_id => distributor_product.id
|
||||
spree_post :populate, :variants => {p.master.id => 1}, :distributor_id => distributor_product.id
|
||||
end.to change(Spree::LineItem, :count).by(1)
|
||||
|
||||
order.reload.distributor.should == distributor_product
|
||||
@@ -51,7 +51,7 @@ describe Spree::OrdersController do
|
||||
p = create(:product, :distributors => [d])
|
||||
|
||||
# When we add the product to our cart
|
||||
spree_put :populate, :variants => {p.id => 1}, :distributor_id => d.id
|
||||
spree_post :populate, :variants => {p.master.id => 1}, :distributor_id => d.id
|
||||
|
||||
# Then our order should have its distributor set to the chosen distributor
|
||||
current_order(false).distributor.should == d
|
||||
@@ -65,7 +65,7 @@ describe Spree::OrdersController do
|
||||
@product = create(:product, :distributors => [@distributor])
|
||||
|
||||
# And the product is in the cart
|
||||
spree_put :populate, :variants => {@product.id => 1}, :distributor_id => @distributor.id
|
||||
spree_post :populate, :variants => {@product.master.id => 1}, :distributor_id => @distributor.id
|
||||
current_order(false).line_items.reload.map { |li| li.product }.should == [@product]
|
||||
current_order(false).distributor.reload.should == @distributor
|
||||
end
|
||||
@@ -76,7 +76,7 @@ describe Spree::OrdersController do
|
||||
p2 = create(:product, :distributors => [d2])
|
||||
|
||||
# When I attempt to add the product to the cart
|
||||
spree_put :populate, :variants => {p2.id => 1}, :distributor_id => d2.id
|
||||
spree_post :populate, :variants => {p2.master.id => 1}, :distributor_id => d2.id
|
||||
|
||||
# Then the product should not be added to the cart
|
||||
current_order(false).line_items.reload.map { |li| li.product }.should == [@product]
|
||||
@@ -89,7 +89,7 @@ describe Spree::OrdersController do
|
||||
p2 = create(:product, :distributors => [d2])
|
||||
|
||||
# When I attempt to add the product to the cart with a fake distributor_id
|
||||
spree_put :populate, :variants => {p2.id => 1}, :distributor_id => @distributor.id
|
||||
spree_post :populate, :variants => {p2.master.id => 1}, :distributor_id => @distributor.id
|
||||
|
||||
# Then the product should not be added to the cart
|
||||
current_order(false).line_items.reload.map { |li| li.product }.should == [@product]
|
||||
@@ -102,11 +102,26 @@ describe Spree::OrdersController do
|
||||
p2 = create(:product, :distributors => [@distributor, d2])
|
||||
|
||||
# When I attempt to add the product to the cart with the alternate distributor
|
||||
spree_put :populate, :variants => {p2.id => 1}, :distributor_id => d2
|
||||
spree_post :populate, :variants => {p2.master.id => 1}, :distributor_id => d2
|
||||
|
||||
# Then the product should not be added to the cart
|
||||
current_order(false).line_items.reload.map { |li| li.product }.should == [@product]
|
||||
current_order(false).distributor.reload.should == @distributor
|
||||
end
|
||||
end
|
||||
|
||||
context "adding a group buy product to the cart" do
|
||||
it "sets a variant attribute for the max quantity" do
|
||||
distributor_product = create(:distributor)
|
||||
p = create(:product, :distributors => [distributor_product], :group_buy => true)
|
||||
|
||||
order = current_order(true)
|
||||
order.should_receive(:set_variant_attributes).with(p.master, {'max_quantity' => '3'})
|
||||
controller.stub(:current_order).and_return(order)
|
||||
|
||||
expect do
|
||||
spree_post :populate, :variants => {p.master.id => 1}, :variant_attributes => {p.master.id => {:max_quantity => 3}}, :distributor_id => distributor_product.id
|
||||
end.to change(Spree::LineItem, :count).by(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -10,21 +10,67 @@ FactoryGirl.define do
|
||||
end
|
||||
|
||||
factory :distributor, :class => Spree::Distributor do
|
||||
sequence(:name) { |n| "Distributor #{n}" }
|
||||
contact "Mr Turing"
|
||||
phone "1000100100"
|
||||
description 'The creator'
|
||||
email 'alan@somewhere.com'
|
||||
url 'http://example.com'
|
||||
pickup_times "Whenever you're free"
|
||||
pickup_address { Spree::Address.first || FactoryGirl.create(:address) }
|
||||
sequence(:name) { |n| "Distributor #{n}" }
|
||||
contact 'Mr Turing'
|
||||
phone '1000100100'
|
||||
description 'The creator'
|
||||
email 'alan@somewhere.com'
|
||||
url 'http://example.com'
|
||||
pickup_times "Whenever you're free"
|
||||
next_collection_at 'Thursday 10am'
|
||||
pickup_address { Spree::Address.first || FactoryGirl.create(:address) }
|
||||
end
|
||||
|
||||
factory :product_distribution, :class => Spree::ProductDistribution do
|
||||
product { |pd| Spree::Product.first || FactoryGirl.create(:product) }
|
||||
distributor { |pd| Spree::Distributor.first || FactoryGirl.create(:distributor) }
|
||||
shipping_method { |pd| Spree::ShippingMethod.where("name != 'Delivery'").first || FactoryGirl.create(:shipping_method) }
|
||||
end
|
||||
|
||||
factory :itemwise_shipping_method, :parent => :shipping_method do
|
||||
name 'Delivery'
|
||||
calculator { FactoryGirl.build(:itemwise_calculator) }
|
||||
end
|
||||
|
||||
factory :itemwise_calculator, :class => OpenFoodWeb::Calculator::Itemwise do
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
FactoryGirl.modify do
|
||||
factory :simple_product do
|
||||
# Fix product factory name sequence with Kernel.rand so it is not interpreted as a Spree::Product method
|
||||
# Pull request: https://github.com/spree/spree/pull/1964
|
||||
# When this fix has been merged into a version of Spree that we're using, this line can be removed.
|
||||
sequence(:name) { |n| "Product ##{n} - #{Kernel.rand(9999)}" }
|
||||
|
||||
supplier { Spree::Supplier.first || FactoryGirl.create(:supplier) }
|
||||
distributors { [Spree::Distributor.first || FactoryGirl.create(:distributor)] }
|
||||
on_hand 3
|
||||
|
||||
# before(:create) do |product, evaluator|
|
||||
# product.product_distributions = [FactoryGirl.create(:product_distribution, :product => product)]
|
||||
# end
|
||||
|
||||
# Do not create products distributed via the 'Delivery' shipping method
|
||||
after(:create) do |product, evaluator|
|
||||
pd = product.product_distributions.first
|
||||
if pd.andand.shipping_method.andand.name == 'Delivery'
|
||||
pd.shipping_method = Spree::ShippingMethod.where("name != 'Delivery'").first || FactoryGirl.create(:shipping_method)
|
||||
pd.save!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
factory :line_item do
|
||||
shipping_method { |li| li.product.shipping_method_for_distributor(li.order.distributor) }
|
||||
end
|
||||
|
||||
factory :shipping_method do
|
||||
display_on ''
|
||||
end
|
||||
|
||||
factory :address do
|
||||
state { Spree::State.find_by_name 'Victoria' }
|
||||
country { Spree::Country.find_by_name 'Australia' || Spree::Country.first }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,7 +11,7 @@ module Spree
|
||||
|
||||
it "displays variant price differences as absolute, not relative values" do
|
||||
variant = make_variant_stub(10.00, 10.00)
|
||||
subject.variant_price_diff(variant).should be_nil
|
||||
subject.variant_price_diff(variant).should == "($10.00)"
|
||||
|
||||
variant = make_variant_stub(10.00, 15.55)
|
||||
subject.variant_price_diff(variant).should == "($15.55)"
|
||||
|
||||
51
spec/lib/open_food_web/order_and_distributor_report_spec.rb
Normal file
51
spec/lib/open_food_web/order_and_distributor_report_spec.rb
Normal file
@@ -0,0 +1,51 @@
|
||||
require 'spec_helper'
|
||||
|
||||
|
||||
module OpenFoodWeb
|
||||
describe OrderAndDistributorReport do
|
||||
|
||||
describe "orders and distributors report" do
|
||||
|
||||
before(:each) do
|
||||
@bill_address = create(:address)
|
||||
@distributor_address = create(:address, :address1 => "distributor address", :city => 'The Shire', :zipcode => "1234")
|
||||
@distributor = create(:distributor, :pickup_address => @distributor_address)
|
||||
product = create(:product)
|
||||
product_distribution = create(:product_distribution, :product => product, :distributor => @distributor, :shipping_method => create(:shipping_method))
|
||||
@shipping_instructions = "pick up on thursday please!"
|
||||
@order = create(:order, :distributor => @distributor, :bill_address => @bill_address, :special_instructions => @shipping_instructions)
|
||||
@payment_method = create(:payment_method)
|
||||
payment = create(:payment, :payment_method => @payment_method, :order => @order )
|
||||
@order.payments << payment
|
||||
@line_item = create(:line_item, :product => product, :order => @order)
|
||||
@order.line_items << @line_item
|
||||
end
|
||||
|
||||
it "should return a header row describing the report" do
|
||||
subject = OrderAndDistributorReport.new [@order]
|
||||
|
||||
header = subject.header
|
||||
header.should == ["Order date", "Order Id",
|
||||
"Customer Name","Customer Email", "Customer Phone", "Customer City",
|
||||
"SKU", "Item name", "Variant", "Quantity", "Max Quantity", "Cost", "Shipping cost",
|
||||
"Payment method",
|
||||
"Distributor", "Distributor address", "Distributor city", "Distributor postcode", "Shipping instructions"]
|
||||
end
|
||||
|
||||
it "should denormalise order and distributor details for display as csv" do
|
||||
subject = OrderAndDistributorReport.new [@order]
|
||||
|
||||
table = subject.table
|
||||
|
||||
table[0].should == [@order.created_at, @order.id,
|
||||
@bill_address.full_name, @order.email, @bill_address.phone, @bill_address.city,
|
||||
@line_item.product.sku, @line_item.product.name, @line_item.variant.options_text, @line_item.quantity, @line_item.max_quantity, @line_item.price * @line_item.quantity, @line_item.itemwise_shipping_cost,
|
||||
@payment_method.name,
|
||||
@distributor.name, @distributor.pickup_address.address1, @distributor.pickup_address.city, @distributor.pickup_address.zipcode, @shipping_instructions ]
|
||||
end
|
||||
|
||||
it "should include breakdown an order into each line item"
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
20
spec/models/calculator/itemwise_spec.rb
Normal file
20
spec/models/calculator/itemwise_spec.rb
Normal file
@@ -0,0 +1,20 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe OpenFoodWeb::Calculator::Itemwise do
|
||||
it "computes the shipping cost for each line item in an order" do
|
||||
line_item = double(:line_item)
|
||||
line_item.should_receive(:itemwise_shipping_cost).exactly(3).times.and_return(10)
|
||||
|
||||
order = double(:order)
|
||||
order.stub(:line_items).and_return([line_item]*3)
|
||||
|
||||
subject.compute(order).should == 30
|
||||
end
|
||||
|
||||
it "returns zero for an order with no items" do
|
||||
order = double(:order)
|
||||
order.stub(:line_items).and_return([])
|
||||
|
||||
subject.compute(order).should == 0
|
||||
end
|
||||
end
|
||||
18
spec/models/calculator/weight_spec.rb
Normal file
18
spec/models/calculator/weight_spec.rb
Normal file
@@ -0,0 +1,18 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe OpenFoodWeb::Calculator::Weight do
|
||||
it "computes shipping cost for an order by total weight" do
|
||||
variant_1 = double(:variant, :weight => 10)
|
||||
variant_2 = double(:variant, :weight => 20)
|
||||
variant_3 = double(:variant, :weight => nil)
|
||||
|
||||
line_item_1 = double(:line_item, :variant => variant_1, :quantity => 1)
|
||||
line_item_2 = double(:line_item, :variant => variant_2, :quantity => 3)
|
||||
line_item_3 = double(:line_item, :variant => variant_3, :quantity => 5)
|
||||
|
||||
order = double(:order, :line_items => [line_item_1, line_item_2, line_item_3])
|
||||
|
||||
subject.set_preference(:per_kg, 10)
|
||||
subject.compute(order).should == (10*1 + 20*3) * 10
|
||||
end
|
||||
end
|
||||
@@ -5,17 +5,32 @@ module Spree
|
||||
|
||||
describe "associations" do
|
||||
it { should belong_to(:pickup_address) }
|
||||
it { should have_and_belong_to_many(:products) }
|
||||
it { should have_many(:product_distributions) }
|
||||
it { should have_many(:orders) }
|
||||
end
|
||||
|
||||
describe "validations" do
|
||||
it { should validate_presence_of(:name) }
|
||||
end
|
||||
|
||||
it "should default country to system country" do
|
||||
distributor = Distributor.new
|
||||
distributor.pickup_address.country.should == Country.find_by_id(Config[:default_country_id])
|
||||
end
|
||||
|
||||
describe "validations" do
|
||||
it { should validate_presence_of(:name) }
|
||||
describe "scopes" do
|
||||
it "returns distributors with products in stock" do
|
||||
d1 = create(:distributor)
|
||||
d2 = create(:distributor)
|
||||
d3 = create(:distributor)
|
||||
d4 = create(:distributor)
|
||||
create(:product, :distributors => [d1, d2], :on_hand => 5)
|
||||
create(:product, :distributors => [d1], :on_hand => 5)
|
||||
create(:product, :distributors => [d3], :on_hand => 0)
|
||||
|
||||
Distributor.with_active_products_on_hand.sort.should == [d1, d2]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
18
spec/models/line_item_spec.rb
Normal file
18
spec/models/line_item_spec.rb
Normal file
@@ -0,0 +1,18 @@
|
||||
require 'spec_helper'
|
||||
|
||||
module Spree
|
||||
describe LineItem do
|
||||
it "computes shipping cost for its product" do
|
||||
# Create a shipping method with flat rate of 10
|
||||
shipping_method = create(:shipping_method)
|
||||
shipping_method.calculator.set_preference :amount, 10
|
||||
|
||||
order = double(:order, :distributor => nil)
|
||||
|
||||
subject.stub(:shipping_method).and_return(shipping_method)
|
||||
subject.stub(:order).and_return(order)
|
||||
|
||||
subject.itemwise_shipping_cost.should == 10
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,8 +1,25 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Spree::Order do
|
||||
it "initialises a default shipping method after creation" do
|
||||
shipping_method_back_end = create(:shipping_method, :display_on => :back_end)
|
||||
shipping_method_both = create(:shipping_method, :display_on => :both)
|
||||
|
||||
subject.shipping_method.should be_nil
|
||||
subject.adjustments.should be_empty
|
||||
|
||||
subject.save!
|
||||
|
||||
subject.shipping_method.should == shipping_method_both
|
||||
subject.adjustments.where(:label => "Shipping").should be_present
|
||||
end
|
||||
|
||||
it "reveals permission for changing distributor" do
|
||||
p = build(:product)
|
||||
d = create(:distributor)
|
||||
p = create(:product, :distributors => [d])
|
||||
|
||||
subject.distributor = d
|
||||
subject.save!
|
||||
|
||||
subject.can_change_distributor?.should be_true
|
||||
subject.add_variant(p.master, 1)
|
||||
@@ -10,9 +27,11 @@ describe Spree::Order do
|
||||
end
|
||||
|
||||
it "raises an exception if distributor is changed without permission" do
|
||||
d = build(:distributor)
|
||||
p = build(:product, :distributors => [d])
|
||||
d = create(:distributor)
|
||||
p = create(:product, :distributors => [d])
|
||||
subject.distributor = d
|
||||
subject.save!
|
||||
|
||||
subject.add_variant(p.master, 1)
|
||||
subject.can_change_distributor?.should be_false
|
||||
|
||||
@@ -46,4 +65,18 @@ describe Spree::Order do
|
||||
# And cannot be added if it does not match
|
||||
subject.can_add_product_to_cart?(p_subsequent_other_dist).should be_false
|
||||
end
|
||||
|
||||
it "sets attributes on line items for variants" do
|
||||
d = create(:distributor)
|
||||
p = create(:product, :distributors => [d])
|
||||
|
||||
subject.distributor = d
|
||||
subject.save!
|
||||
|
||||
subject.add_variant(p.master, 1)
|
||||
subject.set_variant_attributes(p.master, {'max_quantity' => '3'})
|
||||
|
||||
li = Spree::LineItem.last
|
||||
li.max_quantity.should == 3
|
||||
end
|
||||
end
|
||||
|
||||
23
spec/models/product_distribution_spec.rb
Normal file
23
spec/models/product_distribution_spec.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Spree::ProductDistribution do
|
||||
it "is unique for scope [product, distributor]" do
|
||||
pd1 = create(:product_distribution)
|
||||
pd1.should be_valid
|
||||
|
||||
new_product = create(:product)
|
||||
new_distributor = create(:distributor)
|
||||
|
||||
pd2 = build(:product_distribution, :product => pd1.product, :distributor => pd1.distributor)
|
||||
pd2.should_not be_valid
|
||||
|
||||
pd2 = build(:product_distribution, :product => pd1.product, :distributor => new_distributor)
|
||||
pd2.should be_valid
|
||||
|
||||
pd2 = build(:product_distribution, :product => new_product, :distributor => pd1.distributor)
|
||||
pd2.should be_valid
|
||||
|
||||
pd2 = build(:product_distribution, :product => new_product, :distributor => new_distributor)
|
||||
pd2.should be_valid
|
||||
end
|
||||
end
|
||||
@@ -4,25 +4,36 @@ describe Spree::Product do
|
||||
|
||||
describe "associations" do
|
||||
it { should belong_to(:supplier) }
|
||||
it { should have_and_belong_to_many(:distributors) }
|
||||
it { should have_many(:product_distributions) }
|
||||
end
|
||||
|
||||
describe "validations" do
|
||||
it "is valid when created from factory" do
|
||||
build(:product).should be_valid
|
||||
create(:product).should be_valid
|
||||
end
|
||||
|
||||
it "requires a supplier" do
|
||||
product = build(:product)
|
||||
product = create(:product)
|
||||
product.supplier = nil
|
||||
product.should_not be_valid
|
||||
end
|
||||
|
||||
it "requires at least one distributor" do
|
||||
product = build(:product)
|
||||
product.distributors.clear
|
||||
product.should_not be_valid
|
||||
end
|
||||
end
|
||||
|
||||
context "finders" do
|
||||
it "finds the shipping method for a particular distributor" do
|
||||
shipping_method = create(:shipping_method)
|
||||
distributor = create(:distributor)
|
||||
product = create(:product)
|
||||
product_distribution = create(:product_distribution, :product => product, :distributor => distributor, :shipping_method => shipping_method)
|
||||
product.shipping_method_for_distributor(distributor).should == shipping_method
|
||||
end
|
||||
|
||||
it "raises an error if distributor is not found" do
|
||||
distributor = create(:distributor)
|
||||
product = create(:product)
|
||||
expect do
|
||||
product.shipping_method_for_distributor(distributor)
|
||||
end.to raise_error "This product is not available through that distributor"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,33 +8,53 @@ feature %q{
|
||||
include WebHelper
|
||||
|
||||
|
||||
context "setting up distributors" do
|
||||
scenario "creating a new distributor" do
|
||||
login_to_admin_section
|
||||
scenario "creating a new distributor" do
|
||||
login_to_admin_section
|
||||
|
||||
click_link 'Distributors'
|
||||
click_link 'New Distributor'
|
||||
click_link 'Distributors'
|
||||
click_link 'New Distributor'
|
||||
|
||||
fill_in 'distributor_name', :with => 'Eaterprises'
|
||||
fill_in 'distributor_description', :with => 'Connecting farmers and eaters'
|
||||
fill_in 'distributor_contact', :with => 'Kirsten or Ren'
|
||||
fill_in 'distributor_phone', :with => '0413 897 321'
|
||||
fill_in 'distributor_name', :with => 'Eaterprises'
|
||||
fill_in 'distributor_description', :with => 'Connecting farmers and eaters'
|
||||
fill_in 'distributor_contact', :with => 'Kirsten or Ren'
|
||||
fill_in 'distributor_phone', :with => '0413 897 321'
|
||||
|
||||
fill_in 'distributor_pickup_address_attributes_address1', :with => '35 Ballantyne St'
|
||||
fill_in 'distributor_pickup_address_attributes_city', :with => 'Thornbury'
|
||||
fill_in 'distributor_pickup_address_attributes_zipcode', :with => '3072'
|
||||
select('Australia', :from => 'distributor_pickup_address_attributes_country_id')
|
||||
select('Victoria', :from => 'distributor_pickup_address_attributes_state_id')
|
||||
fill_in 'distributor_pickup_address_attributes_address1', :with => '35 Ballantyne St'
|
||||
fill_in 'distributor_pickup_address_attributes_city', :with => 'Thornbury'
|
||||
fill_in 'distributor_pickup_address_attributes_zipcode', :with => '3072'
|
||||
select('Australia', :from => 'distributor_pickup_address_attributes_country_id')
|
||||
select('Victoria', :from => 'distributor_pickup_address_attributes_state_id')
|
||||
|
||||
fill_in 'distributor_pickup_times', :with => 'Thursday, 22nd Feb, 6 - 9 PM. Friday, 23nd Feb, 6 - 9 PM'
|
||||
fill_in 'distributor_email', :with => 'info@eaterprises.com.au'
|
||||
fill_in 'distributor_url', :with => 'http://eaterprises.com.au'
|
||||
fill_in 'distributor_abn', :with => '09812309823'
|
||||
fill_in 'distributor_acn', :with => ''
|
||||
fill_in 'distributor_next_collection_at', :with => 'Thursday, 22nd Feb, 6 - 9 PM'
|
||||
fill_in 'distributor_pickup_times', :with => 'Thursday, 22nd Feb, 6 - 9 PM. Friday, 23nd Feb, 6 - 9 PM'
|
||||
fill_in 'distributor_email', :with => 'info@eaterprises.com.au'
|
||||
fill_in 'distributor_url', :with => 'http://eaterprises.com.au'
|
||||
fill_in 'distributor_abn', :with => '09812309823'
|
||||
fill_in 'distributor_acn', :with => ''
|
||||
|
||||
click_button 'Create'
|
||||
click_button 'Create'
|
||||
|
||||
flash_message.should == 'Distributor "Eaterprises" has been successfully created!'
|
||||
end
|
||||
flash_message.should == 'Distributor "Eaterprises" has been successfully created!'
|
||||
end
|
||||
|
||||
|
||||
scenario "updating many distributor next collection times at once" do
|
||||
# Given three distributors
|
||||
3.times { create(:distributor) }
|
||||
|
||||
# When I go to the distributors page
|
||||
login_to_admin_section
|
||||
click_link 'Distributors'
|
||||
|
||||
# And I fill in some new collection times and save them
|
||||
fill_in 'distributor_set_distributors_attributes_0_next_collection_at', :with => 'One'
|
||||
fill_in 'distributor_set_distributors_attributes_1_next_collection_at', :with => 'Two'
|
||||
fill_in 'distributor_set_distributors_attributes_2_next_collection_at', :with => 'Three'
|
||||
click_button 'Update'
|
||||
|
||||
# Then my times should have been saved
|
||||
flash_message.should == 'Distributor collection times updated.'
|
||||
Spree::Distributor.all.map { |d| d.next_collection_at }.should == %w(One Two Three)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -10,10 +10,11 @@ feature %q{
|
||||
background do
|
||||
@supplier = create(:supplier, :name => 'New supplier')
|
||||
@distributors = (1..3).map { create(:distributor) }
|
||||
@shipping_method = create(:shipping_method, :name => 'My shipping method')
|
||||
end
|
||||
|
||||
context "creating a product" do
|
||||
scenario "I should be able to assign a supplier to the product" do
|
||||
scenario "assigning a supplier and distributors to the product" do
|
||||
login_to_admin_section
|
||||
|
||||
click_link 'Products'
|
||||
@@ -22,8 +23,11 @@ feature %q{
|
||||
fill_in 'product_name', :with => 'A new product !!!'
|
||||
fill_in 'product_price', :with => '19.99'
|
||||
select 'New supplier', :from => 'product_supplier_id'
|
||||
|
||||
check @distributors[0].name
|
||||
select 'My shipping method', :from => 'product_product_distributions_attributes_0_shipping_method_id'
|
||||
check @distributors[2].name
|
||||
select 'My shipping method', :from => 'product_product_distributions_attributes_2_shipping_method_id'
|
||||
|
||||
click_button 'Create'
|
||||
|
||||
@@ -31,8 +35,27 @@ feature %q{
|
||||
product = Spree::Product.find_by_name('A new product !!!')
|
||||
product.supplier.should == @supplier
|
||||
product.distributors.should == [@distributors[0], @distributors[2]]
|
||||
product.product_distributions.map { |pd| pd.shipping_method }.should == [@shipping_method, @shipping_method]
|
||||
product.group_buy.should be_false
|
||||
end
|
||||
end
|
||||
|
||||
context "Given I am cloning a Product"
|
||||
scenario "making a group buy product" do
|
||||
login_to_admin_section
|
||||
|
||||
click_link 'Products'
|
||||
click_link 'New Product'
|
||||
|
||||
fill_in 'product_name', :with => 'A new product !!!'
|
||||
fill_in 'product_price', :with => '19.99'
|
||||
select 'New supplier', :from => 'product_supplier_id'
|
||||
choose 'product_group_buy_1'
|
||||
|
||||
click_button 'Create'
|
||||
|
||||
flash_message.should == 'Product "A new product !!!" has been successfully created!'
|
||||
product = Spree::Product.find_by_name('A new product !!!')
|
||||
product.group_buy.should be_true
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
58
spec/requests/admin/shipping_methods_spec.rb
Normal file
58
spec/requests/admin/shipping_methods_spec.rb
Normal file
@@ -0,0 +1,58 @@
|
||||
require 'spec_helper'
|
||||
|
||||
feature 'shipping methods' do
|
||||
include AuthenticationWorkflow
|
||||
include WebHelper
|
||||
|
||||
before :each do
|
||||
login_to_admin_section
|
||||
@sm = create(:shipping_method)
|
||||
end
|
||||
|
||||
scenario "deleting a shipping method" do
|
||||
visit_delete spree.admin_shipping_method_path(@sm)
|
||||
|
||||
page.should have_content "Shipping method \"#{@sm.name}\" has been successfully removed!"
|
||||
Spree::ShippingMethod.where(:id => @sm.id).should be_empty
|
||||
end
|
||||
|
||||
scenario "deleting a shipping method referenced by an order" do
|
||||
o = create(:order, shipping_method: @sm)
|
||||
|
||||
visit_delete spree.admin_shipping_method_path(@sm)
|
||||
|
||||
page.should have_content "That shipping method cannot be deleted as it is referenced by an order: #{o.number}."
|
||||
Spree::ShippingMethod.find(@sm.id).should_not be_nil
|
||||
end
|
||||
|
||||
scenario "deleting a shipping method referenced by a product distribution" do
|
||||
p = create(:product)
|
||||
d = create(:distributor)
|
||||
create(:product_distribution, product: p, distributor: d, shipping_method: @sm)
|
||||
|
||||
visit_delete spree.admin_shipping_method_path(@sm)
|
||||
|
||||
page.should have_content "That shipping method cannot be deleted as it is referenced by a product distribution: #{p.id} - #{p.name}."
|
||||
Spree::ShippingMethod.find(@sm.id).should_not be_nil
|
||||
end
|
||||
|
||||
scenario "deleting a shipping method referenced by a line item" do
|
||||
sm2 = create(:shipping_method)
|
||||
d = create(:distributor)
|
||||
|
||||
p = create(:product)
|
||||
create(:product_distribution, product: p, distributor: d, shipping_method: sm2)
|
||||
|
||||
o = create(:order, distributor: d)
|
||||
o.shipping_method = sm2
|
||||
o.save!
|
||||
li = create(:line_item, order: o, product: p)
|
||||
li.shipping_method = @sm
|
||||
li.save!
|
||||
|
||||
visit_delete spree.admin_shipping_method_path(@sm)
|
||||
|
||||
page.should have_content "That shipping method cannot be deleted as it is referenced by a line item in order: #{o.number}."
|
||||
Spree::ShippingMethod.find(@sm.id).should_not be_nil
|
||||
end
|
||||
end
|
||||
@@ -8,24 +8,58 @@ feature %q{
|
||||
include AuthenticationWorkflow
|
||||
include WebHelper
|
||||
|
||||
scenario "adding the first product to the cart" do
|
||||
scenario "adding a product to the cart with no distributor chosen" do
|
||||
# Given a product and some distributors
|
||||
d1 = create(:distributor)
|
||||
d2 = create(:distributor)
|
||||
p = create(:product, :distributors => [d1])
|
||||
create(:product, :distributors => [d2])
|
||||
|
||||
# When I add an item to my cart without choosing a distributor
|
||||
visit spree.product_path p
|
||||
click_button 'Add To Cart'
|
||||
|
||||
# Then I should see an error message
|
||||
page.should have_content "Please choose a distributor for this order."
|
||||
|
||||
# And the product should not have been added to my cart
|
||||
Spree::Order.last.should be_nil
|
||||
end
|
||||
|
||||
scenario "adding the first product to the cart" do
|
||||
create(:itemwise_shipping_method)
|
||||
|
||||
# Given a product, some distributors and a defined shipping cost
|
||||
d1 = create(:distributor)
|
||||
d2 = create(:distributor)
|
||||
create(:product, :distributors => [d2])
|
||||
p = create(:product, :price => 12.34)
|
||||
create(:product_distribution, :product => p, :distributor => d1, :shipping_method => create(:shipping_method))
|
||||
|
||||
# ... with a flat rate shipping method of cost $1.23
|
||||
sm = p.product_distributions.first.shipping_method
|
||||
sm.calculator.preferred_amount = 1.23
|
||||
sm.calculator.save!
|
||||
|
||||
# When I choose a distributor
|
||||
visit spree.root_path
|
||||
click_link d2.name
|
||||
|
||||
# When I add an item to my cart from a different distributor
|
||||
# And I add an item to my cart from a different distributor
|
||||
visit spree.product_path p
|
||||
select d1.name, :from => 'distributor_id'
|
||||
click_button 'Add To Cart'
|
||||
|
||||
# Then the item should be in my cart
|
||||
# Then the correct totals should be displayed
|
||||
page.should have_selector 'span.item-total', :text => '$12.34'
|
||||
page.should have_selector 'span.shipping-total', :text => '$1.23'
|
||||
page.should have_selector 'span.grand-total', :text => '$13.57'
|
||||
|
||||
# And the item should be in my cart, with shipping method set for the line item
|
||||
order = Spree::Order.last
|
||||
order.line_items.first.product.should == p
|
||||
line_item = order.line_items.first
|
||||
line_item.product.should == p
|
||||
line_item.shipping_method.should == p.product_distributions.first.shipping_method
|
||||
|
||||
# And my order should have its distributor set to the chosen distributor
|
||||
order.distributor.should == d1
|
||||
@@ -39,6 +73,7 @@ feature %q{
|
||||
|
||||
# When I add a product to my cart (which sets my distributor)
|
||||
visit spree.product_path p
|
||||
select d1.name, :from => 'distributor_id'
|
||||
click_button 'Add To Cart'
|
||||
page.should have_content "You are shopping at #{d1.name}"
|
||||
|
||||
@@ -57,6 +92,7 @@ feature %q{
|
||||
|
||||
# And a product in my cart
|
||||
visit spree.product_path p
|
||||
select d.name, :from => 'distributor_id'
|
||||
click_button 'Add To Cart'
|
||||
|
||||
# When I go to add it again, I should not have a choice of distributor
|
||||
@@ -74,6 +110,7 @@ feature %q{
|
||||
|
||||
# When I add one of them to my cart
|
||||
visit spree.product_path p1
|
||||
select d1.name, :from => 'distributor_id'
|
||||
click_button 'Add To Cart'
|
||||
|
||||
# And I attempt to add the other
|
||||
@@ -92,6 +129,7 @@ feature %q{
|
||||
|
||||
# When I add the first to my cart
|
||||
visit spree.product_path p1
|
||||
select d.name, :from => 'distributor_id'
|
||||
click_button 'Add To Cart'
|
||||
|
||||
# And I add the second
|
||||
@@ -104,4 +142,78 @@ feature %q{
|
||||
page.should have_selector 'h4 a', :text => p2.name
|
||||
end
|
||||
end
|
||||
|
||||
context "group buys" do
|
||||
scenario "adding a product to the cart for a group buy" do
|
||||
# Given a group buy product and a distributor
|
||||
d = create(:distributor)
|
||||
p = create(:product, :distributors => [d], :group_buy => true)
|
||||
|
||||
# When I add the item to my cart
|
||||
visit spree.product_path p
|
||||
select d.name, :from => 'distributor_id'
|
||||
fill_in "variants_#{p.master.id}", :with => 2
|
||||
fill_in "variant_attributes_#{p.master.id}_max_quantity", :with => 3
|
||||
click_button 'Add To Cart'
|
||||
|
||||
# Then the item should be in my cart with correct quantities
|
||||
order = Spree::Order.last
|
||||
li = order.line_items.first
|
||||
li.product.should == p
|
||||
li.quantity.should == 2
|
||||
li.max_quantity.should == 3
|
||||
end
|
||||
|
||||
scenario "adding a product with variants to the cart for a group buy" do
|
||||
# Given a group buy product with variants and a distributor
|
||||
d = create(:distributor)
|
||||
p = create(:product, :distributors => [d], :group_buy => true)
|
||||
create(:variant, :product => p)
|
||||
|
||||
# When I add the item to my cart
|
||||
visit spree.product_path p
|
||||
select d.name, :from => 'distributor_id'
|
||||
fill_in "quantity", :with => 2
|
||||
fill_in "max_quantity", :with => 3
|
||||
click_button 'Add To Cart'
|
||||
|
||||
# Then the item should be in my cart with correct quantities
|
||||
order = Spree::Order.last
|
||||
li = order.line_items.first
|
||||
li.product.should == p
|
||||
li.quantity.should == 2
|
||||
li.max_quantity.should == 3
|
||||
end
|
||||
|
||||
scenario "adding a product to cart that is not a group buy does not show max quantity field" do
|
||||
# Given a group buy product and a distributor
|
||||
d = create(:distributor)
|
||||
p = create(:product, :distributors => [d], :group_buy => false)
|
||||
|
||||
# When I view the add to cart form, there should not be a max quantity field
|
||||
visit spree.product_path p
|
||||
|
||||
page.should_not have_selector "#variant_attributes_#{p.master.id}_max_quantity"
|
||||
end
|
||||
|
||||
scenario "adding a product with a max quantity less than quantity results in max_quantity==quantity" do
|
||||
# Given a group buy product and a distributor
|
||||
d = create(:distributor)
|
||||
p = create(:product, :distributors => [d], :group_buy => true)
|
||||
|
||||
# When I add the item to my cart
|
||||
visit spree.product_path p
|
||||
select d.name, :from => 'distributor_id'
|
||||
fill_in "variants_#{p.master.id}", :with => 2
|
||||
fill_in "variant_attributes_#{p.master.id}_max_quantity", :with => 1
|
||||
click_button 'Add To Cart'
|
||||
|
||||
# Then the item should be in my cart with correct quantities
|
||||
order = Spree::Order.last
|
||||
li = order.line_items.first
|
||||
li.product.should == p
|
||||
li.quantity.should == 2
|
||||
li.max_quantity.should == 2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -17,13 +17,54 @@ feature %q{
|
||||
:state => Spree::State.find_by_name('Victoria'),
|
||||
:country => Spree::Country.find_by_name('Australia')),
|
||||
:pickup_times => 'Tuesday, 4 PM')
|
||||
@product = create(:product, :name => 'Fuji apples', :distributors => [@distributor])
|
||||
|
||||
@shipping_method_1 = create(:shipping_method, :name => 'Shipping Method One')
|
||||
@shipping_method_1.calculator.set_preference :amount, 1
|
||||
@shipping_method_1.calculator.save!
|
||||
|
||||
@shipping_method_2 = create(:shipping_method, :name => 'Shipping Method Two')
|
||||
@shipping_method_2.calculator.set_preference :amount, 2
|
||||
@shipping_method_2.calculator.save!
|
||||
|
||||
@product_1 = create(:product, :name => 'Fuji apples')
|
||||
@product_1.product_distributions.create(:distributor => @distributor, :shipping_method => @shipping_method_1)
|
||||
|
||||
@product_2 = create(:product, :name => 'Garlic')
|
||||
@product_2.product_distributions.create(:distributor => @distributor, :shipping_method => @shipping_method_2)
|
||||
|
||||
@zone = create(:zone)
|
||||
c = Spree::Country.find_by_name('Australia')
|
||||
Spree::ZoneMember.create(:zoneable => c, :zone => @zone)
|
||||
create(:shipping_method, zone: @zone)
|
||||
create(:payment_method)
|
||||
create(:itemwise_shipping_method, zone: @zone)
|
||||
create(:payment_method, :description => 'Cheque payment method')
|
||||
end
|
||||
|
||||
|
||||
scenario "viewing delivery fees" do
|
||||
# Given I am logged in
|
||||
login_to_consumer_section
|
||||
|
||||
# When I add some apples and some garlic to my cart
|
||||
click_link 'Fuji apples'
|
||||
select @distributor.name, :from => 'distributor_id'
|
||||
click_button 'Add To Cart'
|
||||
click_link 'Continue shopping'
|
||||
|
||||
click_link 'Garlic'
|
||||
click_button 'Add To Cart'
|
||||
|
||||
# Then I should see a breakdown of my delivery fees:
|
||||
# Item | Shipping Method | Delivery Fee
|
||||
# Garlic | Shipping Method Two | $2.00
|
||||
# Fuji apples | Shipping Method One | $1.00
|
||||
#
|
||||
# Subtotal: $3.00
|
||||
table = page.find 'table#delivery'
|
||||
rows = table.all('tr')
|
||||
rows[0].all('th').map { |cell| cell.text.strip }.should == ['Item', 'Shipping Method', 'Delivery Fee']
|
||||
rows[1].all('td').map { |cell| cell.text.strip }.should == ['Fuji apples', 'Shipping Method One', '$1.00']
|
||||
rows[2].all('td').map { |cell| cell.text.strip }.should == ['Garlic', 'Shipping Method Two', '$2.00']
|
||||
page.should have_selector '#delivery-fees span.order-total', :text => '$3.00'
|
||||
end
|
||||
|
||||
|
||||
@@ -31,9 +72,15 @@ feature %q{
|
||||
login_to_consumer_section
|
||||
|
||||
click_link 'Fuji apples'
|
||||
select @distributor.name, :from => 'distributor_id'
|
||||
click_button 'Add To Cart'
|
||||
click_link 'Continue shopping'
|
||||
|
||||
click_link 'Garlic'
|
||||
click_button 'Add To Cart'
|
||||
click_link 'Checkout'
|
||||
|
||||
# -- Checkout: Address
|
||||
fill_in_fields('order_bill_address_attributes_firstname' => 'Joe',
|
||||
'order_bill_address_attributes_lastname' => 'Luck',
|
||||
'order_bill_address_attributes_address1' => '19 Sycamore Lane',
|
||||
@@ -44,6 +91,7 @@ feature %q{
|
||||
select('Australia', :from => 'order_bill_address_attributes_country_id')
|
||||
select('Victoria', :from => 'order_bill_address_attributes_state_id')
|
||||
|
||||
# Distributor details should be displayed
|
||||
within('fieldset#shipping') do
|
||||
[@distributor.name,
|
||||
@distributor.pickup_address.address1,
|
||||
@@ -52,6 +100,7 @@ feature %q{
|
||||
@distributor.pickup_address.state_text,
|
||||
@distributor.pickup_address.country.name,
|
||||
@distributor.pickup_times,
|
||||
@distributor.next_collection_at,
|
||||
@distributor.contact,
|
||||
@distributor.phone,
|
||||
@distributor.email,
|
||||
@@ -63,13 +112,19 @@ feature %q{
|
||||
end
|
||||
|
||||
click_button 'Save and Continue'
|
||||
#display delivery details?
|
||||
|
||||
# -- Checkout: Delivery
|
||||
page.should have_selector 'label', :text => "Delivery $3.00"
|
||||
click_button 'Save and Continue'
|
||||
|
||||
# -- Checkout: Payment
|
||||
click_button 'Save and Continue'
|
||||
|
||||
# -- Checkout: Order complete
|
||||
page.should have_content('Your order has been processed successfully')
|
||||
page.should have_content('Cheque payment method')
|
||||
|
||||
|
||||
# page.should have_content('Your order will be available on:')
|
||||
# page.should have_content('On Tuesday, 4 PM')
|
||||
# page.should have_content('12 Bungee Rd, Carion')
|
||||
|
||||
@@ -10,22 +10,28 @@ feature %q{
|
||||
|
||||
scenario "viewing a list of distributors" do
|
||||
# Given some distributors
|
||||
3.times { create(:distributor) }
|
||||
d1 = create(:distributor)
|
||||
d2 = create(:distributor)
|
||||
d3 = create(:distributor)
|
||||
|
||||
# And some of those distributors have a product
|
||||
create(:product, :distributors => [d1, d2])
|
||||
|
||||
# When I go to the home page
|
||||
visit spree.root_path
|
||||
|
||||
# Then I should see a list containing all distributors
|
||||
Spree::Distributor.all.each do |distributor|
|
||||
page.should have_selector 'a', :text => distributor.name
|
||||
end
|
||||
# Then I should see a list containing the distributors that have products
|
||||
page.should have_selector 'a', :text => d1.name
|
||||
page.should have_selector 'a', :text => d2.name
|
||||
page.should_not have_selector 'a', :text => d3.name
|
||||
end
|
||||
|
||||
|
||||
context "when a distributor is selected" do
|
||||
it "displays the distributor's name" do
|
||||
# Given a distributor
|
||||
# Given a distributor with a product
|
||||
d = create(:distributor, :name => 'Melb Uni Co-op')
|
||||
create(:product, :distributors => [d])
|
||||
|
||||
# When I select the distributor
|
||||
visit spree.root_path
|
||||
@@ -65,13 +71,14 @@ feature %q{
|
||||
end
|
||||
|
||||
it "allows the user to leave the distributor" do
|
||||
# Given a distributor
|
||||
# Given a distributor with a product
|
||||
d = create(:distributor, :name => 'Melb Uni Co-op')
|
||||
create(:product, :distributors => [d])
|
||||
|
||||
# When I select the distributor and then leave it
|
||||
visit spree.root_path
|
||||
click_link d.name
|
||||
click_link 'Leave distributor'
|
||||
click_button 'Browse All Distributors'
|
||||
|
||||
# Then I should have left the distributor
|
||||
page.should_not have_selector '#current-distributor', :text => 'You are shopping at Melb Uni Co-op'
|
||||
@@ -106,10 +113,11 @@ feature %q{
|
||||
end
|
||||
|
||||
it "works when viewing a product from a remote distributor" do
|
||||
# Given two distributors and a product under one
|
||||
# Given two distributors and our product under one
|
||||
distributor_product = create(:distributor)
|
||||
distributor_no_product = create(:distributor)
|
||||
product = create(:product, :distributors => [distributor_product])
|
||||
create(:product, :distributors => [distributor_no_product])
|
||||
|
||||
# When we select the distributor without the product and then view the product
|
||||
visit spree.root_path
|
||||
|
||||
36
spec/requests/consumer/suppliers_spec.rb
Normal file
36
spec/requests/consumer/suppliers_spec.rb
Normal file
@@ -0,0 +1,36 @@
|
||||
require 'spec_helper'
|
||||
|
||||
feature %q{
|
||||
As a consumer
|
||||
I want to see a list of products from a supplier
|
||||
So that I can connect with them (and maybe buy stuff too)
|
||||
} do
|
||||
include AuthenticationWorkflow
|
||||
include WebHelper
|
||||
|
||||
scenario "viewing a list of suppliers" do
|
||||
# Given some suppliers
|
||||
s1 = create(:supplier)
|
||||
s2 = create(:supplier)
|
||||
s3 = create(:supplier)
|
||||
|
||||
# When I go to the home page
|
||||
visit spree.root_path
|
||||
|
||||
# Then I should see a list containing all the suppliers
|
||||
[s1, s2, s3].each { |s| page.should have_selector 'a', :text => s.name }
|
||||
end
|
||||
|
||||
scenario "viewing products provided by a supplier" do
|
||||
# Given a supplier with a product
|
||||
s = create(:supplier, :name => 'Murrnong')
|
||||
p = create(:product, :supplier => s)
|
||||
|
||||
# When I select the supplier
|
||||
visit spree.root_path
|
||||
click_link s.name
|
||||
|
||||
# Then I should see the product
|
||||
page.should have_content p.name
|
||||
end
|
||||
end
|
||||
@@ -76,6 +76,11 @@ module WebHelper
|
||||
page.find(:xpath, "//div[@class=\"ui-dialog-buttonset\"]//span[contains(text(),\"#{button_content}\")]").click
|
||||
end
|
||||
|
||||
def visit_delete(url)
|
||||
response = Capybara.current_session.driver.delete url
|
||||
click_link 'redirected' if response.status == 302
|
||||
end
|
||||
|
||||
def trigger_manual_event(field_selector, event = 'change')
|
||||
page.execute_script("$('#{field_selector}').trigger('#{event}');")
|
||||
end
|
||||
|
||||
10
spec/support/spree/init.rb
Normal file
10
spec/support/spree/init.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
# Initialise shipping method when created without one, like this:
|
||||
# create(:product, :distributors => [...])
|
||||
# In this case, we don't care what the shipping method is, but we need one for validations to pass.
|
||||
Spree::ProductDistribution.class_eval do
|
||||
before_validation :init_shipping_method
|
||||
|
||||
def init_shipping_method
|
||||
self.shipping_method ||= Spree::ShippingMethod.first || FactoryGirl.create(:shipping_method)
|
||||
end
|
||||
end
|
||||
22
zeus.json
Normal file
22
zeus.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"command": "ruby -rubygems -rzeus/rails -eZeus.go",
|
||||
|
||||
"plan": {
|
||||
"boot": {
|
||||
"default_bundle": {
|
||||
"development_environment": {
|
||||
"prerake": {"rake": []},
|
||||
"runner": ["r"],
|
||||
"console": ["c"],
|
||||
"server": ["s"],
|
||||
"generate": ["g"],
|
||||
"dbconsole": []
|
||||
},
|
||||
"test_environment": {
|
||||
"cucumber_environment": {"cucumber": []},
|
||||
"test_helper": {"test": ["rspec", "testrb"]}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user