Compare commits

...

105 Commits

Author SHA1 Message Date
Rohan Mitchell
2535e3965b When merging orders, set distributor when target order distributor is nil 2012-10-09 08:42:29 +11:00
Rohan Mitchell
568d948cbe Destroy incomplete orders if they can't be merged, prevents that order unexpectedly appearing in cart after checkout. Also ensure all orders have a shipping method. 2012-10-05 12:09:53 +10:00
Rohan Mitchell
6d9257d941 Do not delete shipping method referenced by a line item 2012-10-02 12:15:09 +10:00
Rohan Mitchell
7430fc9bdd Do not delete shipping method referenced by a product distribution 2012-10-02 11:58:18 +10:00
Rohan Mitchell
473b4e9adc Add positive case test 2012-10-02 11:54:18 +10:00
Rohan Mitchell
2aa450b072 Do not delete shipping method referenced by an order 2012-10-02 11:51:13 +10:00
Rohan Mitchell
3886ec39f7 Add web helper method to visit paths with delete method 2012-10-02 11:47:55 +10:00
Rohan Mitchell
afb8faa96f Update zeus config 2012-10-02 11:44:50 +10:00
Rohan Mitchell
27b7d59f46 BaseController does not attempt to merge incomplete and current orders when they have differing distributors 2012-10-02 09:44:51 +10:00
Rohan Mitchell
bc408d8b6e Add jquery and jquery_ujs includes to admin/all.js, as these have been removed from spree/admin/spree_core.js 2012-09-22 09:20:27 +10:00
Rohan Mitchell
a8758f1271 Fix OrdersHelper for upgraded spree 2012-09-21 16:36:50 +10:00
Rohan Mitchell
2bce9df25a Track 1-1-stable on spree git, fixes order quantity change bug 2012-09-21 15:55:51 +10:00
Rohan Mitchell
479c49752c Update spree_paypal_express, hopefully fixing 'Validation failed: State can't be blank' error 2012-09-21 15:32:19 +10:00
Rohan Mitchell
62d6067c1a Do not truncate cents for product price update on add to cart JS 2012-09-21 12:44:38 +10:00
Rohan Mitchell
a1b5102476 Fix checkout totals, also amend factories for valid test shipping method data 2012-09-21 12:35:01 +10:00
Rohan Mitchell
593f3887c8 Switch pry for pry-debugger 2012-09-21 12:29:06 +10:00
Rohan Mitchell
757456dd57 Set line item shipping method in callback so that Order#update shipping calcs run correctly 2012-09-20 10:45:50 +10:00
Rohan Mitchell
3894ce946d Fix error on supplier page, add test to cover 2012-09-19 15:46:56 +10:00
Rohan Mitchell
f1f9b5b2e8 Make order and distributor report resilient to orders without distributors 2012-09-19 15:19:30 +10:00
Rohan Mitchell
5402590d5f Add debug output on line item migration for lost data 2012-09-19 15:08:05 +10:00
Rohan Mitchell
eaca160367 Set line item shipping method when added to cart, update specs for changes to line item shipping method 2012-09-19 15:01:50 +10:00
Rohan Mitchell
85f18cfb12 Rob: Replace LineItem shipping_method method with relation 2012-09-19 14:27:28 +10:00
Rohan Mitchell
7492522066 Improve clarity of various totals (items, shipping, grand total) on checkout page 2012-09-14 15:35:22 +10:00
Rohan Mitchell
334f84637d Fix empty cart button alignment at checkout 2012-09-14 13:32:49 +10:00
Rohan Mitchell
3f15fc0b52 Set default admin orders view to sort with most recent orders first 2012-09-14 13:27:33 +10:00
Rohan Mitchell
a013854d2d Change logo to Eaterprises, update link colour to match 2012-09-14 11:25:36 +10:00
Rohan Mitchell
c883ab87b6 Add db backups and uploaded images to gitignore 2012-09-14 10:32:10 +10:00
Rohan Mitchell
0e313e5826 Add Zeus config 2012-09-14 10:23:22 +10:00
Rohan Mitchell
3794c00856 Upgrade Rails to 3.2.8 and Spree to 1.1.3 2012-09-14 10:20:52 +10:00
Rohan Mitchell
b87c59c051 Default to blank distributor on add to cart to require user to select one 2012-09-13 15:29:04 +10:00
Rohan Mitchell
356ae40c7b Display product descriptions as HTML in checkout 2012-09-13 13:05:12 +10:00
Rohan Mitchell
8394c47064 Add admin js includes 2012-09-13 12:27:20 +10:00
Rohan Mitchell
a84f6f08eb Compile all admin javascripts, fixes admin/images/new.js not found error 2012-09-13 12:20:35 +10:00
Rohan Mitchell
3a391d1e76 Give undefined payment method tolerance to orders and distributors report 2012-08-08 15:30:25 +10:00
Rohan Mitchell
9dd94eaf57 Weight shipping calculator treats variants without weight defined as zero weight 2012-08-08 15:29:47 +10:00
Rohan Mitchell
9f013f0e37 When loading distributors for sidebar, only show those that have active products on hand 2012-08-04 17:51:08 +10:00
Rohan Mitchell
f0ec3080e4 Remove instrumentation 2012-08-04 17:50:30 +10:00
Rohan Mitchell
245de4fe1a Add instrumentation to debug products not appearing on distributor view 2012-08-04 16:52:18 +10:00
Rohan Mitchell
9d33ef460c Max quantity field doesn't affect JS price calcs on products without variants 2012-08-04 16:51:43 +10:00
Rohan Mitchell
e0b8b8b4d4 Force precompile admin css and js 2012-08-04 10:27:15 +10:00
Rohan Mitchell
529de72f75 Force precompilation of store/all.css and store/all.js 2012-08-04 10:23:00 +10:00
Rohan Mitchell
b4f867924b Do not connect to db during asset precompile, fix heroku deploy to cedar 2012-08-04 10:12:06 +10:00
Rohan Mitchell
9d3afe80c6 split_products_by_distributor was not written with pre-pagination by searcher in mind, resulting in silently dropped products. Disable pagination at searcher. 2012-08-03 18:47:33 +10:00
Rohan Mitchell
28e75d6467 Fix add to cart JS for compatibility with group buy 2012-08-03 18:32:19 +10:00
Rohan Mitchell
b0fa05df0c Remove assets from git 2012-08-03 18:31:28 +10:00
Rohan Mitchell
f3ffba378a Add a product with variants to the cart with max quantity for a group buy 2012-08-03 18:05:45 +10:00
Rohan Mitchell
2d89640271 Instrument orders controller to debug populate_variant_attributes 2012-08-03 14:11:59 +10:00
Rohan Mitchell
e6ee6b5164 Itemwise shipping calculator returns 0 instead of nil when there are no items 2012-08-03 08:44:53 +10:00
Rohan Mitchell
768a170bb8 Fix with_products_on_hand query for server db compatibility 2012-08-03 08:21:45 +10:00
Rohan Mitchell
8834268970 Fix error on no shipping method defined 2012-08-02 17:45:22 +10:00
Rohan Mitchell
fe61b4aab1 Display shipping fee at all steps of the checkout process, not just after delivery method is chosen 2012-08-02 16:24:08 +10:00
Rohan Mitchell
a6c2490597 Enable auto-capture for spree_paypal_express 2012-08-02 15:45:31 +10:00
Rohan Mitchell
9110dc6414 Fix form local var naming for admin shared address form 2012-08-02 15:33:39 +10:00
Rohan Mitchell
77be0dd6eb Adding a product with a max quantity less than quantity results in max_quantity==quantity 2012-08-02 15:26:13 +10:00
Rohan Mitchell
40544eb27b Adding a product to cart that is not a group buy does not show max quantity field 2012-08-02 15:16:44 +10:00
Rohan Mitchell
306cb5b089 Add max quantity to order and distributor report 2012-08-02 15:07:34 +10:00
Rohan Mitchell
c46613877c Add max quantity field to add to cart form, add end-to-end test for max_quantity 2012-08-02 14:45:55 +10:00
Rohan Mitchell
2db2fbcade Change set_variant_attribute to set_variant_attributes, implement it on Order 2012-08-02 14:45:27 +10:00
Rohan Mitchell
ea05f05576 When adding a group buy product to the cart, set the max quantity on the order 2012-08-02 14:29:05 +10:00
Rohan Mitchell
361a87f580 Add group buy option to new/edit product in admin 2012-08-02 13:42:47 +10:00
Rohan Mitchell
330c62716c Add fields for group buy feature 2012-08-02 13:15:17 +10:00
Rohan Mitchell
63bf25293d Only show distributors in sidebar that have products in stock 2012-08-02 11:49:10 +10:00
Rohan Mitchell
93867682bb Only show distributors in sidebar that have products 2012-08-02 11:33:36 +10:00
Rohan Mitchell
7d5c158021 Install Bugsnag 2012-08-02 10:32:33 +10:00
Rohan Mitchell
06c6422591 Fix by-weight calculator to take line item quantity into account 2012-07-23 18:49:03 +10:00
Rohan Mitchell
5e04032797 Explicitly specify Spree 1.1.1, fix test regression in OrdersController 2012-07-23 18:48:30 +10:00
Andrew Spinks
f716176361 specify ruby version in Gemfile as per heroku requirement: https://devcenter.heroku.com/articles/ruby-versions 2012-07-20 20:40:55 +10:00
Andrew Spinks
2826f62497 Add extra details to the order report. 2012-07-20 20:25:53 +10:00
Andrew Spinks
7172fe0c87 added extra fields to order report. 2012-07-20 00:07:41 +10:00
Andrew Spinks
7e9a84087e cleaning up order report 2012-07-19 22:48:42 +10:00
Andrew Spinks
58e9cd3eeb fix distributor name in report 2012-07-15 21:00:10 +10:00
Andrew Spinks
54559c4a5f first cut at orders report. 2012-07-15 20:48:10 +10:00
Andrew Spinks
8f5b5e7ae4 allow shipping instructions to be provided. 2012-07-11 23:33:03 +10:00
Andrew Spinks
759ceae23f add distributor name to confirmation email 2012-07-11 23:20:59 +10:00
Andrew Spinks
32b37a1390 add padding to the second address line. 2012-07-11 22:45:57 +10:00
Andrew Spinks
0e43fcfaa1 adjust address formatting in confirmation email. 2012-07-11 22:25:42 +10:00
Andrew Spinks
6a27f8da32 update formatting of confirmation email. 2012-07-11 22:15:46 +10:00
Andrew Spinks
c24543c237 Add delivery details to confirmation email. 2012-07-11 22:07:18 +10:00
Andrew Spinks
44314ccb99 copied original spree confirmation mail 2012-07-11 21:35:07 +10:00
Andrew Spinks
9ad42a3966 adding precompiled assets 2012-07-11 20:46:20 +10:00
Andrew Spinks
d34e6570fc trying to get asset precompilation to work on deploy 2012-07-11 20:39:49 +10:00
Andrew Spinks
b5b35491cc allow asset precompile to work on new heroku instance 2012-07-07 10:17:33 +10:00
Rohan Mitchell
1e471e5e22 Name all form-containing partials with _form, tweak admin new product form 2012-07-02 16:28:31 +10:00
Rohan Mitchell
aa027f6e29 Display subtotal for delivery fees 2012-07-02 16:13:55 +10:00
Rohan Mitchell
6f581fce43 Admin can edit next collection date/time when editing an individual distributor 2012-07-02 14:36:45 +10:00
Rohan Mitchell
8156da509e Display distributor next collection time in checkout process 2012-07-02 14:32:53 +10:00
Rohan Mitchell
718e54f933 Add distributor next_collection_at field, bulk edit in admin backend 2012-07-02 14:24:52 +10:00
Rohan Mitchell
cb56e9f658 Display delivery fee breakdown along with cart 2012-07-01 19:09:34 +10:00
Rohan Mitchell
9afa566be5 Add spree_last_address extension, which retrieves a customer's address when they order a second time so they don't need to retype it 2012-07-01 11:44:18 +10:00
Rohan Mitchell
86847d99da Make Leave Distributor link more intuitive 2012-07-01 11:33:40 +10:00
Rohan Mitchell
258559f9d0 Update the price on the product details page in real time when the variant or the quantity are changed 2012-07-01 10:07:08 +10:00
Rohan Mitchell
af05448dd8 For check payment method, display description after purchase for use with EFT 2012-06-29 15:27:30 +10:00
Rohan Mitchell
e74f9054ae Fix seeds: shipping and payment info created for successful checkout out of the box 2012-06-29 15:03:32 +10:00
Rohan Mitchell
82dd485e01 Install spree_paypal_express gem 2012-06-29 14:40:20 +10:00
Rohan Mitchell
1d5e4d22e7 Add pending spree migrations 2012-06-29 14:34:19 +10:00
Rohan Mitchell
28d2292de0 Add by-weight shipping calculator 2012-06-29 12:46:33 +10:00
Rohan Mitchell
73e601315b Add acceptance spec for itemwise shipping fees 2012-06-29 11:50:43 +10:00
Rohan Mitchell
a0c1d1d255 Look up a product's shipping method though a particular distributor 2012-06-29 11:02:34 +10:00
Rohan Mitchell
411ba107ce Perform shipping calculation in line item model 2012-06-29 10:47:11 +10:00
Rohan Mitchell
4f1e4fc223 Compute itemwise shipping cost for a line item 2012-06-29 08:46:31 +10:00
Rohan Mitchell
eae05ea59c Add itemwise shipping cost calculator 2012-06-29 07:52:29 +10:00
Rohan Mitchell
c09d4c98c8 Product distributions now editable 2012-06-28 15:38:26 +10:00
Rohan Mitchell
474c049f0d Set up basic form for admin editing product distributions (not yet functional) 2012-06-28 15:13:26 +10:00
Rohan Mitchell
1d3b7de5c6 Require ProductDistribution to be unique on [product, distributor] 2012-06-28 15:12:15 +10:00
Rohan Mitchell
3f08c2a9b0 Convert distributors_products join table into ProductDistribution explicit join model 2012-06-27 11:55:10 +10:00
99 changed files with 1814 additions and 343 deletions

