diff --git a/.gitignore b/.gitignore index 00360d0b4e..78e0a36aef 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ .bundle .rbenv-version +.ruby-version +.ruby-gemset .swp *.swo *.swp @@ -16,6 +18,7 @@ tmp/ *.~lock.* .emacs.desktop .DS_Store +*.sublime-project* spec/javascripts/generated/* db/development_structure.sql db/test_structure.sql @@ -29,4 +32,6 @@ public/images public/spree config/abr.yml config/heroku_env.rb +config/initializers/feature_toggle.rb NERD_tree* +coverage diff --git a/.rvmrc b/.rvmrc new file mode 100644 index 0000000000..4a8ffc396b --- /dev/null +++ b/.rvmrc @@ -0,0 +1,48 @@ +#!/usr/bin/env bash + +# This is an RVM Project .rvmrc file, used to automatically load the ruby +# development environment upon cd'ing into the directory + +# First we specify our desired [@], the @gemset name is optional, +# Only full ruby name is supported here, for short names use: +# echo "rvm use 1.9.3" > .rvmrc +environment_id="ruby-1.9.3-p392@openfoodweb" + +# Uncomment the following lines if you want to verify rvm version per project +# rvmrc_rvm_version="1.18.21 (stable)" # 1.10.1 seams as a safe start +# eval "$(echo ${rvm_version}.${rvmrc_rvm_version} | awk -F. '{print "[[ "$1*65536+$2*256+$3" -ge "$4*65536+$5*256+$6" ]]"}' )" || { +# echo "This .rvmrc file requires at least RVM ${rvmrc_rvm_version}, aborting loading." +# return 1 +# } + +# First we attempt to load the desired environment directly from the environment +# file. This is very fast and efficient compared to running through the entire +# CLI and selector. If you want feedback on which environment was used then +# insert the word 'use' after --create as this triggers verbose mode. +if [[ -d "${rvm_path:-$HOME/.rvm}/environments" + && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]] +then + \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id" + [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]] && + \. "${rvm_path:-$HOME/.rvm}/hooks/after_use" || true +else + # If the environment file has not yet been created, use the RVM CLI to select. + rvm --create "$environment_id" || { + echo "Failed to create RVM environment '${environment_id}'." + return 1 + } +fi + +# If you use bundler, this might be useful to you: +# if [[ -s Gemfile ]] && { +# ! builtin command -v bundle >/dev/null || +# builtin command -v bundle | GREP_OPTIONS= \grep $rvm_path/bin/bundle >/dev/null +# } +# then +# printf "%b" "The rubygem 'bundler' is not installed. Installing it now.\n" +# gem install bundler +# fi +# if [[ -s Gemfile ]] && builtin command -v bundle >/dev/null +# then +# bundle install | GREP_OPTIONS= \grep -vE '^Using|Your bundle is complete' +# fi diff --git a/Gemfile b/Gemfile index 50f29dabdc..bec59f9fa8 100644 --- a/Gemfile +++ b/Gemfile @@ -1,13 +1,13 @@ -source 'http://rubygems.org' +source 'https://rubygems.org' ruby "1.9.3" -gem 'rails', '3.2.11' +gem 'rails', '3.2.13' gem 'pg' gem 'spree', :git => 'git://github.com/spree/spree.git', :branch => '1-3-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-3-stable' -gem 'spree_last_address', :git => 'git://github.com/eaterprises/spree-last-address.git' +gem 'spree_last_address', :git => 'git://github.com/eaterprises/spree-last-address.git', :branch => '1-3-stable' gem 'spree_auth_devise', :git => 'https://github.com/spree/spree_auth_devise.git', :branch => '1-3-stable' gem 'comfortable_mexican_sofa' @@ -18,12 +18,18 @@ gem 'simple_form', :git => 'git://github.com/RohanM/simple_form.git' gem 'unicorn' gem 'bugsnag' -gem 'spree_heroku', :git => 'git://github.com/eaterprises/spree-heroku.git' +gem 'newrelic_rpm' gem 'haml' +gem 'sass' gem 'aws-sdk' +gem 'db2fog' gem 'andand' gem 'truncate_html' gem 'representative_view' +gem 'rabl' +gem 'oj' +gem 'chili', :github => 'eaterprises/chili' +gem 'deface', :github => 'spree/deface' # Gems used only for assets and not required # in production environments by default. @@ -36,6 +42,8 @@ group :assets do gem 'therubyracer' gem 'uglifier', '>= 1.0.3' + + gem 'turbo-sprockets-rails3' end gem 'jquery-rails' @@ -51,8 +59,16 @@ group :test, :development do gem 'faker' gem 'capybara' gem 'database_cleaner', '0.7.1', :require => false + gem 'simplecov', :require => false gem 'awesome_print' - gem "letter_opener" + gem 'letter_opener' + gem 'timecop' +end + +group :chili do + gem 'enterprises_distributor_info_rich_text_feature', path: 'lib/chili/enterprises_distributor_info_rich_text_feature' + gem 'eaterprises_feature', path: 'lib/chili/eaterprises_feature' + gem 'local_organics_feature', path: 'lib/chili/local_organics_feature' end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index 49c14ae8af..4b243f28e5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -7,63 +7,71 @@ GIT activemodel (~> 3.0) GIT - remote: git://github.com/eaterprises/spree-heroku.git - revision: a1e07bf7a22fc0c07a1be9148f477d20b557dbf6 + remote: git://github.com/eaterprises/chili.git + revision: b82608623d504eb39f852115b138a53af5f89505 specs: - spree_heroku (1.0) - aws-sdk (~> 1.3.4) - spree_core (>= 0.70.0) + chili (3.1.0) + deface (~> 1.0.0.rc2) + rails (~> 3.2) GIT remote: git://github.com/eaterprises/spree-last-address.git - revision: f5ed71a5482fbc16da559737903bb46fe032c150 + revision: f93ea5a6b06e4605ea9c3fc5ef8e71f8e6aa0ffc + branch: 1-3-stable specs: spree_last_address (1.1.0) spree_core (>= 1.1) +GIT + remote: git://github.com/spree/deface.git + revision: 1110a1336252109bce7f98f9182042e0bc2930ae + specs: + deface (1.0.0.rc3) + colorize (>= 0.5.8) + nokogiri (~> 1.6.0) + rails (>= 3.1) + GIT remote: git://github.com/spree/spree.git - revision: 36a59eb311470a2c24b9aa826ecad114c518c01f + revision: 94566bf1b7d50f474333d10844534e570b6edf5a branch: 1-3-stable specs: - spree (1.3.3.beta) - spree_api (= 1.3.3.beta) - spree_cmd (= 1.3.3.beta) - spree_core (= 1.3.3.beta) - spree_dash (= 1.3.3.beta) - spree_promo (= 1.3.3.beta) - spree_sample (= 1.3.3.beta) - spree_api (1.3.3.beta) - spree_core (= 1.3.3.beta) + spree (1.3.3) + spree_api (= 1.3.3) + spree_cmd (= 1.3.3) + spree_core (= 1.3.3) + spree_promo (= 1.3.3) + spree_sample (= 1.3.3) + spree_api (1.3.3) + spree_core (= 1.3.3) versioncake (= 0.4.0) - spree_cmd (1.3.3.beta) + spree_cmd (1.3.3) thor (>= 0.14.6) - spree_core (1.3.3.beta) - activemerchant (~> 1.29.3) + spree_core (1.3.3) + activemerchant (~> 1.31) acts_as_list (= 0.1.4) awesome_nested_set (= 2.1.5) aws-sdk (~> 1.3.4) cancan (= 1.6.8) deface (>= 0.9.0) - ffaker (~> 1.12.0) - highline (= 1.6.11) + ffaker (~> 1.15.0) + highline (= 1.6.18) jquery-rails (~> 2.2.0) + json (>= 1.5.5) kaminari (= 0.13.0) money (= 5.0.0) paperclip (~> 2.8) rabl (= 0.7.2) - rails (~> 3.2.11) - ransack (~> 0.7.2) - select2-rails (~> 3.2) + rails (~> 3.2.13) + ransack (= 0.7.2) + select2-rails (= 3.2.1) state_machine (= 1.1.2) stringex (~> 1.3.2) - spree_dash (1.3.3.beta) - httparty (~> 0.8.1) - spree_core (= 1.3.3.beta) - spree_promo (1.3.3.beta) - spree_core (= 1.3.3.beta) - spree_sample (1.3.3.beta) - spree_core (= 1.3.3.beta) + truncate_html (~> 0.5.5) + spree_promo (1.3.3) + spree_core (= 1.3.3) + spree_sample (1.3.3) + spree_core (= 1.3.3) GIT remote: git://github.com/spree/spree_i18n.git @@ -75,7 +83,7 @@ GIT GIT remote: git://github.com/spree/spree_paypal_express.git - revision: 483f6ababa9c8a1c574aad0a948c96cc21a591db + revision: 9d70ab6d537420ff41468d05d6d2ac3c8d2ff3bf branch: 1-3-stable specs: spree_paypal_express (1.2.0) @@ -83,28 +91,49 @@ GIT GIT remote: https://github.com/spree/spree_auth_devise.git - revision: ab03a7a22740b52f96bf0311a1e9f18a99ee02f2 + revision: b2b82f1bbe4b47a0713bcf70af8b3c17fa39c0d0 branch: 1-3-stable specs: spree_auth_devise (1.0.0) cancan (~> 1.6.7) devise (~> 2.2.3) - devise-encryptable (= 0.1.1) + devise-encryptable (= 0.1.2) spree_core -GEM - remote: http://rubygems.org/ +PATH + remote: lib/chili/eaterprises_feature specs: - actionmailer (3.2.11) - actionpack (= 3.2.11) - mail (~> 2.4.4) - actionpack (3.2.11) - activemodel (= 3.2.11) - activesupport (= 3.2.11) + eaterprises_feature (0.0.1) + chili (~> 3.1) + rails (~> 3.2.11) + +PATH + remote: lib/chili/enterprises_distributor_info_rich_text_feature + specs: + enterprises_distributor_info_rich_text_feature (0.0.1) + chili (~> 3.1) + rails (~> 3.2.11) + +PATH + remote: lib/chili/local_organics_feature + specs: + local_organics_feature (0.0.1) + chili (~> 3.1) + rails (~> 3.2.11) + +GEM + remote: https://rubygems.org/ + specs: + actionmailer (3.2.13) + actionpack (= 3.2.13) + mail (~> 2.5.3) + actionpack (3.2.13) + activemodel (= 3.2.13) + activesupport (= 3.2.13) builder (~> 3.0.0) erubis (~> 2.7.0) journey (~> 1.0.4) - rack (~> 1.4.0) + rack (~> 1.4.5) rack-cache (~> 1.2) rack-test (~> 0.6.1) sprockets (~> 2.2.1) @@ -112,7 +141,7 @@ GEM active_utils (1.0.5) activesupport (>= 2.3.11) i18n - activemerchant (1.29.3) + activemerchant (1.34.0) active_utils (>= 1.0.2) activesupport (>= 2.3.14) builder (>= 2.0.0) @@ -120,19 +149,19 @@ GEM json (>= 1.5.1) money nokogiri - activemodel (3.2.11) - activesupport (= 3.2.11) + activemodel (3.2.13) + activesupport (= 3.2.13) builder (~> 3.0.0) - activerecord (3.2.11) - activemodel (= 3.2.11) - activesupport (= 3.2.11) + activerecord (3.2.13) + activemodel (= 3.2.13) + activesupport (= 3.2.13) arel (~> 3.0.2) tzinfo (~> 0.3.29) - activeresource (3.2.11) - activemodel (= 3.2.11) - activesupport (= 3.2.11) - activesupport (3.2.11) - i18n (~> 0.6) + activeresource (3.2.13) + activemodel (= 3.2.13) + activesupport (= 3.2.13) + activesupport (3.2.13) + i18n (= 0.6.1) multi_json (~> 1.0) acts_as_list (0.1.4) addressable (2.3.3) @@ -162,7 +191,7 @@ GEM xpath (~> 1.0.0) childprocess (0.3.9) ffi (~> 1.0, >= 1.0.11) - chunky_png (1.2.7) + chunky_png (1.2.8) climate_control (0.0.3) activesupport (>= 3.0) cocaine (0.5.1) @@ -175,6 +204,7 @@ GEM coffee-script-source execjs coffee-script-source (1.3.3) + colorize (0.5.8) columnize (0.3.6) comfortable_mexican_sofa (1.6.24) active_link_to (~> 1.0.0) @@ -187,24 +217,26 @@ GEM compass-rails (1.0.3) compass (>= 0.12.2, < 0.14) database_cleaner (0.7.1) - debugger (1.5.0) + db2fog (0.8.0) + activerecord (~> 3.0) + fog (~> 1.0) + rails (~> 3.0) + debugger (1.6.1) columnize (>= 0.3.1) debugger-linecache (~> 1.2.0) - debugger-ruby_core_source (~> 1.2.0) + debugger-ruby_core_source (~> 1.2.3) debugger-linecache (1.2.0) - debugger-ruby_core_source (1.2.0) - deface (0.9.1) - nokogiri (~> 1.5.0) - rails (~> 3.1) - devise (2.2.3) + debugger-ruby_core_source (1.2.3) + devise (2.2.4) bcrypt-ruby (~> 3.0) orm_adapter (~> 0.1) railties (~> 3.1) warden (~> 1.2.1) - devise-encryptable (0.1.1) - devise (>= 2.1.0.rc) + devise-encryptable (0.1.2) + devise (>= 2.1.0) diff-lcs (1.1.3) erubis (2.7.0) + excon (0.25.3) execjs (1.4.0) multi_json (~> 1.0) factory_girl (3.3.0) @@ -214,21 +246,32 @@ GEM railties (>= 3.0.0) faker (1.0.1) i18n (~> 0.4) - ffaker (1.12.1) + ffaker (1.15.0) ffi (1.4.0) + fog (1.14.0) + builder + excon (~> 0.25.0) + formatador (~> 0.2.0) + mime-types + multi_json (~> 1.0) + net-scp (~> 1.1) + net-ssh (>= 2.1.3) + nokogiri (~> 1.5) + ruby-hmac + formatador (0.2.4) fssm (0.2.10) haml (3.1.6) - highline (1.6.11) - hike (1.2.1) - httparty (0.8.3) + highline (1.6.18) + hike (1.2.3) + httparty (0.11.0) multi_json (~> 1.0) - multi_xml + multi_xml (>= 0.5.2) i18n (0.6.1) journey (1.0.4) - jquery-rails (2.2.1) + jquery-rails (2.2.2) railties (>= 3.0, < 5.0) thor (>= 0.14, < 2.0) - json (1.7.7) + json (1.8.0) kaminari (0.13.0) actionpack (>= 3.0.0) activesupport (>= 3.0.0) @@ -239,18 +282,24 @@ GEM letter_opener (1.0.0) launchy (>= 2.0.4) libv8 (3.3.10.4) - mail (2.4.4) - i18n (>= 0.4.0) + mail (2.5.4) mime-types (~> 1.16) treetop (~> 1.4.8) method_source (0.8.1) - mime-types (1.21) + mime-types (1.23) + mini_portile (0.5.1) money (5.0.0) i18n (~> 0.4) json - multi_json (1.6.1) - multi_xml (0.5.3) - nokogiri (1.5.6) + multi_json (1.7.7) + multi_xml (0.5.4) + net-scp (1.1.2) + net-ssh (>= 2.6.5) + net-ssh (2.6.8) + newrelic_rpm (3.6.5.130) + nokogiri (1.6.0) + mini_portile (~> 0.5.0) + oj (2.1.2) orm_adapter (0.4.0) paperclip (2.8.0) activerecord (>= 2.3.0) @@ -261,7 +310,7 @@ GEM polyamorous (0.5.0) activerecord (~> 3.0) polyglot (0.3.3) - pry (0.9.12) + pry (0.9.12.2) coderay (~> 1.0.5) method_source (~> 0.8) slop (~> 3.4) @@ -278,28 +327,28 @@ GEM rack rack-test (0.6.2) rack (>= 1.0) - rails (3.2.11) - actionmailer (= 3.2.11) - actionpack (= 3.2.11) - activerecord (= 3.2.11) - activeresource (= 3.2.11) - activesupport (= 3.2.11) + rails (3.2.13) + actionmailer (= 3.2.13) + actionpack (= 3.2.13) + activerecord (= 3.2.13) + activeresource (= 3.2.13) + activesupport (= 3.2.13) bundler (~> 1.0) - railties (= 3.2.11) - railties (3.2.11) - actionpack (= 3.2.11) - activesupport (= 3.2.11) + railties (= 3.2.13) + railties (3.2.13) + actionpack (= 3.2.13) + activesupport (= 3.2.13) rack-ssl (~> 1.3.2) rake (>= 0.8.7) rdoc (~> 3.4) thor (>= 0.14.6, < 2.0) raindrops (0.9.0) - rake (10.0.3) + rake (10.1.0) ransack (0.7.2) actionpack (~> 3.0) activerecord (~> 3.0) polyamorous (~> 0.5.0) - rdoc (3.12.1) + rdoc (3.12.2) json (~> 1.4) representative (1.0.5) activesupport (>= 2.2.2) @@ -322,14 +371,14 @@ GEM activesupport (>= 3.0) railties (>= 3.0) rspec (~> 2.10.0) + ruby-hmac (0.4.0) rubyzip (0.9.9) - sass (3.1.19) - sass-rails (3.2.5) + sass (3.2.9) + sass-rails (3.2.6) railties (~> 3.2.0) sass (>= 3.1.10) tilt (~> 1.3) - select2-rails (3.3.0) - sass-rails (~> 3.2) + select2-rails (3.2.1) thor (~> 0.14) selenium-webdriver (2.31.0) childprocess (>= 0.2.5) @@ -338,7 +387,11 @@ GEM websocket (~> 1.0.4) shoulda-matchers (1.1.0) activesupport (>= 3.0.0) - slop (3.4.4) + simplecov (0.7.1) + multi_json (~> 1.0) + simplecov-html (~> 0.7.1) + simplecov-html (0.7.1) + slop (3.4.5) sprockets (2.2.2) hike (~> 1.2) multi_json (~> 1.0) @@ -348,15 +401,19 @@ GEM stringex (1.3.3) therubyracer (0.10.1) libv8 (~> 3.3.10) - thor (0.17.0) - tilt (1.3.3) - treetop (1.4.12) + thor (0.18.1) + tilt (1.4.1) + timecop (0.6.2.2) + treetop (1.4.14) polyglot polyglot (>= 0.3.1) truncate_html (0.5.5) + turbo-sprockets-rails3 (0.3.6) + railties (> 3.2.8, < 4.0.0) + sprockets (>= 2.0.0) turn (0.8.3) ansi - tzinfo (0.3.35) + tzinfo (0.3.37) uglifier (1.2.4) execjs (>= 0.3.0) multi_json (>= 1.0.2) @@ -364,7 +421,7 @@ GEM kgio (~> 2.6) rack raindrops (~> 0.7) - uuidtools (2.1.3) + uuidtools (2.1.4) versioncake (0.4.0) actionpack (>= 3.0) activesupport (>= 3.0) @@ -384,32 +441,44 @@ DEPENDENCIES aws-sdk bugsnag capybara + chili! coffee-rails (~> 3.2.1) comfortable_mexican_sofa compass-rails database_cleaner (= 0.7.1) + db2fog debugger-linecache + deface! + eaterprises_feature! + enterprises_distributor_info_rich_text_feature! factory_girl_rails faker haml jquery-rails letter_opener + local_organics_feature! + newrelic_rpm + oj pg pry-debugger - rails (= 3.2.11) + rabl + rails (= 3.2.13) representative_view rspec-rails + sass sass-rails (~> 3.2.3) shoulda-matchers simple_form! + simplecov spree! spree_auth_devise! - spree_heroku! spree_i18n! spree_last_address! spree_paypal_express! therubyracer + timecop truncate_html + turbo-sprockets-rails3 turn (~> 0.8.3) uglifier (>= 1.0.3) unicorn diff --git a/README.markdown b/README.markdown index 27c303df51..9a64221cd1 100644 --- a/README.markdown +++ b/README.markdown @@ -7,8 +7,8 @@ produce. ## Dependencies -* Rails 3.x -* Ruby >= 1.9.2 +* Rails 3.2.x +* Ruby >= 1.9.3 * PostgreSQL database * See Gemfile for a list of gems required @@ -75,6 +75,8 @@ speak to Andrew Spinks. * Andrew Spinks (http://github.com/andrewspinks) * Rohan Mitchell (http://github.com/rohanm) * Rob Harrington (http://github.com/oeoeaio) +* Alex Serdyuk (http://github.com/alexs333) +* David Cook (http://github.com/dacook) ## Licence diff --git a/app/assets/images/favicon.ico b/app/assets/images/favicon.ico new file mode 100644 index 0000000000..4011e1ba8b Binary files /dev/null and b/app/assets/images/favicon.ico differ diff --git a/app/assets/images/ofw.png b/app/assets/images/ofw.png new file mode 100644 index 0000000000..ac571bacd0 Binary files /dev/null and b/app/assets/images/ofw.png differ diff --git a/app/assets/javascripts/admin/bulk_product_update.js b/app/assets/javascripts/admin/bulk_product_update.js new file mode 100644 index 0000000000..b916d1cb5c --- /dev/null +++ b/app/assets/javascripts/admin/bulk_product_update.js @@ -0,0 +1,396 @@ +var productsApp = angular.module('bulk_product_update', []) + +productsApp.config(["$httpProvider", function(provider) { + provider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content'); +}]); + +productsApp.directive('ngDecimal', function () { + return { + require: 'ngModel', + link: function(scope, element, attrs, ngModel) { + var numRegExp = /^\d+(\.\d+)?$/; + + element.bind('blur', function() { + scope.$apply(ngModel.$setViewValue(ngModel.$modelValue)); + ngModel.$render(); + }); + + ngModel.$parsers.push(function(viewValue){ + if (angular.isString(viewValue) && numRegExp.test(viewValue)){ + if (viewValue.indexOf(".") == -1){ + return viewValue+".0"; + } + } + return viewValue; + }); + } + } +}); + +productsApp.directive('ngTrackProduct', function(){ + return { + require: 'ngModel', + link: function(scope, element, attrs, ngModel) { + var property_name = attrs.ngTrackProduct; + ngModel.$parsers.push(function(viewValue){ + if (ngModel.$dirty) { + addDirtyProperty(scope.dirtyProducts, scope.product.id, property_name, viewValue); + scope.displayDirtyProducts(); + } + return viewValue; + }); + } + } +}); + +productsApp.directive('ngTrackVariant', function(){ + return { + require: 'ngModel', + link: function(scope, element, attrs, ngModel) { + var property_name = attrs.ngTrackVariant; + ngModel.$parsers.push(function(viewValue){ + var dirtyVariants = {}; + if (scope.dirtyProducts.hasOwnProperty(scope.product.id) && scope.dirtyProducts[scope.product.id].hasOwnProperty("variants")) dirtyVariants = scope.dirtyProducts[scope.product.id].variants; + if (ngModel.$dirty) { + addDirtyProperty(dirtyVariants, scope.variant.id, property_name, viewValue); + addDirtyProperty(scope.dirtyProducts, scope.product.id, "variants", dirtyVariants); + scope.displayDirtyProducts(); + } + return viewValue; + }); + } + } +}); + +productsApp.directive('ngToggleVariants',function(){ + return { + link: function(scope,element,attrs){ + if (scope.displayProperties[scope.product.id].showVariants) { element.removeClass('icon-chevron-right'); element.addClass('icon-chevron-down'); } + else { element.removeClass('icon-chevron-down'); element.addClass('icon-chevron-right'); } + element.on('click', function(){ + scope.$apply(function(){ + if (scope.displayProperties[scope.product.id].showVariants){ + scope.displayProperties[scope.product.id].showVariants = false; + element.removeClass('icon-chevron-down'); + element.addClass('icon-chevron-right'); + } + else { + scope.displayProperties[scope.product.id].showVariants = true; + element.removeClass('icon-chevron-right'); + element.addClass('icon-chevron-down'); + } + }); + }); + } + }; +}); + +productsApp.directive('ngToggleColumn',function(){ + return { + link: function(scope,element,attrs){ + if (!scope.column.visible) { element.addClass("unselected"); } + element.click('click', function(){ + scope.$apply(function(){ + if (scope.column.visible) { scope.column.visible = false; element.addClass("unselected"); } + else { scope.column.visible = true; element.removeClass("unselected"); } + }); + }); + } + }; +}); + +productsApp.directive('ngToggleColumnList', function($compile){ + return { + link: function(scope,element,attrs){ + var dialogDiv = element.next(); + element.on('click',function(){ + var pos = element.position(); + var height = element.outerHeight(); + dialogDiv.css({ + position: "absolute", + top: (pos.top + height) + "px", + left: pos.left + "px", + }).toggle(); + }); + } + } +}); + +productsApp.directive('datetimepicker', function ($parse) { + return { + require: 'ngModel', + link: function (scope, element, attrs, ngModel) { + element.datetimepicker({ + dateFormat: 'yy-mm-dd', + timeFormat: 'HH:mm:ss', + stepMinute: 15, + onSelect:function (dateText, inst) { + scope.$apply(function(scope){ + ngModel.$setViewValue(dateText); // Fires ngModel.$parsers + }); + } + }); + } + } +}); + +productsApp.controller('AdminBulkProductsCtrl', function($scope, $timeout, $http, dataFetcher) { + $scope.updateStatusMessage = { + text: "", + style: {} + } + + $scope.columns = { + name: { name: 'Name', visible: true }, + supplier: { name: 'Supplier', visible: true }, + price: { name: 'Price', visible: true }, + on_hand: { name: 'On Hand', visible: true }, + available_on: { name: 'Available On', visible: true } + } + + $scope.initialise = function(spree_api_key){ + var authorise_api_reponse = ""; + dataFetcher('/api/users/authorise_api?token='+spree_api_key).then(function(data){ + authorise_api_reponse = data; + $scope.spree_api_key_ok = data.hasOwnProperty("success") && data["success"] == "Use of API Authorised"; + if ($scope.spree_api_key_ok){ + $http.defaults.headers.common['X-Spree-Token'] = spree_api_key; + dataFetcher('/api/enterprises?template=bulk_index;q[is_primary_producer_eq]=true').then(function(data){ + $scope.suppliers = data; + // Need to have suppliers before we get products so we can match suppliers to product.supplier + dataFetcher('/api/products?template=bulk_index').then(function(data){ + $scope.resetProducts(data); + }); + }); + } + else if (authorise_api_reponse.hasOwnProperty("error")){ $scope.api_error_msg = authorise_api_reponse("error"); } + else{ api_error_msg = "You don't have an API key yet. An attempt was made to generate one, but you are currently not authorised, please contact your site administrator for access." } + }); + }; + + $scope.resetProducts = function(data){ + $scope.products = data; + $scope.dirtyProducts = {}; + $scope.displayProperties = $scope.displayProperties || {}; + angular.forEach($scope.products,function(product){ + $scope.displayProperties[product.id] = $scope.displayProperties[product.id] || { showVariants: false }; + $scope.matchSupplier(product); + }); + } + + $scope.matchSupplier = function(product){ + for (i in $scope.suppliers){ + var supplier = $scope.suppliers[i]; + if (angular.equals(supplier,product.supplier)){ + product.supplier = supplier; + break; + } + } + } + + $scope.updateOnHand = function(product){ + product.on_hand = onHand(product); + } + + $scope.editWarn = function(product,variant){ + if ( ( $scope.dirtyProductCount() > 0 && confirm("Unsaved changes will be lost. Continue anyway?") ) || ( $scope.dirtyProductCount() == 0 ) ){ + window.location = "/admin/products/"+product.permalink_live+(variant ? "/variants/"+variant.id : "")+"/edit"; + } + } + + $scope.deleteProduct = function(product){ + if (confirm("Are you sure?")){ + $http({ + method: 'DELETE', + url: '/api/products/'+product.id + }) + .success(function(data){ + $scope.products.splice($scope.products.indexOf(product),1); + if ($scope.dirtyProducts.hasOwnProperty(product.id)) delete $scope.dirtyProducts[product.id]; + $scope.displayDirtyProducts(); + }) + } + } + + $scope.deleteVariant = function(product,variant){ + if (confirm("Are you sure?")){ + $http({ + method: 'DELETE', + url: '/api/products/'+product.id+"/variants/"+variant.id + }) + .success(function(data){ + product.variants.splice(product.variants.indexOf(variant),1); + if ($scope.dirtyProducts.hasOwnProperty(product.id) && $scope.dirtyProducts[product.id].hasOwnProperty("variants") && $scope.dirtyProducts[product.id].variants.hasOwnProperty(variant.id)) delete $scope.dirtyProducts[product.id].variants[variant.id]; + $scope.displayDirtyProducts(); + }) + } + } + + $scope.cloneProduct = function(product){ + dataFetcher("/admin/products/"+product.permalink_live+"/clone.json").then(function(data){ + // Ideally we would use Spree's built in respond_override helper here to redirect the user after a successful clone with .json in the accept headers + // However, at the time of writing there appears to be an issue which causes the respond_with block in the destroy action of Spree::Admin::Product to break + // when a respond_overrride for the clone action is used. + var id = data.product.id; + dataFetcher("/api/products/"+id+"?template=bulk_show").then(function(data){ + var newProduct = data; + $scope.matchSupplier(newProduct); + $scope.products.push(newProduct); + }); + }); + } + + $scope.hasVariants = function(product){ + return Object.keys(product.variants).length > 0; + } + + $scope.updateProducts = function(productsToSubmit){ + $scope.displayUpdating(); + $http({ + method: 'POST', + url: '/admin/products/bulk_update', + data: productsToSubmit + }) + .success(function(data){ + if (angular.toJson($scope.products) == angular.toJson(data)){ + $scope.resetProducts(data); + $scope.displaySuccess(); + } + else{ + $scope.displayFailure("Product lists do not match."); + } + }) + .error(function(data,status){ + $scope.displayFailure("Server returned with error status: "+status); + }); + } + + $scope.prepareProductsForSubmit = function(){ + var productsToSubmit = filterSubmitProducts($scope.dirtyProducts); + $scope.updateProducts(productsToSubmit); + } + + $scope.setMessage = function(model,text,style,timeout){ + model.text = text; + model.style = style; + if (model.timeout) $timeout.cancel(model.timeout); + if (timeout){ + model.timeout = $timeout(function() { $scope.setMessage(model,"",{},false); }, timeout, true); + } + } + + $scope.displayUpdating = function(){ + $scope.setMessage($scope.updateStatusMessage,"Updating...",{ color: "orange" },false); + } + + $scope.displaySuccess = function(){ + $scope.setMessage($scope.updateStatusMessage,"Update complete",{ color: "green" },3000); + } + + $scope.displayFailure = function(failMessage){ + $scope.setMessage($scope.updateStatusMessage,"Updating failed. "+failMessage,{ color: "red" },10000); + } + + $scope.displayDirtyProducts = function(){ + if ($scope.dirtyProductCount() > 0) $scope.setMessage($scope.updateStatusMessage,"Changes to "+$scope.dirtyProductCount()+" products remain unsaved.",{ color: "gray" },false); + else $scope.setMessage($scope.updateStatusMessage,"",{},false); + } + + $scope.dirtyProductCount = function(){ + return Object.keys($scope.dirtyProducts).length; + } +}); + +productsApp.factory('dataFetcher', function($http,$q){ + return function(dataLocation){ + var deferred = $q.defer(); + $http.get(dataLocation).success(function(data) { + deferred.resolve(data); + }).error(function(){ + deferred.reject(); + }); + return deferred.promise; + }; +}); + +function onHand(product){ + var onHand = 0; + if(product.hasOwnProperty('variants') && product.variants instanceof Object){ + angular.forEach(product.variants, function(variant) { + onHand = parseInt( onHand ) + parseInt( variant.on_hand > 0 ? variant.on_hand : 0 ); + }); + } + else{ + onHand = 'error'; + } + return onHand; +} + +function filterSubmitProducts(productsToFilter){ + var filteredProducts= []; + + if (productsToFilter instanceof Object){ + angular.forEach(productsToFilter, function(product){ + if (product.hasOwnProperty("id")){ + var filteredProduct = {}; + var filteredVariants = []; + + if (product.hasOwnProperty("variants")){ + angular.forEach(product.variants, function(variant){ + if (variant.deleted_at == null && variant.hasOwnProperty("id")){ + var hasUpdateableProperty = false; + var filteredVariant = {}; + filteredVariant.id = variant.id; + if (variant.hasOwnProperty("on_hand")) { filteredVariant.on_hand = variant.on_hand; hasUpdatableProperty = true; } + if (variant.hasOwnProperty("price")) { filteredVariant.price = variant.price; hasUpdatableProperty = true; } + if (hasUpdatableProperty) filteredVariants.push(filteredVariant); + } + }); + } + + var hasUpdatableProperty = false; + filteredProduct.id = product.id; + if (product.hasOwnProperty("name")) { filteredProduct.name = product.name; hasUpdatableProperty = true; } + if (product.hasOwnProperty("supplier")) { filteredProduct.supplier_id = product.supplier.id; hasUpdatableProperty = true; } + if (product.hasOwnProperty("price")) { filteredProduct.price = product.price; hasUpdatableProperty = true; } + if (product.hasOwnProperty("on_hand") && filteredVariants.length == 0) { filteredProduct.on_hand = product.on_hand; hasUpdatableProperty = true; } //only update if no variants present + if (product.hasOwnProperty("available_on")) { filteredProduct.available_on = product.available_on; hasUpdatableProperty = true; } + if (filteredVariants.length > 0) { filteredProduct.variants_attributes = filteredVariants; hasUpdatableProperty = true; } // Note that the name of the property changes to enable mass assignment of variants attributes with rails + + if (hasUpdatableProperty) filteredProducts.push(filteredProduct); + } + }); + } + return filteredProducts; +} + +function addDirtyProperty(dirtyObjects, objectID, propertyName, propertyValue){ + if (dirtyObjects.hasOwnProperty(objectID)){ + dirtyObjects[objectID][propertyName] = propertyValue; + } + else { + dirtyObjects[objectID] = {}; + dirtyObjects[objectID]["id"] = objectID; + dirtyObjects[objectID][propertyName] = propertyValue; + } +} + +function removeCleanProperty(dirtyObjects, objectID, propertyName){ + if (dirtyObjects.hasOwnProperty(objectID) && dirtyObjects[objectID].hasOwnProperty(propertyName)) delete dirtyObjects[objectID][propertyName]; + if (dirtyObjects.hasOwnProperty(objectID) && Object.keys(dirtyObjects[objectID]).length <= 1) delete dirtyObjects[objectID]; +} + +function toObjectWithIDKeys(array){ + var object = {}; + //if (array instanceof Array){ + for (i in array){ + if (array[i] instanceof Object && array[i].hasOwnProperty("id")){ + object[array[i].id] = angular.copy(array[i]); + if (array[i].hasOwnProperty("variants") && array[i].variants instanceof Array){ + object[array[i].id].variants = toObjectWithIDKeys(array[i].variants); + } + } + } + //} + return object; +} \ No newline at end of file diff --git a/app/assets/stylesheets/admin/products.css.scss b/app/assets/stylesheets/admin/products.css.scss index 8cb9b9a778..966b983b67 100644 --- a/app/assets/stylesheets/admin/products.css.scss +++ b/app/assets/stylesheets/admin/products.css.scss @@ -1,3 +1,49 @@ #product_distributors_field span { display: block; } + +tbody.odd { + tr.product { td { background-color: white; } } + tr.variant.odd { td { background-color: lighten(#eff5fc, 3); } } + tr.variant.even { td { background-color: white; } } +} +tbody.even { + tr.product { td { background-color: darken(#eff5fc, 1); } } + tr.variant.odd { td { background-color: lighten(#eff5fc, 2); } } + tr.variant.even { td { background-color: darken(#eff5fc, 1); } } +} + +tbody tr.product td.actions { background-color: transparent; } +tbody tr.variant td.actions { background-color: transparent; } +tbody tr.variant td { padding: 5px 10px; } + +th.left-actions, td.left-actions { + background-color: transparent !important; + border: none !important; + border-right: 1px solid #cee1f4 !important; +} + +li.column-list-item { + border-radius: 3px; + padding: 2px 20px; + margin: 2px 1px; + border: 2px solid darken(#5498da, 3); + background-color: #5498da; + color: white; + font-size: 100%; + cursor: default; +} + +li.column-list-item.unselected { + background-color: white; + border: 2px solid lightgray; + color: darkgray; + font-size: 100%; +} + +ul.column-list{ + padding: 5px 8px; + border-radius: 3px; + border: solid 1px darkgray; + list-style:none +} \ No newline at end of file diff --git a/app/assets/stylesheets/store/openfoodweb.css.scss b/app/assets/stylesheets/store/openfoodweb.css.scss index bbb0f2f1a5..79084afae7 100644 --- a/app/assets/stylesheets/store/openfoodweb.css.scss +++ b/app/assets/stylesheets/store/openfoodweb.css.scss @@ -234,6 +234,11 @@ fieldset#product-distributor-details { } } +/* Checkout address page */ +#checkout .alternative-available-distributors { + padding-top: 30px; +} + /* Delivery fees table on checkout page */ #delivery-fees { diff --git a/app/assets/stylesheets/store/variables.css.scss b/app/assets/stylesheets/store/variables.css.scss index 4eab8c3ce2..f33a4318e9 100644 --- a/app/assets/stylesheets/store/variables.css.scss +++ b/app/assets/stylesheets/store/variables.css.scss @@ -7,7 +7,7 @@ $c_red: #e45353 !default; /* Error red */ $layout_background_color: #FFFFFF !default; $title_text_color: #404042 !default; $body_text_color: #404042 !default; -$link_text_color: #006066 !default; +$link_text_color: #00ADEE !default; $product_background_color: #FFFFFF !default; $product_title_text_color: #404042 !default; @@ -55,6 +55,10 @@ $ff_base: 'Ubuntu', sans-serif !default; $button_font_size: 12px !default; $input_box_font_size: 13px !default; $base_font_size: 12px !default; - $border_color: lighten($body_text_color, 60); - $default_border: 1px solid $border_color; + $border_color: lighten($body_text_color, 60) !default; + $default_border: 1px solid $border_color !default; $button_border_color: rgba(0, 138, 189, .75) !default; + $table_head_color: lighten($body_text_color, 60) !default; + + +@import "./variables_changes.css.scss"; diff --git a/app/controllers/enterprises_controller.rb b/app/controllers/enterprises_controller.rb index a582d0e6c0..d93db83ab0 100644 --- a/app/controllers/enterprises_controller.rb +++ b/app/controllers/enterprises_controller.rb @@ -1,6 +1,5 @@ include Spree::ProductsHelper class EnterprisesController < BaseController - helper Spree::AnalyticsHelper def index @enterprises = Enterprise.all diff --git a/app/controllers/spree/admin/products_controller_decorator.rb b/app/controllers/spree/admin/products_controller_decorator.rb new file mode 100644 index 0000000000..bbbf8a3a5b --- /dev/null +++ b/app/controllers/spree/admin/products_controller_decorator.rb @@ -0,0 +1,36 @@ +Spree::Admin::ProductsController.class_eval do + before_filter :load_spree_api_key, :only => :bulk_edit + + alias_method :location_after_save_original, :location_after_save + + respond_to :json, :only => :clone + + #respond_override :clone => { :json => {:success => lambda { redirect_to bulk_index_admin_products_url+"?q[id_eq]=#{@new.id}" } } } + + def bulk_update + collection_hash = Hash[params[:_json].each_with_index.map { |p,i| [i,p] }] + product_set = Spree::ProductSet.new({:collection_attributes => collection_hash}) + + if product_set.save + redirect_to "/api/products?template=bulk_index" + else + render :nothing => true + end + end + + protected + def location_after_save + if URI(request.referer).path == '/admin/products/bulk_edit' + bulk_edit_admin_products_url + else + location_after_save_original + end + end + + private + + def load_spree_api_key + current_user.generate_spree_api_key! unless spree_current_user.spree_api_key + @spree_api_key = spree_current_user.spree_api_key + end +end \ No newline at end of file diff --git a/app/controllers/spree/admin/reports_controller_decorator.rb b/app/controllers/spree/admin/reports_controller_decorator.rb index 6de3fc1575..f922f39453 100644 --- a/app/controllers/spree/admin/reports_controller_decorator.rb +++ b/app/controllers/spree/admin/reports_controller_decorator.rb @@ -333,11 +333,11 @@ Spree::Admin::ReportsController.class_eval do if params[:q][:completed_at_gt].blank? params[:q][:completed_at_gt] = Time.zone.now.beginning_of_month else - params[:q][:completed_at_gt] = Time.zone.parse(params[:q][:completed_at_gt]).beginning_of_day rescue Time.zone.now.beginning_of_month + params[:q][:completed_at_gt] = Time.zone.parse(params[:q][:completed_at_gt]) rescue Time.zone.now.beginning_of_month end if params[:q] && !params[:q][:completed_at_lt].blank? - params[:q][:completed_at_lt] = Time.zone.parse(params[:q][:completed_at_lt]).end_of_day rescue "" + params[:q][:completed_at_lt] = Time.zone.parse(params[:q][:completed_at_lt]) rescue "" end params[:q][:meta_sort] ||= "completed_at.desc" diff --git a/app/controllers/spree/api/enterprises_controller.rb b/app/controllers/spree/api/enterprises_controller.rb new file mode 100644 index 0000000000..545372a285 --- /dev/null +++ b/app/controllers/spree/api/enterprises_controller.rb @@ -0,0 +1,17 @@ +module Spree + module Api + class EnterprisesController < Spree::Api::BaseController + respond_to :json + + def bulk_show + @enterprise = Enterprise.find(params[:id]) + respond_with(@enterprise) + end + + def bulk_index + @enterprises = Enterprise.ransack(params[:q]).result + respond_with(@enterprises) + end + end + end +end \ No newline at end of file diff --git a/app/controllers/spree/orders_controller_decorator.rb b/app/controllers/spree/orders_controller_decorator.rb index 2dbd0f04a1..10788004a3 100644 --- a/app/controllers/spree/orders_controller_decorator.rb +++ b/app/controllers/spree/orders_controller_decorator.rb @@ -19,25 +19,6 @@ Spree::OrdersController.class_eval do end end - def update_distribution - @order = current_order(true) - - if params[:commit] == 'Choose Hub' - distributor = Enterprise.is_distributor.find params[:order][:distributor_id] - @order.set_distributor! distributor - - flash[:notice] = 'Your hub has been selected.' - redirect_to request.referer - - elsif params[:commit] == 'Choose Order Cycle' - order_cycle = OrderCycle.active.find params[:order][:order_cycle_id] - @order.set_order_cycle! order_cycle - - flash[:notice] = 'Your order cycle has been selected.' - redirect_to request.referer - end - end - def select_distributor distributor = Enterprise.is_distributor.find params[:id] @@ -57,6 +38,24 @@ Spree::OrdersController.class_eval do redirect_to root_path end + def update_distribution + @order = current_order(true) + + if params[:commit] == 'Choose Hub' + distributor = Enterprise.is_distributor.find params[:order][:distributor_id] + @order.set_distributor! distributor + + flash[:notice] = 'Your hub has been selected.' + redirect_to request.referer + + elsif params[:commit] == 'Choose Order Cycle' + order_cycle = OrderCycle.active.find params[:order][:order_cycle_id] + @order.set_order_cycle! order_cycle + + flash[:notice] = 'Your order cycle has been selected.' + redirect_to request.referer + end + end private diff --git a/app/helpers/html_helper.rb b/app/helpers/html_helper.rb new file mode 100644 index 0000000000..85dc5b1c53 --- /dev/null +++ b/app/helpers/html_helper.rb @@ -0,0 +1,5 @@ +module HtmlHelper + def strip_html(html) + strip_tags(html).gsub(/ /i, ' ').gsub(/&/i, '&') + end +end diff --git a/app/mailers/spree/order_mailer_decorator.rb b/app/mailers/spree/order_mailer_decorator.rb new file mode 100644 index 0000000000..1ce563ad56 --- /dev/null +++ b/app/mailers/spree/order_mailer_decorator.rb @@ -0,0 +1,3 @@ +Spree::OrderMailer.class_eval do + helper HtmlHelper +end diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index 75ba517a09..885ba0cddf 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -48,7 +48,7 @@ class Enterprise < ActiveRecord::Base def to_param "#{id}-#{name.parameterize}" end - + def distributed_variants Spree::Variant.joins(:product).merge(Spree::Product.in_distributor(self)).select('spree_variants.*') end @@ -57,6 +57,9 @@ class Enterprise < ActiveRecord::Base Spree::Variant.joins(:product).merge(Spree::Product.in_product_distribution_by(self)).select('spree_variants.*') end + def available_variants + Spree::Variant.joins(:product => :product_distributions).where('product_distributions.distributor_id=?', self.id) + end private diff --git a/app/models/spree/gateway/migs.rb b/app/models/spree/gateway/migs.rb new file mode 100644 index 0000000000..bfffc6de12 --- /dev/null +++ b/app/models/spree/gateway/migs.rb @@ -0,0 +1,19 @@ +module Spree + class Gateway::Migs < Gateway + preference :login, :string + preference :password, :string + + attr_accessible :preferred_login, :preferred_password + + + def provider_class + ActiveMerchant::Billing::MigsGateway + end + + def options_with_test_preference + options_without_test_preference.merge(:test => self.preferred_test_mode) + end + + alias_method_chain :options, :test_preference + end +end diff --git a/app/models/spree/line_item_decorator.rb b/app/models/spree/line_item_decorator.rb index aac21c1225..ec4f83e5e2 100644 --- a/app/models/spree/line_item_decorator.rb +++ b/app/models/spree/line_item_decorator.rb @@ -5,11 +5,16 @@ Spree::LineItem.class_eval do before_create :set_itemwise_shipping_method + def itemwise_shipping_cost order = OpenStruct.new :line_items => [self] shipping_method.compute_amount(order) end + def update_itemwise_shipping_method_without_callbacks!(distributor) + update_column(:shipping_method_id, self.product.shipping_method_for_distributor(distributor).id) + end + private diff --git a/app/models/spree/order_decorator.rb b/app/models/spree/order_decorator.rb index c9ff0a0a7e..62839f3d52 100644 --- a/app/models/spree/order_decorator.rb +++ b/app/models/spree/order_decorator.rb @@ -8,9 +8,11 @@ Spree::Order.class_eval do validate :products_available_from_new_distribution, :if => lambda { distributor_id_changed? || order_cycle_id_changed? } attr_accessible :order_cycle_id, :distributor_id + before_validation :shipping_address_from_distributor + before_save :update_line_item_shipping_methods after_create :set_default_shipping_method - + def products_available_from_new_distribution # Check that the line_items in the current order are available from a newly selected distribution errors.add(:base, "Distributor or order cycle cannot supply the products in your cart") unless DistributionChangeValidator.new(self).can_change_to_distribution?(distributor, order_cycle) @@ -22,6 +24,12 @@ Spree::Order.class_eval do save! end + def empty! + line_items.destroy_all + adjustments.destroy_all + set_default_shipping_method + end + def set_distributor!(distributor) self.distributor = distributor self.order_cycle = nil unless self.order_cycle.andand.has_distributor? distributor @@ -44,7 +52,7 @@ Spree::Order.class_eval do line_item.assign_attributes(attributes) line_item.save! end - + def line_item_variants line_items.map { |li| li.variant } end @@ -80,4 +88,11 @@ Spree::Order.class_eval do end end end + + def update_line_item_shipping_methods + if %w(cart address delivery resumed).include? state + self.line_items.each { |li| li.update_itemwise_shipping_method_without_callbacks!(distributor) } + self.update! + end + end end diff --git a/app/models/spree/product_set.rb b/app/models/spree/product_set.rb new file mode 100644 index 0000000000..ce316641bb --- /dev/null +++ b/app/models/spree/product_set.rb @@ -0,0 +1,39 @@ +class Spree::ProductSet < ModelSet + def initialize(attributes={}) + super(Spree::Product, [], proc { |attrs| attrs[:product_id].blank? }, attributes) + end + + # A separate method of updating products was required due to an issue with the way Rails' assign_attributes and updates_attributes behave when delegated attributes of a nested + # object are updated via the parent object (ie. price of variants). Updating such attributes by themselves did not work using: + # product.update_attributes( { variants_attributes: [ { id: y, price: xx.x } ] } ) + # and so an explicit call to update attributes on each individual variant was required. ie: + # variant.update_attributes( { price: xx.x } ) + def update_attributes(attributes) + e = @collection.detect { |e| e.id.to_s == attributes[:id].to_s && !e.id.nil? } + if e.nil? + @klass.new(attributes).save unless @reject_if.andand.call(attributes) + else + e.update_attributes(attributes.except(:id,:variants_attributes)) and (attributes[:variants_attributes] ? update_variants_attributes(e,attributes[:variants_attributes]) : true ) + end + end + + def update_variants_attributes(product,variants_attributes) + variants_attributes.each do |attributes| + e = product.variants.detect { |e| e.id.to_s == attributes[:id].to_s && !e.id.nil? } + if !e.nil? + e.update_attributes(attributes.except(:id)) + end + end + end + + def collection_attributes=(attributes) + @collection = Spree::Product.where( :id => attributes.each_value.map{ |p| p[:id] } ) + @collection_hash = attributes + end + + def save + @collection_hash.each_value.all? do |product_attributes| + update_attributes(product_attributes) + end + end +end \ No newline at end of file diff --git a/app/overrides/add_bulk_edit_tab_to_products_admin_sub_menu.rb b/app/overrides/add_bulk_edit_tab_to_products_admin_sub_menu.rb new file mode 100644 index 0000000000..f6b6f94e9f --- /dev/null +++ b/app/overrides/add_bulk_edit_tab_to_products_admin_sub_menu.rb @@ -0,0 +1,4 @@ +Deface::Override.new(:virtual_path => "spree/admin/shared/_product_sub_menu", + :name => "add_bulk_edit_tab_to_products_admin_sub_menu", + :insert_bottom => "[data-hook='admin_product_sub_tabs']", + :text => "<%= tab :bulk_product_edit, :url => bulk_edit_admin_products_path %>") \ No newline at end of file diff --git a/app/overrides/add_feedback_script.rb b/app/overrides/add_feedback_script.rb deleted file mode 100644 index 1bfb854c10..0000000000 --- a/app/overrides/add_feedback_script.rb +++ /dev/null @@ -1,5 +0,0 @@ -Deface::Override.new(:virtual_path => "spree/layouts/spree_application", - :insert_bottom => "[data-hook='inside_head']", - :partial => "layouts/feedback_script", - :name => "add_feedback_script", - :original => '429dfd9824ee588f51fb1b69013933424f149592') \ No newline at end of file diff --git a/app/overrides/add_order_cycles_admin_tab.rb b/app/overrides/add_order_cycles_admin_tab.rb index bab6566fe8..6e36e413a8 100644 --- a/app/overrides/add_order_cycles_admin_tab.rb +++ b/app/overrides/add_order_cycles_admin_tab.rb @@ -1,5 +1,5 @@ Deface::Override.new(:virtual_path => "spree/layouts/admin", :name => "add_order_cycles_admin_tab", :insert_bottom => "[data-hook='admin_tabs'], #admin_tabs[data-hook]", - :text => "<%= tab 'Order Cycles', :url => main_app.admin_order_cycles_path %>", + :text => "<%= tab :order_cycles, :url => main_app.admin_order_cycles_path %>", :original => 'd4e321201ecb543e92192a031c8896a45dde3576') \ No newline at end of file diff --git a/app/overrides/replace_payment_name_with_description.rb b/app/overrides/replace_payment_name_with_description.rb new file mode 100644 index 0000000000..60566fe780 --- /dev/null +++ b/app/overrides/replace_payment_name_with_description.rb @@ -0,0 +1,5 @@ +Deface::Override.new(:virtual_path => "spree/payments/_payment", + :replace => "code[erb-loud]:contains('content_tag(:span, payment.payment_method.name)')", + :text => "<%= content_tag( :span, ( payment.payment_method.description || payment.payment_method.name ).html_safe ) %>", + :name => "replace_payment_name_with_description", + :original => 'dff62efcadc0f9e6513b0f81a51ebbda035f78f6') \ No newline at end of file diff --git a/app/views/admin/enterprises/show.html.haml b/app/views/admin/enterprises/show.html.haml index a2eb9027fa..d4a4ed0743 100644 --- a/app/views/admin/enterprises/show.html.haml +++ b/app/views/admin/enterprises/show.html.haml @@ -6,7 +6,7 @@ %tr %th Description: %td= @enterprise.description - %tr + %tr{"data-hook" => "long_description"} %th Extended Description: %td= @enterprise.long_description.andand.html_safe %tr diff --git a/app/views/enterprises/_distributor_details.html.haml b/app/views/enterprises/_distributor_details.html.haml index 950ba1e7f2..a3f070b451 100644 --- a/app/views/enterprises/_distributor_details.html.haml +++ b/app/views/enterprises/_distributor_details.html.haml @@ -1,23 +1,24 @@ -%h2= distributor.name -%p - %strong Address: - %br/ - = render 'spree/shared/address', :address => distributor.address -%p - %strong Next collection time: - %br/ - = distributor.next_collection_at -%p - %strong Regular collection times: - %br/ - = distributor.pickup_times -%p - %strong Contact: - %br/ - = distributor.contact - %br/ - = "Phone: #{distributor.phone}" - %br/ - = "Email: #{distributor.email}" -%p= distributor.description -%p= link_to distributor.website, distributor.website if distributor.website +.distributor-details{'data-hook' => 'distributor-details'} + %h2= distributor.name + %p + %strong Address: + %br/ + = render 'spree/shared/address', :address => distributor.address + %p + %strong Next collection time: + %br/ + = distributor.next_collection_at + %p + %strong Regular collection times: + %br/ + = distributor.pickup_times + %p + %strong Contact: + %br/ + = distributor.contact + %br/ + = "Phone: #{distributor.phone}" + %br/ + = "Email: #{distributor.email}" + %p= distributor.description + %p= link_to distributor.website, distributor.website if distributor.website diff --git a/app/views/spree/admin/products/bulk_edit.html.haml b/app/views/spree/admin/products/bulk_edit.html.haml new file mode 100644 index 0000000000..187be578e7 --- /dev/null +++ b/app/views/spree/admin/products/bulk_edit.html.haml @@ -0,0 +1,79 @@ +- content_for :page_title do + = "Bulk Edit Products" + +- content_for :page_actions do + %div{ :class => "toolbar", 'data-hook' => "toolbar" } + %ul{ :class => "actions header-action-links inline-menu" } + %li#new_product_link + = button_link_to t(:new_product), new_object_url, { :remote => true, :icon => 'icon-plus', :id => 'admin_new_product' } + += render :partial => 'spree/admin/shared/product_sub_menu' + +%div#new_product(data-hook) + + + +%div{ 'ng-app' => 'bulk_product_update', 'ng-controller' => 'AdminBulkProductsCtrl', 'ng-init' => "initialise('#{@spree_api_key}');" } + %div{ 'ng-show' => '!spree_api_key_ok' } + {{ api_error_msg }} + %div + %div.options + Filter Results: + %input.search{ 'ng-model' => 'query', :type => 'text', 'placeholder' => 'Search Value' } + %input{ :type => 'button', :value => 'Toggle Columns', 'ng-toggle-column-list' => true } + %div{ :style => 'display: none;' } + %ul.column-list{ style: 'border: 1px solid darkgray; background-color: white;' } + %li.column-list-item{ 'ng-toggle-column' => 'column', 'ng-repeat' => 'column in columns' } + {{ column.name }} + %br.clear + %br.clear + %table.index#listing_products + %thead + %tr + %th.left-actions + %th{ 'ng-show' => 'columns.name.visible' } Name + %th{ 'ng-show' => 'columns.supplier.visible' } Supplier + %th{ 'ng-show' => 'columns.price.visible' } Price + %th{ 'ng-show' => 'columns.on_hand.visible' } On Hand + %th{ 'ng-show' => 'columns.available_on.visible' } Av. On + %th.actions + %tbody{ 'ng-repeat' => 'product in products | filter:query', 'ng-class-even' => "'even'", 'ng-class-odd' => "'odd'" } + %tr.product + %td.left-actions + %a{ 'ng-toggle-variants' => 'true', :class => "view-variants icon-chevron-right", 'ng-show' => 'hasVariants(product)' } + %td{ 'ng-show' => 'columns.name.visible' } + %input{ 'ng-model' => "product.name", :name => 'product_name', 'ng-track-product' => 'name', :type => 'text' } + %td{ 'ng-show' => 'columns.supplier.visible' } + %select.select2{ 'ng-model' => 'product.supplier', :name => 'supplier', 'ng-track-product' => 'supplier', 'ng-options' => 's.name for s in suppliers' } + %td{ 'ng-show' => 'columns.price.visible' } + %input{ 'ng-model' => 'product.price', 'ng-decimal' => :true, :name => 'price', 'ng-track-product' => 'price', :type => 'text' } + %td{ 'ng-show' => 'columns.on_hand.visible' } + %span{ 'ng-bind' => 'product.on_hand', :name => 'on_hand', 'ng-show' => 'hasVariants(product)' } + %input.field{ 'ng-model' => 'product.on_hand', :name => 'on_hand', 'ng-track-product' => 'on_hand', 'ng-show' => '!hasVariants(product)', :type => 'number' } + %td{ 'ng-show' => 'columns.available_on.visible' } + %input{ 'ng-model' => 'product.available_on', :name => 'available_on', 'ng-track-product' => 'available_on', 'datetimepicker' => 'product.available_on', type: "text" } + %td.actions + %a{ 'ng-click' => 'cloneProduct(product)', :class => "clone-product icon-copy no-text" } + %td.actions + %a{ 'ng-click' => 'editWarn(product)', :class => "edit-product icon-edit no-text" } + %td.actions + %a{ 'ng-click' => 'deleteProduct(product)', :class => "delete-product icon-trash no-text" } + %tr.variant{ 'ng-repeat' => 'variant in product.variants', 'ng-show' => 'displayProperties[product.id].showVariants', 'ng-class-even' => "'even'", 'ng-class-odd' => "'odd'" } + %td.left-actions + %a{ :class => "variant-item icon-caret-right" } + %td{ 'ng-show' => 'columns.name.visible' } + {{ variant.options_text }} + %td{ 'ng-show' => 'columns.supplier.visible' } + %td{ 'ng-show' => 'columns.price.visible' } + %input{ 'ng-model' => 'variant.price', 'ng-decimal' => :true, :name => 'variant_price', 'ng-track-variant' => 'price', :type => 'text' } + %td{ 'ng-show' => 'columns.on_hand.visible' } + %input.field{ 'ng-model' => 'variant.on_hand', 'ng-change' => 'updateOnHand(product)', :name => 'variant_on_hand', 'ng-track-variant' => 'on_hand', :type => 'number' } + %td{ 'ng-show' => 'columns.available_on.visible' } + %td.actions + %td.actions + %a{ 'ng-click' => 'editWarn(product,variant)', :class => "edit-variant icon-edit no-text" } + %td.actions + %a{ 'ng-click' => 'deleteVariant(product,variant)', :class => "delete-variant icon-trash no-text" } + %input{ :type => 'button', :value => 'Update', 'ng-click' => 'prepareProductsForSubmit()'} + %span{ id: "update-status-message", 'ng-style' => 'updateStatusMessage.style' } + {{ updateStatusMessage.text }} \ No newline at end of file diff --git a/app/views/spree/admin/reports/order_cycles.html.haml b/app/views/spree/admin/reports/order_cycles.html.haml index 4468f1d183..e8fb54c069 100644 --- a/app/views/spree/admin/reports/order_cycles.html.haml +++ b/app/views/spree/admin/reports/order_cycles.html.haml @@ -3,11 +3,11 @@ %br .date-range-filter %div{"class" => "left sub-field"} - = f.text_field :completed_at_gt, :class => 'datepicker' + = f.text_field :completed_at_gt, :class => 'datetimepicker' %br = label_tag nil, t(:start), :class => 'sub' %div{"class" => "right sub-field"} - = f.text_field :completed_at_lt, :class => 'datepicker' + = f.text_field :completed_at_lt, :class => 'datetimepicker' %br = label_tag nil, t(:stop) %br diff --git a/app/views/spree/api/enterprises/bulk_index.v1.rabl b/app/views/spree/api/enterprises/bulk_index.v1.rabl new file mode 100644 index 0000000000..f84733b401 --- /dev/null +++ b/app/views/spree/api/enterprises/bulk_index.v1.rabl @@ -0,0 +1,2 @@ +collection @enterprises +extends "spree/api/enterprises/bulk_show" diff --git a/app/views/spree/api/enterprises/bulk_show.v1.rabl b/app/views/spree/api/enterprises/bulk_show.v1.rabl new file mode 100644 index 0000000000..5a40b74aa1 --- /dev/null +++ b/app/views/spree/api/enterprises/bulk_show.v1.rabl @@ -0,0 +1,3 @@ +object @enterprise + +attributes :id, :name \ No newline at end of file diff --git a/app/views/spree/api/products/bulk_index.v1.rabl b/app/views/spree/api/products/bulk_index.v1.rabl new file mode 100644 index 0000000000..dfb9f20f2a --- /dev/null +++ b/app/views/spree/api/products/bulk_index.v1.rabl @@ -0,0 +1,2 @@ +collection @products.order('id ASC') +extends "spree/api/products/bulk_show" diff --git a/app/views/spree/api/products/bulk_show.v1.rabl b/app/views/spree/api/products/bulk_show.v1.rabl new file mode 100644 index 0000000000..9dbaaab402 --- /dev/null +++ b/app/views/spree/api/products/bulk_show.v1.rabl @@ -0,0 +1,11 @@ +object @product +attributes :id, :name, :price, :on_hand +node( :available_on ) { |p| p.available_on.strftime("%F %T") } +node( :permalink_live ) { |p| p.permalink } +node( :supplier ) do |p| + partial 'spree/api/enterprises/bulk_show', :object => p.supplier +end +node( :variants ) do |p| + partial 'spree/api/variants/bulk_index', :object => p.variants.order('id ASC') +end + diff --git a/app/views/spree/api/users/authorise_api.v1.rabl b/app/views/spree/api/users/authorise_api.v1.rabl new file mode 100644 index 0000000000..7cb0064e2e --- /dev/null +++ b/app/views/spree/api/users/authorise_api.v1.rabl @@ -0,0 +1,2 @@ +object false +node(:success) { "Use of API Authorised" } \ No newline at end of file diff --git a/app/views/spree/api/variants/bulk_index.v1.rabl b/app/views/spree/api/variants/bulk_index.v1.rabl new file mode 100644 index 0000000000..69f1b82f5f --- /dev/null +++ b/app/views/spree/api/variants/bulk_index.v1.rabl @@ -0,0 +1,2 @@ +collection @variants +extends "spree/api/variants/bulk_show" diff --git a/app/views/spree/api/variants/bulk_show.v1.rabl b/app/views/spree/api/variants/bulk_show.v1.rabl new file mode 100644 index 0000000000..3fed62bf99 --- /dev/null +++ b/app/views/spree/api/variants/bulk_show.v1.rabl @@ -0,0 +1,3 @@ +object @variant + +attributes :id, :options_text, :price, :on_hand \ No newline at end of file diff --git a/app/views/spree/checkout/_other_available_distributors.html.erb b/app/views/spree/checkout/_other_available_distributors.html.erb index b9a00e828f..765c71640a 100644 --- a/app/views/spree/checkout/_other_available_distributors.html.erb +++ b/app/views/spree/checkout/_other_available_distributors.html.erb @@ -1,13 +1,13 @@ <% if @order.state == 'address' %> -
- <% if alternative_available_distributors(@order) %> +
+ <% unless alternative_available_distributors(@order).empty? %> <%= form_for(@order) do |f| %> <%= f.label :distributor_label, "Alternative distributors for this order:" %> - <%= f.select :distributor_id, options_for_select( enterprises_options(alternative_available_distributors(@order)) ) %> - <%= f.submit "Change Distributor" %> - <% end %> + <%= f.select :distributor_id, options_for_select( enterprises_options(alternative_available_distributors(@order)) ) %> + <%= f.submit "Change Distributor" %> + <% end %> <% else %> - No alternative distributors available. + No alternative distributors available. <% end %>
<% end %> diff --git a/app/views/spree/order_mailer/confirm_email.text.erb b/app/views/spree/order_mailer/confirm_email.text.erb index 29549e4ffa..3277ccaf00 100644 --- a/app/views/spree/order_mailer/confirm_email.text.erb +++ b/app/views/spree/order_mailer/confirm_email.text.erb @@ -7,20 +7,20 @@ Order Summary ============================================================ Order for: <%= @order.bill_address.full_name %> <% @order.line_items.each do |item| %> - <%= item.variant.sku %> <%= raw(item.variant.product.name) %> <%= raw(item.variant.options_text) -%> (<%=item.quantity%>) @ <%= number_to_currency item.price %> = <%= number_to_currency(item.price * item.quantity) %> + <%= item.variant.sku %> <%= raw(item.variant.product.name) %> <%= raw(item.variant.options_text) -%> (<%=item.quantity%>) @ <%= item.single_money %> = <%= item.display_amount %> <% end %> ============================================================ -Subtotal: <%= number_to_currency @order.item_total %> +Subtotal: <%= @order.display_item_total %> <% @order.adjustments.each do |adjustment| %> - <%= raw(adjustment.label) %> <%= number_to_currency(adjustment.amount) %> + <%= raw(adjustment.label) %> <%= adjustment.display_amount %> <% end %> -Order Total: <%= number_to_currency(@order.total) %> +Order Total: <%= @order.display_total %> -<% if @order.payment_method.name.include? "EFT" %> +<% if @order.payments.first.payment_method.name.include? "EFT" %> ============================================================ Payment Details ============================================================ -<%= @order.payment_method.description.html_safe %> +<%= @order.payments.first.payment_method.description.html_safe %> <% end %> ============================================================ diff --git a/app/views/spree/products/_add_to_cart_distributor_choice.html.haml b/app/views/spree/products/_add_to_cart_distributor_choice.html.haml index 2a1246e1ac..79936442c7 100644 --- a/app/views/spree/products/_add_to_cart_distributor_choice.html.haml +++ b/app/views/spree/products/_add_to_cart_distributor_choice.html.haml @@ -1,2 +1,2 @@ -%div Distributor for your order: +.distributor Distributor for your order: = select_tag "distributor_id", options_from_collection_for_select([Enterprise.new]+distributor_collection, "id", "name", current_distributor.andand.id) diff --git a/app/views/spree/shared/_order_details_steps_data.html.erb b/app/views/spree/shared/_order_details_steps_data.html.erb index 396e2be2fd..ee68620787 100644 --- a/app/views/spree/shared/_order_details_steps_data.html.erb +++ b/app/views/spree/shared/_order_details_steps_data.html.erb @@ -1,49 +1,37 @@
- -
-
<%= "Customer Details" %> <%= link_to "(#{t(:edit)})", checkout_state_path(:address) unless @order.completed? %>
-
- Name: <%= order.bill_address.full_name %>
- Address: <%= order.bill_address.address1 + ", " + order.bill_address.city %> -
-
-
-
<%= "Distributor Details" %> <%# link_to "(#{t(:edit)})", checkout_state_path(:address) unless @order.completed? %>
-
- Distributor: <%= order.distributor.name %>
- Address: <%= order.distributor.address.address1 + ", " + order.distributor.address.city %> + <% if order.has_step?("address") %> +
+
<%= "Customer Details" %> <%= link_to "(#{t(:edit)})", checkout_state_path(:address) unless @order.completed? %>
+
+ <%= render 'enterprises/distributor_details', :distributor => order.distributor %> +
-
- + <% end %> +
+
-
id="eft-payment-alert"<% end %>> + +
<%= t(:payment_information) %> <%= link_to "(#{t(:edit)})", checkout_state_path(:payment) unless @order.completed? %>
- <% if order.payment_method.name.include? "PayPal" %> + <% if order.payments.any? { |payment| payment.payment_method.name.include? "PayPal" } %>
Your payment via PayPal has been processed successfully.
- <% elsif order.payment_method.name.include? "EFT" %> - <%= order.payment_method.description.html_safe %> - <% elsif order.credit_cards.empty? == false %> - - <%= image_tag "credit_cards/icons/#{order.credit_cards.first.cc_type}.png" %> - <%= t(:ending_in)%> <%= order.credit_cards.first.last_digits %> - -
- - <%= order.credit_cards.first.first_name %> - <%= order.credit_cards.first.last_name %> - - <% elsif order.payment_method.type == "Spree::PaymentMethod::Check" %> - <%= order.payment_method.description %> - <% end %> + <% end %> + <%= render order.payments.valid %>
-
\ No newline at end of file + +
diff --git a/config-angular/testacular.conf.js b/config-angular/testacular.conf.js index 9147464ce3..8c48c93db7 100644 --- a/config-angular/testacular.conf.js +++ b/config-angular/testacular.conf.js @@ -8,6 +8,7 @@ files = [ 'app/assets/javascripts/shared/angular-*.js', 'app/assets/javascripts/admin/order_cycle.js.erb.coffee', + 'app/assets/javascripts/admin/bulk_product_update.js', 'spec/javascripts/unit/**/*.js*' ]; diff --git a/config/application.rb b/config/application.rb index fa5411b9a6..02a159bc2f 100644 --- a/config/application.rb +++ b/config/application.rb @@ -37,6 +37,10 @@ module Openfoodweb OpenFoodWeb::Calculator::Weight] end + # Register Spree payment methods + initializer "spree.gateway.payment_methods", :after => "spree.register.payment_methods" do |app| + app.config.spree.payment_methods << Spree::Gateway::Migs + end # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers @@ -72,7 +76,7 @@ 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.initialize_on_precompile = true config.assets.precompile += ['store/all.css', 'store/all.js', 'admin/all.css', 'admin/*.js', 'admin/**/*.js', 'comfortable_mexican_sofa/*'] end end diff --git a/config/database.yml b/config/database.yml index 9633824f0f..3e0db65bae 100644 --- a/config/database.yml +++ b/config/database.yml @@ -3,6 +3,7 @@ development: encoding: unicode database: open_food_web_dev pool: 5 + host: localhost username: ofw password: f00d @@ -11,6 +12,7 @@ test: encoding: unicode database: open_food_web_test pool: 5 + host: localhost username: ofw password: f00d diff --git a/config/environments/development.rb b/config/environments/development.rb index dfd2d7b171..82599dd78a 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -26,7 +26,7 @@ Openfoodweb::Application.configure do config.assets.compress = false # Expands the lines which load the assets - config.assets.debug = true + config.assets.debug = false # Show emails using Letter Opener config.action_mailer.delivery_method = :letter_opener diff --git a/config/initializers/comfortable_mexican_sofa.rb b/config/initializers/comfortable_mexican_sofa.rb index 46dd0ad0a6..e526ab48ed 100644 --- a/config/initializers/comfortable_mexican_sofa.rb +++ b/config/initializers/comfortable_mexican_sofa.rb @@ -3,43 +3,43 @@ ComfortableMexicanSofa.configure do |config| # Title of the admin area # config.cms_title = 'ComfortableMexicanSofa CMS Engine' - + # Module responsible for authentication. You can replace it with your own. # It simply needs to have #authenticate method. See http_auth.rb for reference. config.admin_auth = 'CmsSpreeAuth' - + # Module responsible for public authentication. Similar to the above. You also # will have access to @cms_site, @cms_layout, @cms_page so you can use them in # your logic. Default module doesn't do anything. # config.public_auth = 'ComfortableMexicanSofa::DummyAuth' - - # Default url to access admin area is http://yourhost/cms-admin/ + + # Default url to access admin area is http://yourhost/cms-admin/ # You can change 'cms-admin' to 'admin', for example. To disable admin area # entirely set this to '' or nil # config.admin_route_prefix = 'cms-admin' - + # When arriving at /cms-admin you may chose to redirect to arbirtary path, # for example '/cms-admin/users' # config.admin_route_redirect = '' - + # Normally we include default routes from https://github.com/comfy/comfortable-mexican-sofa/blob/master/config/routes.rb # If you want to include the routes manually set this to false # config.use_default_routes = true - + # /sitemap.xml that is used by search engines for indexing. It's enabled by # default, but you may turn it off. # config.enable_sitemap = true - + # File uploads use Paperclip and can support filesystem or s3 uploads. Override # the upload method and appropriate settings based on Paperclip. For S3 see: - # http://rdoc.info/gems/paperclip/2.3.8/Paperclip/Storage/S3, and for + # http://rdoc.info/gems/paperclip/2.3.8/Paperclip/Storage/S3, and for # filesystem see: http://rdoc.info/gems/paperclip/2.3.8/Paperclip/Storage/Filesystem config.upload_file_options = { :storage => 's3', :s3_credentials => { - :bucket => ENV['S3_BUCKET'], - :access_key_id => ENV['S3_KEY'], - :secret_access_key => ENV['S3_SECRET'] + :bucket => Spree::Config[:s3_bucket], + :access_key_id => Spree::Config[:s3_access_key], + :secret_access_key => Spree::Config[:s3_secret] } } @@ -47,11 +47,11 @@ ComfortableMexicanSofa.configure do |config| # request (if necessary). Please note that database entries are destroyed if there's # no corresponding file. Fixtures are disabled by default. # config.enable_fixtures = false - + # Path where fixtures can be located. # config.fixtures_path = File.expand_path('db/cms_fixtures', Rails.root) - - # Importing fixtures into Database + + # Importing fixtures into Database # To load fixtures into the database just run this rake task: # local: $ rake comfortable_mexican_sofa:fixtures:import FROM=example.local TO=localhost # Heroku: $ heroku run rake comfortable_mexican_sofa:fixtures:import FROM=example.local TO=yourapp.herokuapp.com @@ -62,53 +62,53 @@ ComfortableMexicanSofa.configure do |config| # local: $ rake comfortable_mexican_sofa:fixtures:export FROM=localhost TO=example.local # Heroku: $ heroku run rake comfortable_mexican_sofa:fixtures:export FROM=yourapp.herokuapp.com TO=example.local # This will create example.local folder and dump all content from example.com Site. - + # Content for Layouts, Pages and Snippets has a revision history. You can revert # a previous version using this system. You can control how many revisions per # object you want to keep. Set it to 0 if you wish to turn this feature off. # config.revisions_limit = 25 - + # Locale definitions. If you want to define your own locale merge # {:locale => 'Locale Title'} with this. # config.locales = {:en => 'English', :es => 'Español'} - + # Admin interface will respect the locale of the site being managed. However you can # force it to English by setting this to `:en` # config.admin_locale = nil - + # If you want to keep your CMS tables in a location other than the default database # add a database_config. For example, setting it to 'cms' will look for a cms_#{Rails.env} # definition in your database.yml file # config.database_config = nil - + # A class that is included as a sweeper to admin base controller if it's set # config.admin_cache_sweeper = nil - + # By default you cannot have irb code inside your layouts/pages/snippets. # Generally this is to prevent putting something like this: # <% User.delete_all %> but if you really want to allow it... # config.allow_irb = false - + # Whitelist of all helper methods that can be used via {{cms:helper}} tag. By default # all helpers are allowed except `eval`, `send`, `call` and few others. Empty array # will prevent rendering of all helpers. # config.allowed_helpers = nil - + # Whitelist of partials paths that can be used via {{cms:partial}} tag. All partials # are accessible by default. Empty array will prevent rendering of all partials. # config.allowed_partials = nil - - # Site aliases, if you want to have aliases for your site. Good for harmonizing + + # Site aliases, if you want to have aliases for your site. Good for harmonizing # production env with dev/testing envs. # e.g. config.site_aliases = {'host.com' => 'host.inv', 'host_a.com' => ['host.lvh.me', 'host.dev']} # Default is nil (not used) # config.hostname_aliases = nil - + end module CmsSpreeAuth def authenticate - unless current_user && current_user.has_spree_role?('admin') + unless spree_current_user && spree_current_user.has_spree_role?('admin') redirect_to spree.login_path end end diff --git a/config/initializers/db2fog.rb b/config/initializers/db2fog.rb new file mode 100644 index 0000000000..84579d4d42 --- /dev/null +++ b/config/initializers/db2fog.rb @@ -0,0 +1,6 @@ +DB2Fog.config = { + :aws_access_key_id => Spree::Config[:s3_access_key], + :aws_secret_access_key => Spree::Config[:s3_secret], + :directory => Spree::Config[:s3_bucket], + :provider => 'AWS' +} diff --git a/config/initializers/spree.rb b/config/initializers/spree.rb index 59982c1a9e..cf58bfb576 100644 --- a/config/initializers/spree.rb +++ b/config/initializers/spree.rb @@ -11,10 +11,6 @@ require 'spree/product_filters' 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.checkout_zone = 'Australia' config.address_requires_state = true diff --git a/config/locales/en.yml b/config/locales/en.yml index 179c14ca52..56eba0e134 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2,4 +2,10 @@ # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. en: - hello: "Hello world" + spree: + + devise: + failure: + invalid: | + Invalid email or password. + Were you a guest last time? Perhaps you need to create an account or reset your password. \ No newline at end of file diff --git a/config/newrelic.yml b/config/newrelic.yml new file mode 100644 index 0000000000..4e1be6e682 --- /dev/null +++ b/config/newrelic.yml @@ -0,0 +1,255 @@ +# Here are the settings that are common to all environments +common: &default_settings + # ============================== LICENSE KEY =============================== + + # You must specify the license key associated with your New Relic + # account. This key binds your Agent's data to your account in the + # New Relic service. + license_key: '<%= ENV["NEW_RELIC_LICENSE_KEY"] %>' + + # Agent Enabled (Rails Only) + # Use this setting to force the agent to run or not run. + # Default is 'auto' which means the agent will install and run only + # if a valid dispatcher such as Mongrel is running. This prevents + # it from running with Rake or the console. Set to false to + # completely turn the agent off regardless of the other settings. + # Valid values are true, false and auto. + # + # agent_enabled: auto + + # Application Name Set this to be the name of your application as + # you'd like it show up in New Relic. The service will then auto-map + # instances of your application into an "application" on your + # dashboard page. If you want to map this instance into multiple + # apps, like "AJAX Requests" and "All UI" then specify a semicolon + # separated list of up to three distinct names, or a yaml list. + # Defaults to the capitalized RAILS_ENV or RACK_ENV (i.e., + # Production, Staging, etc) + # + # Example: + # + # app_name: + # - Ajax Service + # - All Services + # + app_name: <%= ENV["NEW_RELIC_APP_NAME"] %> + + # When "true", the agent collects performance data about your + # application and reports this data to the New Relic service at + # newrelic.com. This global switch is normally overridden for each + # environment below. (formerly called 'enabled') + monitor_mode: true + + # Developer mode should be off in every environment but + # development as it has very high overhead in memory. + developer_mode: false + + # The newrelic agent generates its own log file to keep its logging + # information separate from that of your application. Specify its + # log level here. + log_level: info + + # Optionally set the path to the log file This is expanded from the + # root directory (may be relative or absolute, e.g. 'log/' or + # '/var/log/') The agent will attempt to create this directory if it + # does not exist. + # log_file_path: 'log' + + # Optionally set the name of the log file, defaults to 'newrelic_agent.log' + # log_file_name: 'newrelic_agent.log' + + # The newrelic agent communicates with the service via http by + # default. If you want to communicate via https to increase + # security, then turn on SSL by setting this value to true. Note, + # this will result in increased CPU overhead to perform the + # encryption involved in SSL communication, but this work is done + # asynchronously to the threads that process your application code, + # so it should not impact response times. + ssl: false + + # EXPERIMENTAL: enable verification of the SSL certificate sent by + # the server. This setting has no effect unless SSL is enabled + # above. This may block your application. Only enable it if the data + # you send us needs end-to-end verified certificates. + # + # This means we cannot cache the DNS lookup, so each request to the + # service will perform a lookup. It also means that we cannot + # use a non-blocking lookup, so in a worst case, if you have DNS + # problems, your app may block indefinitely. + # verify_certificate: true + + # Set your application's Apdex threshold value with the 'apdex_t' + # setting, in seconds. The apdex_t value determines the buckets used + # to compute your overall Apdex score. + # Requests that take less than apdex_t seconds to process will be + # classified as Satisfying transactions; more than apdex_t seconds + # as Tolerating transactions; and more than four times the apdex_t + # value as Frustrating transactions. + # For more about the Apdex standard, see + # http://newrelic.com/docs/general/apdex + + apdex_t: 0.5 + + #============================== Browser Monitoring =============================== + # New Relic Real User Monitoring gives you insight into the performance real users are + # experiencing with your website. This is accomplished by measuring the time it takes for + # your users' browsers to download and render your web pages by injecting a small amount + # of JavaScript code into the header and footer of each page. + browser_monitoring: + # By default the agent automatically injects the monitoring JavaScript + # into web pages. Set this attribute to false to turn off this behavior. + auto_instrument: true + + # Proxy settings for connecting to the service. + # + # If a proxy is used, the host setting is required. Other settings + # are optional. Default port is 8080. + # + # proxy_host: hostname + # proxy_port: 8080 + # proxy_user: + # proxy_pass: + + + # Tells transaction tracer and error collector (when enabled) + # whether or not to capture HTTP params. When true, frameworks can + # exclude HTTP parameters from being captured. + # Rails: the RoR filter_parameter_logging excludes parameters + # Java: create a config setting called "ignored_params" and set it to + # a comma separated list of HTTP parameter names. + # ex: ignored_params: credit_card, ssn, password + capture_params: false + + + # Transaction tracer captures deep information about slow + # transactions and sends this to the service once a + # minute. Included in the transaction is the exact call sequence of + # the transactions including any SQL statements issued. + transaction_tracer: + + # Transaction tracer is enabled by default. Set this to false to + # turn it off. This feature is only available at the Professional + # and above product levels. + enabled: true + + # Threshold in seconds for when to collect a transaction + # trace. When the response time of a controller action exceeds + # this threshold, a transaction trace will be recorded and sent to + # the service. Valid values are any float value, or (default) + # "apdex_f", which will use the threshold for an dissatisfying + # Apdex controller action - four times the Apdex T value. + transaction_threshold: apdex_f + + # When transaction tracer is on, SQL statements can optionally be + # recorded. The recorder has three modes, "off" which sends no + # SQL, "raw" which sends the SQL statement in its original form, + # and "obfuscated", which strips out numeric and string literals + record_sql: obfuscated + + # Threshold in seconds for when to collect stack trace for a SQL + # call. In other words, when SQL statements exceed this threshold, + # then capture and send the current stack trace. This is + # helpful for pinpointing where long SQL calls originate from + stack_trace_threshold: 0.500 + + # Determines whether the agent will capture query plans for slow + # SQL queries. Only supported in mysql and postgres. Should be + # set to false when using other adapters. + # explain_enabled: true + + # Threshold for query execution time below which query plans will not + # not be captured. Relevant only when `explain_enabled` is true. + # explain_threshold: 0.5 + + # Error collector captures information about uncaught exceptions and + # sends them to the service for viewing + error_collector: + + # Error collector is enabled by default. Set this to false to turn + # it off. This feature is only available at the Professional and above + # product levels + enabled: true + + # Rails Only - tells error collector whether or not to capture a + # source snippet around the place of the error when errors are View + # related. + capture_source: true + + # To stop specific errors from reporting to New Relic, set this property + # to comma separated values. Default is to ignore routing errors + # which are how 404's get triggered. + # + ignore_errors: ActionController::RoutingError + + # (Advanced) Uncomment this to ensure the cpu and memory samplers + # won't run. Useful when you are using the agent to monitor an + # external resource + # disable_samplers: true + + # If you aren't interested in visibility in these areas, you can + # disable the instrumentation to reduce overhead. + # + # disable_view_instrumentation: true + # disable_activerecord_instrumentation: true + # disable_memcache_instrumentation: true + # disable_dj: true + + # If you're interested in capturing memcache keys as though they + # were SQL uncomment this flag. Note that this does increase + # overhead slightly on every memcached call, and can have security + # implications if your memcached keys are sensitive + # capture_memcache_keys: true + + # Certain types of instrumentation such as GC stats will not work if + # you are running multi-threaded. Please let us know. + # multi_threaded = false + +# Application Environments +# ------------------------------------------ +# Environment specific settings are in this section. +# For Rails applications, RAILS_ENV is used to determine the environment +# For Java applications, pass -Dnewrelic.environment to set +# the environment + +# NOTE if your application has other named environments, you should +# provide newrelic configuration settings for these environments here. + +development: + <<: *default_settings + # Turn off communication to New Relic service in development mode (also + # 'enabled'). + # NOTE: for initial evaluation purposes, you may want to temporarily + # turn the agent on in development mode. + monitor_mode: false + + # Rails Only - when running in Developer Mode, the New Relic Agent will + # present performance information on the last 100 transactions you have + # executed since starting the mongrel. + # NOTE: There is substantial overhead when running in developer mode. + # Do not use for production or load testing. + developer_mode: true + + # Enable textmate links + # textmate: true + +test: + <<: *default_settings + # It almost never makes sense to turn on the agent when running + # unit, functional or integration tests or the like. + monitor_mode: false + +# Turn on the agent in production for 24x7 monitoring. NewRelic +# testing shows an average performance impact of < 5 ms per +# transaction, you you can leave this on all the time without +# incurring any user-visible performance degradation. +production: + <<: *default_settings + monitor_mode: true + +# Many applications have a staging environment which behaves +# identically to production. Support for that environment is provided +# here. By default, the staging environment has the agent turned on. +staging: + <<: *default_settings + monitor_mode: true + app_name: <%= ENV["NEW_RELIC_APP_NAME"] %> (Staging) diff --git a/config/routes.rb b/config/routes.rb index 11ab6cb5a3..b0c6de223b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -31,6 +31,17 @@ Spree::Core::Engine.routes.prepend do match '/admin/reports/bulk_coop' => 'admin/reports#bulk_coop', :as => "bulk_coop_admin_reports", :via => [:get, :post] match '/admin/reports/payments' => 'admin/reports#payments', :as => "payments_admin_reports", :via => [:get, :post] match '/admin/reports/order_cycles' => 'admin/reports#order_cycles', :as => "order_cycles_admin_reports", :via => [:get, :post] + match '/admin/products/bulk_edit' => 'admin/products#bulk_edit', :as => "bulk_edit_admin_products" + + match '/api/users/authorise_api' => 'api/users#authorise_api', :via => :get, :defaults => { :format => 'json' } + match '/api/enterprises' => 'api/enterprises#bulk_index', :via => :get, :defaults => { :format => 'json' } + match '/api/enterprises/:id' => 'api/enterprises#bulk_show', :via => :get, :defaults => { :format => 'json' } + + namespace :admin do + resources :products do + post :bulk_update, :on => :collection, :as => :bulk_update + end + end resources :orders do get :select_distributor, :on => :member diff --git a/config/unicorn.rb b/config/unicorn.rb index 6f6f2fcc14..e5d7317940 100644 --- a/config/unicorn.rb +++ b/config/unicorn.rb @@ -1,2 +1,27 @@ +preload_app true # https://newrelic.com/docs/ruby/no-data-with-unicorn worker_processes 4 # amount of unicorn workers to spin up -timeout 30 # restarts workers that hang for 30 seconds \ No newline at end of file +timeout 60 # restarts workers that hang for 30 seconds + + +# https://devcenter.heroku.com/articles/forked-pg-connections +before_fork do |server, worker| + + Signal.trap 'TERM' do + puts 'Unicorn master intercepting TERM and sending myself QUIT instead' + Process.kill 'QUIT', Process.pid + end + + defined?(ActiveRecord::Base) and + ActiveRecord::Base.connection.disconnect! +end + +after_fork do |server, worker| + + Signal.trap 'TERM' do + puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to sent QUIT' + end + + defined?(ActiveRecord::Base) and + ActiveRecord::Base.establish_connection + +end diff --git a/db/migrate/20130426023034_add_distributor_info_to_enterprises.enterprises_distributor_info_rich_text_feature.rb b/db/migrate/20130426023034_add_distributor_info_to_enterprises.enterprises_distributor_info_rich_text_feature.rb new file mode 100644 index 0000000000..69a6b9981e --- /dev/null +++ b/db/migrate/20130426023034_add_distributor_info_to_enterprises.enterprises_distributor_info_rich_text_feature.rb @@ -0,0 +1,6 @@ +# This migration comes from enterprises_distributor_info_rich_text_feature (originally 20130426022945) +class AddDistributorInfoToEnterprises < ActiveRecord::Migration + def change + add_column :enterprises, :distributor_info, :text + end +end diff --git a/db/migrate/20130629120633_add_order_id_index_to_payments.spree.rb b/db/migrate/20130629120633_add_order_id_index_to_payments.spree.rb new file mode 100644 index 0000000000..49b378abb3 --- /dev/null +++ b/db/migrate/20130629120633_add_order_id_index_to_payments.spree.rb @@ -0,0 +1,10 @@ +# This migration comes from spree (originally 20130207155350) +class AddOrderIdIndexToPayments < ActiveRecord::Migration + def self.up + add_index :spree_payments, :order_id + end + + def self.down + remove_index :spree_payments, :order_id + end +end diff --git a/db/migrate/20130629120634_add_primary_to_spree_products_taxons.spree.rb b/db/migrate/20130629120634_add_primary_to_spree_products_taxons.spree.rb new file mode 100644 index 0000000000..fd438d5c83 --- /dev/null +++ b/db/migrate/20130629120634_add_primary_to_spree_products_taxons.spree.rb @@ -0,0 +1,6 @@ +# This migration comes from spree (originally 20130208032954) +class AddPrimaryToSpreeProductsTaxons < ActiveRecord::Migration + def change + add_column :spree_products_taxons, :id, :primary_key + end +end diff --git a/db/migrate/20130629120635_add_order_id_index_to_shipments.spree.rb b/db/migrate/20130629120635_add_order_id_index_to_shipments.spree.rb new file mode 100644 index 0000000000..5d0ebdbc78 --- /dev/null +++ b/db/migrate/20130629120635_add_order_id_index_to_shipments.spree.rb @@ -0,0 +1,6 @@ +# This migration comes from spree (originally 20130222032153) +class AddOrderIdIndexToShipments < ActiveRecord::Migration + def change + add_index :spree_shipments, :order_id + end +end diff --git a/db/migrate/20130629120636_change_meta_description_on_spree_products_to_text.spree.rb b/db/migrate/20130629120636_change_meta_description_on_spree_products_to_text.spree.rb new file mode 100644 index 0000000000..66fff52115 --- /dev/null +++ b/db/migrate/20130629120636_change_meta_description_on_spree_products_to_text.spree.rb @@ -0,0 +1,6 @@ +# This migration comes from spree (originally 20130226032817) +class ChangeMetaDescriptionOnSpreeProductsToText < ActiveRecord::Migration + def change + change_column :spree_products, :meta_description, :text, :limit => nil + end +end diff --git a/db/migrate/20130629120637_add_variant_id_index_to_spree_prices.spree.rb b/db/migrate/20130629120637_add_variant_id_index_to_spree_prices.spree.rb new file mode 100644 index 0000000000..0a362f2ee8 --- /dev/null +++ b/db/migrate/20130629120637_add_variant_id_index_to_spree_prices.spree.rb @@ -0,0 +1,6 @@ +# This migration comes from spree (originally 20130226054936) +class AddVariantIdIndexToSpreePrices < ActiveRecord::Migration + def change + add_index :spree_prices, :variant_id + end +end diff --git a/db/migrate/20130629120638_change_orders_total_precision.spree.rb b/db/migrate/20130629120638_change_orders_total_precision.spree.rb new file mode 100644 index 0000000000..cfb1c81e6a --- /dev/null +++ b/db/migrate/20130629120638_change_orders_total_precision.spree.rb @@ -0,0 +1,9 @@ +# This migration comes from spree (originally 20130319062004) +class ChangeOrdersTotalPrecision < ActiveRecord::Migration + def change + change_column :spree_orders, :item_total, :decimal, :precision => 10, :scale => 2, :default => 0.0, :null => false + change_column :spree_orders, :total, :decimal, :precision => 10, :scale => 2, :default => 0.0, :null => false + change_column :spree_orders, :adjustment_total, :decimal, :precision => 10, :scale => 2, :default => 0.0, :null => false + change_column :spree_orders, :payment_total, :decimal, :precision => 10, :scale => 2, :default => 0.0 + end +end diff --git a/db/migrate/20130629120639_change_spree_payments_amount_precision.spree.rb b/db/migrate/20130629120639_change_spree_payments_amount_precision.spree.rb new file mode 100644 index 0000000000..2ac4630836 --- /dev/null +++ b/db/migrate/20130629120639_change_spree_payments_amount_precision.spree.rb @@ -0,0 +1,8 @@ +# This migration comes from spree (originally 20130319063911) +class ChangeSpreePaymentsAmountPrecision < ActiveRecord::Migration + def change + + change_column :spree_payments, :amount, :decimal, :precision => 10, :scale => 2, :default => 0.0, :null => false + + end +end diff --git a/db/migrate/20130629120640_change_spree_return_authorization_amount_precision.spree.rb b/db/migrate/20130629120640_change_spree_return_authorization_amount_precision.spree.rb new file mode 100644 index 0000000000..cf6cc4b3c2 --- /dev/null +++ b/db/migrate/20130629120640_change_spree_return_authorization_amount_precision.spree.rb @@ -0,0 +1,8 @@ +# This migration comes from spree (originally 20130319064308) +class ChangeSpreeReturnAuthorizationAmountPrecision < ActiveRecord::Migration + def change + + change_column :spree_return_authorizations, :amount, :decimal, :precision => 10, :scale => 2, :default => 0.0, :null => false + + end +end diff --git a/db/migrate/20130629120641_change_adjustments_amount_precision.spree.rb b/db/migrate/20130629120641_change_adjustments_amount_precision.spree.rb new file mode 100644 index 0000000000..f391987c40 --- /dev/null +++ b/db/migrate/20130629120641_change_adjustments_amount_precision.spree.rb @@ -0,0 +1,8 @@ +# This migration comes from spree (originally 20130319082943) +class ChangeAdjustmentsAmountPrecision < ActiveRecord::Migration + def change + + change_column :spree_adjustments, :amount, :decimal, :precision => 10, :scale => 2 + + end +end diff --git a/db/migrate/20130629120642_add_seo_metas_to_taxons.spree.rb b/db/migrate/20130629120642_add_seo_metas_to_taxons.spree.rb new file mode 100644 index 0000000000..a947764a27 --- /dev/null +++ b/db/migrate/20130629120642_add_seo_metas_to_taxons.spree.rb @@ -0,0 +1,10 @@ +# This migration comes from spree (originally 20130328195253) +class AddSeoMetasToTaxons < ActiveRecord::Migration + def change + change_table :spree_taxons do |t| + t.string :meta_title + t.string :meta_description + t.string :meta_keywords + end + end +end diff --git a/db/migrate/20130629120643_add_cvv_result_code_and_cvv_result_message_to_spree_payments.spree.rb b/db/migrate/20130629120643_add_cvv_result_code_and_cvv_result_message_to_spree_payments.spree.rb new file mode 100644 index 0000000000..0f611c6336 --- /dev/null +++ b/db/migrate/20130629120643_add_cvv_result_code_and_cvv_result_message_to_spree_payments.spree.rb @@ -0,0 +1,7 @@ +# This migration comes from spree (originally 20130626232741) +class AddCvvResultCodeAndCvvResultMessageToSpreePayments < ActiveRecord::Migration + def change + add_column :spree_payments, :cvv_response_code, :string + add_column :spree_payments, :cvv_response_message, :string + end +end diff --git a/db/migrate/20130629120644_add_unique_index_to_permalink_on_spree_products.spree.rb b/db/migrate/20130629120644_add_unique_index_to_permalink_on_spree_products.spree.rb new file mode 100644 index 0000000000..310d487116 --- /dev/null +++ b/db/migrate/20130629120644_add_unique_index_to_permalink_on_spree_products.spree.rb @@ -0,0 +1,6 @@ +# This migration comes from spree (originally 20130628021056) +class AddUniqueIndexToPermalinkOnSpreeProducts < ActiveRecord::Migration + def change + add_index "spree_products", ["permalink"], :name => "permalink_idx_unique", :unique => true + end +end diff --git a/db/migrate/20130629120645_add_unique_index_to_orders_shipments_and_stock_transfers.spree.rb b/db/migrate/20130629120645_add_unique_index_to_orders_shipments_and_stock_transfers.spree.rb new file mode 100644 index 0000000000..054cc7402e --- /dev/null +++ b/db/migrate/20130629120645_add_unique_index_to_orders_shipments_and_stock_transfers.spree.rb @@ -0,0 +1,7 @@ +# This migration comes from spree (originally 20130628022817) +class AddUniqueIndexToOrdersShipmentsAndStockTransfers < ActiveRecord::Migration + def add + add_index "spree_orders", ["number"], :name => "number_idx_unique", :unique => true + add_index "spree_shipments", ["number"], :name => "number_idx_unique", :unique => true + end +end diff --git a/db/schema.rb b/db/schema.rb index f59aa43ae4..df3c5ad03a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20130207043555) do +ActiveRecord::Schema.define(:version => 20130629120645) do create_table "cms_blocks", :force => true do |t| t.integer "page_id", :null => false @@ -156,6 +156,7 @@ ActiveRecord::Schema.define(:version => 20130207043555) do t.string "next_collection_at" t.datetime "created_at", :null => false t.datetime "updated_at", :null => false + t.text "distributor_info" end create_table "exchange_fees", :force => true do |t| @@ -240,17 +241,17 @@ ActiveRecord::Schema.define(:version => 20130207043555) do create_table "spree_adjustments", :force => true do |t| t.integer "source_id" - t.decimal "amount", :precision => 8, :scale => 2 + t.decimal "amount", :precision => 10, :scale => 2 t.string "label" t.string "source_type" t.integer "adjustable_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false t.boolean "mandatory" t.boolean "locked" t.integer "originator_id" t.string "originator_type" - t.boolean "eligible", :default => true + t.boolean "eligible", :default => true t.string "adjustable_type" end @@ -405,17 +406,17 @@ ActiveRecord::Schema.define(:version => 20130207043555) do create_table "spree_orders", :force => true do |t| t.string "number", :limit => 15 - t.decimal "item_total", :precision => 8, :scale => 2, :default => 0.0, :null => false - t.decimal "total", :precision => 8, :scale => 2, :default => 0.0, :null => false + t.decimal "item_total", :precision => 10, :scale => 2, :default => 0.0, :null => false + t.decimal "total", :precision => 10, :scale => 2, :default => 0.0, :null => false t.string "state" - t.decimal "adjustment_total", :precision => 8, :scale => 2, :default => 0.0, :null => false + t.decimal "adjustment_total", :precision => 10, :scale => 2, :default => 0.0, :null => false t.integer "user_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false t.datetime "completed_at" t.integer "bill_address_id" t.integer "ship_address_id" - t.decimal "payment_total", :precision => 8, :scale => 2, :default => 0.0 + t.decimal "payment_total", :precision => 10, :scale => 2, :default => 0.0 t.integer "shipping_method_id" t.string "shipment_state" t.string "payment_state" @@ -442,10 +443,10 @@ ActiveRecord::Schema.define(:version => 20130207043555) do end create_table "spree_payments", :force => true do |t| - t.decimal "amount", :precision => 8, :scale => 2, :default => 0.0, :null => false + t.decimal "amount", :precision => 10, :scale => 2, :default => 0.0, :null => false t.integer "order_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false t.integer "source_id" t.string "source_type" t.integer "payment_method_id" @@ -453,8 +454,12 @@ ActiveRecord::Schema.define(:version => 20130207043555) do t.string "response_code" t.string "avs_response" t.string "identifier" + t.string "cvv_response_code" + t.string "cvv_response_message" end + add_index "spree_payments", ["order_id"], :name => "index_spree_payments_on_order_id" + create_table "spree_paypal_accounts", :force => true do |t| t.string "email" t.string "payer_id" @@ -486,6 +491,8 @@ ActiveRecord::Schema.define(:version => 20130207043555) do t.string "currency" end + add_index "spree_prices", ["variant_id"], :name => "index_spree_prices_on_variant_id" + create_table "spree_product_groups", :force => true do |t| t.string "name" t.string "permalink" @@ -534,7 +541,7 @@ ActiveRecord::Schema.define(:version => 20130207043555) do t.datetime "available_on" t.datetime "deleted_at" t.string "permalink" - t.string "meta_description" + t.text "meta_description" t.string "meta_keywords" t.integer "tax_category_id" t.integer "shipping_category_id" @@ -551,6 +558,7 @@ ActiveRecord::Schema.define(:version => 20130207043555) do add_index "spree_products", ["deleted_at"], :name => "index_products_on_deleted_at" add_index "spree_products", ["name"], :name => "index_products_on_name" add_index "spree_products", ["permalink"], :name => "index_products_on_permalink" + add_index "spree_products", ["permalink"], :name => "permalink_idx_unique", :unique => true create_table "spree_products_promotion_rules", :id => false, :force => true do |t| t.integer "product_id" @@ -560,7 +568,7 @@ ActiveRecord::Schema.define(:version => 20130207043555) do add_index "spree_products_promotion_rules", ["product_id"], :name => "index_products_promotion_rules_on_product_id" add_index "spree_products_promotion_rules", ["promotion_rule_id"], :name => "index_products_promotion_rules_on_promotion_rule_id" - create_table "spree_products_taxons", :id => false, :force => true do |t| + create_table "spree_products_taxons", :force => true do |t| t.integer "product_id" t.integer "taxon_id" end @@ -621,11 +629,11 @@ ActiveRecord::Schema.define(:version => 20130207043555) do create_table "spree_return_authorizations", :force => true do |t| t.string "number" t.string "state" - t.decimal "amount", :precision => 8, :scale => 2, :default => 0.0, :null => false + t.decimal "amount", :precision => 10, :scale => 2, :default => 0.0, :null => false t.integer "order_id" t.text "reason" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false end create_table "spree_roles", :force => true do |t| @@ -654,6 +662,7 @@ ActiveRecord::Schema.define(:version => 20130207043555) do end add_index "spree_shipments", ["number"], :name => "index_shipments_on_number" + add_index "spree_shipments", ["order_id"], :name => "index_spree_shipments_on_order_id" create_table "spree_shipping_categories", :force => true do |t| t.string "name" @@ -744,6 +753,9 @@ ActiveRecord::Schema.define(:version => 20130207043555) do t.integer "icon_file_size" t.datetime "icon_updated_at" t.text "description" + t.string "meta_title" + t.string "meta_description" + t.string "meta_keywords" end add_index "spree_taxons", ["parent_id"], :name => "index_taxons_on_parent_id" diff --git a/db/seeds.rb b/db/seeds.rb index dd6be815e2..85fc9e4d86 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -2,6 +2,7 @@ # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). require File.expand_path('../../spec/factories', __FILE__) +require File.expand_path('../../spec/support/spree/init', __FILE__) # -- Spree @@ -72,21 +73,31 @@ end unless Spree::Product.count > 0 puts "[db:seed] Seeding products" - FactoryGirl.create(:product, + prod1 = FactoryGirl.create(:product, :name => 'Garlic', :price => 20.00, :supplier => Enterprise.is_primary_producer[0], - :distributors => [Enterprise.is_distributor[0]], :taxons => [Spree::Taxon.find_by_name('Vegetables')]) - FactoryGirl.create(:product, + ProductDistribution.create(:product => prod1, + :distributor => Enterprise.is_distributor[0], + :shipping_method => Spree::ShippingMethod.first) + + + prod2 = FactoryGirl.create(:product, :name => 'Fuji Apple', :price => 5.00, :supplier => Enterprise.is_primary_producer[1], - :distributors => Enterprise.is_distributor, :taxons => [Spree::Taxon.find_by_name('Fruit')]) - FactoryGirl.create(:product, + ProductDistribution.create(:product => prod2, + :distributor => Enterprise.is_distributor[1], + :shipping_method => Spree::ShippingMethod.first) + + prod3 = FactoryGirl.create(:product, :name => 'Beef - 5kg Trays', :price => 50.00, :supplier => Enterprise.is_primary_producer[2], - :distributors => [Enterprise.is_distributor[2]], :taxons => [Spree::Taxon.find_by_name('Meat and Fish')]) + + ProductDistribution.create(:product => prod3, + :distributor => Enterprise.is_distributor[2], + :shipping_method => Spree::ShippingMethod.first) end diff --git a/lib/chili/eaterprises_feature/.gitignore b/lib/chili/eaterprises_feature/.gitignore new file mode 100644 index 0000000000..8619e09c5a --- /dev/null +++ b/lib/chili/eaterprises_feature/.gitignore @@ -0,0 +1,3 @@ +.bundle/ +log/*.log +pkg/ diff --git a/lib/chili/eaterprises_feature/README.rdoc b/lib/chili/eaterprises_feature/README.rdoc new file mode 100644 index 0000000000..047a9eccec --- /dev/null +++ b/lib/chili/eaterprises_feature/README.rdoc @@ -0,0 +1,3 @@ += Eaterprises Feature + +This feature is released under the AGPL licence. \ No newline at end of file diff --git a/lib/chili/eaterprises_feature/app/assets/images/eaterprises_feature/.gitkeep b/lib/chili/eaterprises_feature/app/assets/images/eaterprises_feature/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/chili/eaterprises_feature/app/assets/javascripts/eaterprises_feature/application.js b/lib/chili/eaterprises_feature/app/assets/javascripts/eaterprises_feature/application.js new file mode 100644 index 0000000000..15ebed9422 --- /dev/null +++ b/lib/chili/eaterprises_feature/app/assets/javascripts/eaterprises_feature/application.js @@ -0,0 +1,13 @@ +// This is a manifest file that'll be compiled into application.js, which will include all the files +// listed below. +// +// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, +// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. +// +// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the +// the compiled file. +// +// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD +// GO AFTER THE REQUIRES BELOW. +// +//= require_tree . diff --git a/lib/chili/eaterprises_feature/app/assets/stylesheets/eaterprises_feature/application.css b/lib/chili/eaterprises_feature/app/assets/stylesheets/eaterprises_feature/application.css new file mode 100644 index 0000000000..3192ec897b --- /dev/null +++ b/lib/chili/eaterprises_feature/app/assets/stylesheets/eaterprises_feature/application.css @@ -0,0 +1,13 @@ +/* + * This is a manifest file that'll be compiled into application.css, which will include all the files + * listed below. + * + * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, + * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. + * + * You're free to add application-wide styles to this file and they'll appear at the top of the + * compiled file, but it's generally better to create a new file per style scope. + * + *= require_self + *= require_tree . + */ diff --git a/lib/chili/eaterprises_feature/app/assets/stylesheets/eaterprises_feature/variables_changes.css.scss b/lib/chili/eaterprises_feature/app/assets/stylesheets/eaterprises_feature/variables_changes.css.scss new file mode 100644 index 0000000000..c4007abd2f --- /dev/null +++ b/lib/chili/eaterprises_feature/app/assets/stylesheets/eaterprises_feature/variables_changes.css.scss @@ -0,0 +1 @@ +$link_text_color: #006066; diff --git a/lib/chili/eaterprises_feature/app/overrides/layouts/application/assets.html.erb.deface b/lib/chili/eaterprises_feature/app/overrides/layouts/application/assets.html.erb.deface new file mode 100644 index 0000000000..72e5ed7748 --- /dev/null +++ b/lib/chili/eaterprises_feature/app/overrides/layouts/application/assets.html.erb.deface @@ -0,0 +1,3 @@ + +<%= stylesheet_link_tag 'eaterprises_feature/application' %> +<%= javascript_include_tag 'eaterprises_feature/application' %> diff --git a/app/views/layouts/_feedback_script.html.erb b/lib/chili/eaterprises_feature/app/overrides/spree/layouts/spree_application/feedback_script.html.erb.deface similarity index 89% rename from app/views/layouts/_feedback_script.html.erb rename to lib/chili/eaterprises_feature/app/overrides/spree/layouts/spree_application/feedback_script.html.erb.deface index 605e48721c..5ced3ebb12 100644 --- a/app/views/layouts/_feedback_script.html.erb +++ b/lib/chili/eaterprises_feature/app/overrides/spree/layouts/spree_application/feedback_script.html.erb.deface @@ -1,3 +1,4 @@ + <% if Rails.env.production? %>