31
.gitignore vendored
View File

@@ -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
View File

@@ -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

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 B

View File

@@ -5,6 +5,8 @@
// the compiled file.
//
//= require jquery
//= require jquery_ujs
//= require admin/spree_core
//= require admin/spree_auth
//= require admin/spree_promo

View 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));
}

View File

@@ -0,0 +1,7 @@
#header #logo {
top: 10px;
}
#header h1 {
left: 275px;
}

View File

@@ -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;
}
}
}

View 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);

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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 })

View 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

View File

@@ -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

View 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

View 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

View File

@@ -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

View 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

View 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

View File

@@ -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

View File

@@ -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

View 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

View 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")

View File

@@ -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")

View 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")

View File

@@ -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")

View 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")

View File

@@ -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")

View File

@@ -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

View File

@@ -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' %> &nbsp;
<%= 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' %> &nbsp;
<%= 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 %>

View File

@@ -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:

View File

@@ -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

View 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

View 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'

View File

@@ -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)

View File

@@ -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)

View 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 %>

View File

@@ -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

View File

@@ -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

View 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.

View 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 => "...")

View 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)

View File

@@ -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

View File

@@ -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}"

View File

@@ -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

View File

@@ -0,0 +1,2 @@
- if order.payment_method.type == "Spree::PaymentMethod::Check"
= simple_format order.payment_method.description

View File

@@ -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

View File

@@ -0,0 +1,3 @@
Bugsnag.configure do |config|
config.api_key = "937a200f492fad600b4cc29dddda5f71"
end

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,5 @@
class AddNextCollectionAtToDistributors < ActiveRecord::Migration
def change
add_column :distributors, :next_collection_at, :string
end
end

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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|

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)"

View 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

View 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

View 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

View File

@@ -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

View 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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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')

View File

@@ -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

View 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

View File

@@ -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

View 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
View 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"]}
}
}
}
}
}